Natalius
26.12.2009, 16:04
Hallo Bascom-Fans,
Mit den im Dezember 2009 erschienenen Bascom-Versionen (aktuell 1.11.9.8) hat Mark Alberts deutliche Fortschritte bei der Unterstützung der Xmegas erzielt. Leider fehlt für die Modellbau/Robotik/UAV-Szene noch etwas Elementares - nämlich der Bascom-support von PWM und Servos. Das kann man aber selbst mit kleinen Veränderungen an der XM128def.dat hinbekommen. Wie, ist in nachstehendem Source snippet erläutert.
Wünsche noch einen guten Rutsch,
Natalius
'----------------------------------------------------------------
' (C) MCS 2009 & N.Kiedro
' Xmega2Servo.bas
' This snippet demonstrates PWM on the Xmega128A1
' Platform: Xmega A1 USB module from http://shop.avr-praxis.de
'
' USE port D to create six RC servo signals in 4000 steps/ms
' resolution via interrupt-free single slope PWM.
' Servo signals are pulses between 1 and 2 ms,
' corresponding to 4000 to 8000 here - center at 6000.
' In my own kixm128a1def.dat file I have done these extensions for
' all Timer/Counters which allows to control 20 servos (=24-4 because
' of USART F0 in use) via the Xmega-A1-USB module. Of course, jitter-free
' and with best achievable resolution @ 32 MHz.
'-----------------------------------------------------------------
$regfile = "kixm128a1def.dat"
'For BASCOM 1.11.9.8: This snippet needs an extended definition dat with the following
'changes:
''(1) Load xm128def.dat into the editor and save it under a different name, e.g. kixm128a1def.dat
''(2) Find the following definitions for TCD0, TCD1
'' _CNT
'' _PER
'' _CCA
'' _CCB
'' _CCC
'' _CCD
'' _PERBUF
'' _CCABUF
'' _CCBBUF
''
''(3) Replace the corresponding sections as follows:
'' TCD0_CNTL = 2336 ; Count
'' TCD0_CNTH = 2337 ; Count
'' TCD0_PERL = 2342 ; Period
'' TCD0_PERH = 2343 ; Period
'' TCD0_CCAL = 2344 ; Compare or Capture A
'' TCD0_CCAH = 2345 ; Compare or Capture A
'' TCD0_CCBL = 2346 ; Compare or Capture B
'' TCD0_CCBH = 2347 ; Compare or Capture B
'' TCD0_CCCL = 2348 ; Compare or Capture C
'' TCD0_CCCH = 2349 ; Compare or Capture C
'' TCD0_CCDL = 2350 ; Compare or Capture D
'' TCD0_CCDH = 2351 ; Compare or Capture D
'' TCD0_PERBUFL = 2358 ; Period Buffer
'' TCD0_PERBUFH = 2359 ; Period Buffer
'' TCD0_CCABUFL = 2360 ; Compare Or Capture A Buffer
'' TCD0_CCABUFH = 2361 ; Compare Or Capture A Buffer
'' TCD0_CCBBUFL = 2362 ; Compare Or Capture B Buffer
'' TCD0_CCBBUFH = 2363 ; Compare Or Capture B Buffer
'' TCD0_CCCBUFL = 2364 ; Compare Or Capture C Buffer
'' TCD0_CCCBUFH = 2365 ; Compare Or Capture C Buffer
'' TCD0_CCDBUFL = 2366 ; Compare Or Capture D Buffer
'' TCD0_CCDBUFH = 2367 ; Compare Or Capture D Buffer
''
'' TCD1_CNTL = 2400 ; Count
'' TCD1_CNTH = 2401 ; Count
'' TCD1_PERL = 2406 ; Period
'' TCD1_PERH = 2407 ; Period
'' TCD1_CCAL = 2408 ; Compare or Capture A
'' TCD1_CCAH = 2409 ; Compare or Capture A
'' TCD1_CCBL = 2410 ; Compare or Capture B
'' TCD1_CCBH = 2411 ; Compare or Capture B
'' TCD1_PERBUFL = 2422 ; Period Buffer
'' TCD1_PERBUFH = 2423 ; Period Buffer
'' TCD1_CCABUFL = 2424 ; Compare Or Capture A Buffer
'' TCD1_CCABUFH = 2425 ; Compare Or Capture A Buffer
'' TCD1_CCBBUFL = 2426 ; Compare Or Capture B Buffer
'' TCD1_CCBBUFH = 2427 ; Compare Or Capture B Buffer
''(4) Dont forget to save the changes
$crystal = 32000000
$hwstack = 512
$swstack = 256
$framesize = 256
'include the following lib and code, the routines will be replaced since they are a workaround
$lib "xmega.lib"
$external _xmegafix_clear
$external _xmegafix_rol_r1014
'$timeout = 8000000 TIMEOUT WILL WORK FOR ALL UARTS
'first enable the osc of your choice
Config Osc = Enabled , 32mhzosc = Enabled 'remarkably accurate given the fact that no xtal is employed
'Config Osc = Enabled , Extosc = Enabled , Range = 12mhz_16mhz , Startup = Xtal_16kclk (so far doesn't work)
'configure the systemclock
Config Sysclock = 32mhz , Prescalea = 1 , Prescalebc = 1_1
Dim N As String * 16 , B As Byte
Dim Tel As Byte , Channum As Byte , Jst As String * 1 , Chanval As Word , Chanpwm(6) As Word , Iby As Byte
Config Com7 = 38400 , Mode = Asynchroneous , Parity = None , Stopbits = 1 , Databits = 8
Config Input7 = Cr , Echo = Crlf ' CR is used for input, we echo back CR and LF
Open "COM7:" For Binary As #7
' ^^^^ change from COM1-COM8
Config Portf = Output
Config Portf.3 = Output ' TX pin must be output
Config Portf.2 = Input
Config Portq = Output
'Waitms 500
Print #7 , "Press <CR> to start";
'pwm initialisation here
'RC cycle period should be ideally at 20ms, viz. 50 Hz.
'With fpwm = fosc/per/clkdiv = 32MHz/(2^16)/8 = 1MHz/2^14 = 61.0352 Hz we have a
'cycle period of 16.384 ms most servos should be able to live with.
' From the Xmega 128A1 manual:
' 6.4 Using a Timer/Counter for PWM Generation
' Task: Configure TCC0 for pulse width modulation output with varying duty cycle on channel A.
' 1. Configure PC0 for output by setting bit 0 in PORTC.DIR.
' 2. Select the timer period by setting the PER[H:L] register.
' 3. Select a waveform generation mode by setting the WGMODE[2:0] bits in CTRLB
' 4. Enable Compare Channel A by setting the CCAEN bit in CTRLB.
' 5. Start the TC by selecting a clock source (CLKSEL[3:0] in CTRLA).
' 6. Calculate the desired compare value.
' 7. Write the new compare value to CCA[H:L].
' 8. Wait for the TC Overflow Flag to be set. (OVFIF in INTFLAGS).
' 9. Clear the TC Overflow flag.
' 10. Go to step 6.
'Using this sequence, the compare value will be updated once every PWM period.
'Modification: free running pwm - no interrupt, but ASAP update instead:
' 1. Configure PD0 and PD1 for output --> PORTD.DIR.
' 2. Select the timer period by setting the PER[H:L] register.
' 3. Select a waveform generation mode by setting the WGMODE[2:0] bits in CTRLB
' 4. Enable Compare Channel A-D by setting the CCAEN bits in CTRLB.
' 5. Start the TC by selecting a clock source (CLKSEL[3:0] in CTRLA).
' 6. Calculate the desired compare value.
' 7. Write the new compare value to CCxBUF[H:L].
' 8. Go to step 6
'ad 1.
Portd_dir = &HFF
'ad2.
Tcd0_perl = &HFF
Tcd0_perh = &HFF
Tcd1_perl = &HFF
Tcd1_perh = &HFF
'ad 3 & 4
Tcd0_ctrlb = &HF3 'define WGMODE 011 = single slope and set OCA-D active
Tcd1_ctrlb = &HC3
'ad 5
Tcd0_ctrla = &H04 'Divide Clock By 8 , Enable Timers (Bits 3..0 define clckdiv)
Tcd1_ctrla = &H04
'ad 6
For Iby = 1 To 6
Chanpwm(iby) = 6000
Next Iby
'ad 7
Gosub Update
'configure the priority
'config priority=static|roundrobin,vector=application|boot ,HI=enabled|disabled, LO=enabled|disabled,ME=enabled|disabled
Config Priority = Static , Vector = Application , Lo = Enabled
'test an interrupts
On Usartf0_rxc Rxc_isr
Enable Usartf0_rxc , Lo
Enable Interrupts
Tel = 65
Do
Print #7 , "Channel(1-6)?";
Tel = Waitkey(#7)
Jst = Chr(tel)
Channum = Val(jst)
Print #7 , Channum
Input #7 , "value?" , N 'enter values between 4000 (1ms) and 8000 (2ms)
Chanval = Val(n)
Print #7 , N
Chanpwm(channum) = Chanval
'ad 7
Gosub Update
Loop
Rxc_isr:
Toggle Portq.3
'Incr Teller
Return
Update:
Tcd0_ccabufL = Low(chanpwm(1))
Tcd0_ccabufH = High(chanpwm(1))
Tcd0_ccbbufL = Low(chanpwm(2))
Tcd0_ccbbufH = High(chanpwm(2))
Tcd0_cccbufL = Low(chanpwm(3))
Tcd0_cccbufH = High(chanpwm(3))
Tcd0_ccdbufL = Low(chanpwm(4))
Tcd0_ccdbufH = High(chanpwm(4))
Tcd1_ccabufL = Low(chanpwm(5))
Tcd1_ccabufH = High(chanpwm(5))
Tcd1_ccbbufL = Low(chanpwm(6))
Tcd1_ccbbufH = High(chanpwm(6))
Return
Mit den im Dezember 2009 erschienenen Bascom-Versionen (aktuell 1.11.9.8) hat Mark Alberts deutliche Fortschritte bei der Unterstützung der Xmegas erzielt. Leider fehlt für die Modellbau/Robotik/UAV-Szene noch etwas Elementares - nämlich der Bascom-support von PWM und Servos. Das kann man aber selbst mit kleinen Veränderungen an der XM128def.dat hinbekommen. Wie, ist in nachstehendem Source snippet erläutert.
Wünsche noch einen guten Rutsch,
Natalius
'----------------------------------------------------------------
' (C) MCS 2009 & N.Kiedro
' Xmega2Servo.bas
' This snippet demonstrates PWM on the Xmega128A1
' Platform: Xmega A1 USB module from http://shop.avr-praxis.de
'
' USE port D to create six RC servo signals in 4000 steps/ms
' resolution via interrupt-free single slope PWM.
' Servo signals are pulses between 1 and 2 ms,
' corresponding to 4000 to 8000 here - center at 6000.
' In my own kixm128a1def.dat file I have done these extensions for
' all Timer/Counters which allows to control 20 servos (=24-4 because
' of USART F0 in use) via the Xmega-A1-USB module. Of course, jitter-free
' and with best achievable resolution @ 32 MHz.
'-----------------------------------------------------------------
$regfile = "kixm128a1def.dat"
'For BASCOM 1.11.9.8: This snippet needs an extended definition dat with the following
'changes:
''(1) Load xm128def.dat into the editor and save it under a different name, e.g. kixm128a1def.dat
''(2) Find the following definitions for TCD0, TCD1
'' _CNT
'' _PER
'' _CCA
'' _CCB
'' _CCC
'' _CCD
'' _PERBUF
'' _CCABUF
'' _CCBBUF
''
''(3) Replace the corresponding sections as follows:
'' TCD0_CNTL = 2336 ; Count
'' TCD0_CNTH = 2337 ; Count
'' TCD0_PERL = 2342 ; Period
'' TCD0_PERH = 2343 ; Period
'' TCD0_CCAL = 2344 ; Compare or Capture A
'' TCD0_CCAH = 2345 ; Compare or Capture A
'' TCD0_CCBL = 2346 ; Compare or Capture B
'' TCD0_CCBH = 2347 ; Compare or Capture B
'' TCD0_CCCL = 2348 ; Compare or Capture C
'' TCD0_CCCH = 2349 ; Compare or Capture C
'' TCD0_CCDL = 2350 ; Compare or Capture D
'' TCD0_CCDH = 2351 ; Compare or Capture D
'' TCD0_PERBUFL = 2358 ; Period Buffer
'' TCD0_PERBUFH = 2359 ; Period Buffer
'' TCD0_CCABUFL = 2360 ; Compare Or Capture A Buffer
'' TCD0_CCABUFH = 2361 ; Compare Or Capture A Buffer
'' TCD0_CCBBUFL = 2362 ; Compare Or Capture B Buffer
'' TCD0_CCBBUFH = 2363 ; Compare Or Capture B Buffer
'' TCD0_CCCBUFL = 2364 ; Compare Or Capture C Buffer
'' TCD0_CCCBUFH = 2365 ; Compare Or Capture C Buffer
'' TCD0_CCDBUFL = 2366 ; Compare Or Capture D Buffer
'' TCD0_CCDBUFH = 2367 ; Compare Or Capture D Buffer
''
'' TCD1_CNTL = 2400 ; Count
'' TCD1_CNTH = 2401 ; Count
'' TCD1_PERL = 2406 ; Period
'' TCD1_PERH = 2407 ; Period
'' TCD1_CCAL = 2408 ; Compare or Capture A
'' TCD1_CCAH = 2409 ; Compare or Capture A
'' TCD1_CCBL = 2410 ; Compare or Capture B
'' TCD1_CCBH = 2411 ; Compare or Capture B
'' TCD1_PERBUFL = 2422 ; Period Buffer
'' TCD1_PERBUFH = 2423 ; Period Buffer
'' TCD1_CCABUFL = 2424 ; Compare Or Capture A Buffer
'' TCD1_CCABUFH = 2425 ; Compare Or Capture A Buffer
'' TCD1_CCBBUFL = 2426 ; Compare Or Capture B Buffer
'' TCD1_CCBBUFH = 2427 ; Compare Or Capture B Buffer
''(4) Dont forget to save the changes
$crystal = 32000000
$hwstack = 512
$swstack = 256
$framesize = 256
'include the following lib and code, the routines will be replaced since they are a workaround
$lib "xmega.lib"
$external _xmegafix_clear
$external _xmegafix_rol_r1014
'$timeout = 8000000 TIMEOUT WILL WORK FOR ALL UARTS
'first enable the osc of your choice
Config Osc = Enabled , 32mhzosc = Enabled 'remarkably accurate given the fact that no xtal is employed
'Config Osc = Enabled , Extosc = Enabled , Range = 12mhz_16mhz , Startup = Xtal_16kclk (so far doesn't work)
'configure the systemclock
Config Sysclock = 32mhz , Prescalea = 1 , Prescalebc = 1_1
Dim N As String * 16 , B As Byte
Dim Tel As Byte , Channum As Byte , Jst As String * 1 , Chanval As Word , Chanpwm(6) As Word , Iby As Byte
Config Com7 = 38400 , Mode = Asynchroneous , Parity = None , Stopbits = 1 , Databits = 8
Config Input7 = Cr , Echo = Crlf ' CR is used for input, we echo back CR and LF
Open "COM7:" For Binary As #7
' ^^^^ change from COM1-COM8
Config Portf = Output
Config Portf.3 = Output ' TX pin must be output
Config Portf.2 = Input
Config Portq = Output
'Waitms 500
Print #7 , "Press <CR> to start";
'pwm initialisation here
'RC cycle period should be ideally at 20ms, viz. 50 Hz.
'With fpwm = fosc/per/clkdiv = 32MHz/(2^16)/8 = 1MHz/2^14 = 61.0352 Hz we have a
'cycle period of 16.384 ms most servos should be able to live with.
' From the Xmega 128A1 manual:
' 6.4 Using a Timer/Counter for PWM Generation
' Task: Configure TCC0 for pulse width modulation output with varying duty cycle on channel A.
' 1. Configure PC0 for output by setting bit 0 in PORTC.DIR.
' 2. Select the timer period by setting the PER[H:L] register.
' 3. Select a waveform generation mode by setting the WGMODE[2:0] bits in CTRLB
' 4. Enable Compare Channel A by setting the CCAEN bit in CTRLB.
' 5. Start the TC by selecting a clock source (CLKSEL[3:0] in CTRLA).
' 6. Calculate the desired compare value.
' 7. Write the new compare value to CCA[H:L].
' 8. Wait for the TC Overflow Flag to be set. (OVFIF in INTFLAGS).
' 9. Clear the TC Overflow flag.
' 10. Go to step 6.
'Using this sequence, the compare value will be updated once every PWM period.
'Modification: free running pwm - no interrupt, but ASAP update instead:
' 1. Configure PD0 and PD1 for output --> PORTD.DIR.
' 2. Select the timer period by setting the PER[H:L] register.
' 3. Select a waveform generation mode by setting the WGMODE[2:0] bits in CTRLB
' 4. Enable Compare Channel A-D by setting the CCAEN bits in CTRLB.
' 5. Start the TC by selecting a clock source (CLKSEL[3:0] in CTRLA).
' 6. Calculate the desired compare value.
' 7. Write the new compare value to CCxBUF[H:L].
' 8. Go to step 6
'ad 1.
Portd_dir = &HFF
'ad2.
Tcd0_perl = &HFF
Tcd0_perh = &HFF
Tcd1_perl = &HFF
Tcd1_perh = &HFF
'ad 3 & 4
Tcd0_ctrlb = &HF3 'define WGMODE 011 = single slope and set OCA-D active
Tcd1_ctrlb = &HC3
'ad 5
Tcd0_ctrla = &H04 'Divide Clock By 8 , Enable Timers (Bits 3..0 define clckdiv)
Tcd1_ctrla = &H04
'ad 6
For Iby = 1 To 6
Chanpwm(iby) = 6000
Next Iby
'ad 7
Gosub Update
'configure the priority
'config priority=static|roundrobin,vector=application|boot ,HI=enabled|disabled, LO=enabled|disabled,ME=enabled|disabled
Config Priority = Static , Vector = Application , Lo = Enabled
'test an interrupts
On Usartf0_rxc Rxc_isr
Enable Usartf0_rxc , Lo
Enable Interrupts
Tel = 65
Do
Print #7 , "Channel(1-6)?";
Tel = Waitkey(#7)
Jst = Chr(tel)
Channum = Val(jst)
Print #7 , Channum
Input #7 , "value?" , N 'enter values between 4000 (1ms) and 8000 (2ms)
Chanval = Val(n)
Print #7 , N
Chanpwm(channum) = Chanval
'ad 7
Gosub Update
Loop
Rxc_isr:
Toggle Portq.3
'Incr Teller
Return
Update:
Tcd0_ccabufL = Low(chanpwm(1))
Tcd0_ccabufH = High(chanpwm(1))
Tcd0_ccbbufL = Low(chanpwm(2))
Tcd0_ccbbufH = High(chanpwm(2))
Tcd0_cccbufL = Low(chanpwm(3))
Tcd0_cccbufH = High(chanpwm(3))
Tcd0_ccdbufL = Low(chanpwm(4))
Tcd0_ccdbufH = High(chanpwm(4))
Tcd1_ccabufL = Low(chanpwm(5))
Tcd1_ccabufH = High(chanpwm(5))
Tcd1_ccbbufL = Low(chanpwm(6))
Tcd1_ccbbufH = High(chanpwm(6))
Return