Fox G20 PWM NOTES (+ some notes on Aria G25) =-=-=-=-=-=-=-=-= Introduction ============ Basically "Pulse Width Modulation" (PWM) refers to square waves in which the frequency and the ratio of the time in the up state compared to the down state (i.e. the "mark-space ratio")) can be precisely controlled. With the FoxG20 the amplitude cannot be controlled: the up state is a little less than 3.3 volts (or 1.8 volts if the PC4-15 GPIO lines are used) and the down state is a little more than 0 volts. PWM can be generated by the FoxG20 via a silicon within the AT91SAM9G20 chip (which I'll call "hardware PWM") or by using programs to manipulate GPIO lines directly (which I'll call "software PWM"). Both software and hardware PWM generation could be implemented in a Linux kernel driver or in the user space. This note concentrates on the hardware PWM generation from code running in the user space (with the help of the mem2io utility). Compared to the software generation technique, the hardware PWM generation advantages are: - (much) more accurate PWM generation (i.e. frequency and mark-space ratio stability) - much higher maximum frequency PWM (i.e. 33 MHz) - low CPU overhead and the disadvantages are: - limited to 3 PWM (TC) channels which are only available on specific GPIO lines (i.e. PB0-3 and PB16-19) - tricky to generate PWM at low frequencies (i.e. below 0.5 Hz); possible by cascading counters (limited by 16 bit counter) - limited by the capabilities of the silicon (e.g. I can see no easy way to sweep frequency or mark-space ratio without CPU intervention) - no Linux kernel support for PWM generation on the G20 currently A Linux "kernel module for generating PWM signals" is described here: http://www.acmesystems.it/foxg20/doku.php?id=contributes:antoniogalea:soft_pwm This uses what I would describe as software PWM generation within a Linux kernel driver. Fox G20 hardware PWM basics and pins ==================================== There is an Atmel application note titled: "Pulse Width Modulation Generation Using the AT91 Timer/Counter". It may be found at: http://www.atmel.com/dyn/resources/prod_documents/doc2682.pdf Note that the TC block described in the application note is slightly different (older) compared to what is found in the AT91SAM9G20 but close enough to be a useful guide. The AT91SAM9G20 has two "Timer Counter" (TC) blocks, each of which has 3 independent 16 bit counters. The naming of these counters varies a little depending on which chapter in the "AT91SAM9G20 Preliminary" manual is referring to them. The clearest approach is probably to name the 16 bit counters as TC0, TC1 and TC2 in the first TC block; and TC3, TC4, TC5 in the second TC block. The Linux kernel uses TC0, TC1, TC2 so they are unavailable for the purposes of PWM generation. That leaves TC3, TC4 and TC5 and depending of the GPIO line configuration the following lines are associated with them: PB0 TIOA3 [A output of TC3] PB1 TIOB3 [B output of TC3] PB2 TIOA4 [A output of TC4] PB3 TIOA5 [A output of TC5] PB16 TCLK3 [external clock input for TC3] PB17 TCLK4 [external clock input for TC4] PB18 TIOB4 [B output of TC4] PB19 TIOB5 [B output of TC5] The reader is referred to the Timer Counter (TC) chapter in the AT91SAM9G20 Preliminary manual. Note that it is written as if there is only one TC block (so you won't see references to TC3, TC4 or TC5). For the FoxG20 MCLK is 132 MHz and SCLK is 32768 Hz. These yield the following clock frequencies: TIMER_CLOCK1 66 MHz 66000000 Hz TIMER_CLOCK2 16.5 MHz 16500000 Hz TIMER_CLOCK3 4.125 MHz 4125000 Hz TIMER_CLOCK4 1.03125 MHz 1031250 Hz TIMER_CLOCK5 32.768 kHz 32768 Hz Alternatively the timer clock may be obtained from an external clock input (e.g. TCLK3) or from the output of another TC element. So if a 16 bit counter is not sufficient, multiple TC elements can be chained together. The "chaining" may be done within a TC block or via two gpio lines (e.g. connecting TIOA3 (PB0) to TCLK4 (PB17)). There are several ways of generating a specific frequency, I will describe one way which worked in my testing. The timer frequency is determined by the RC register (i.e. TIMER_CLOCK / RC) and either RA or RB determines the mark space ratio of the PWM. To simplify, just look at RA now. These relations needs to be observed: 1< RC < 65536 and 0 < RA < RC . The maximum frequency occurs with TIMER_CLOCK1 when RA=1 and RC=2 yielding 33 MHz (with a mark-space ratio of 1:1). The percentage of space is RA/RC * 100 (given the way I set up the triggers). When using TIOA3, TIOA4 or TIOA5 for PWM output it is appropriate to set the RA register. When using TIOB3, TIOB4 or TIOB5 for PWM output the RB register should be set. Notice for a frequency controlled by the RC register (say on TC3), two different mark space ratios could be generated by setting RA and RB appropriately (and for TC3 the outputs would appear on TIOA3 and TIOB3). There are a couple of "gotchas" illustrated by the example below. The main ones are the "Peripheral B" needs to be selected for the GPIO lines that are going to be used (e.g. PB0 in the first example below) by the PIO_BSR control register. Another is that the peripheral clock for the TC channel needs to be turned on in the PMC_PCER register. Note that when a TC channel peripheral clock is on then the AT91SAM9G20 will consume a bit more power which is why they are off by default. Also if the PWM control is being left on and changed from time to time by software control, then the initial and final states (i.e. either up or down) may be important. The examples below start in the low state and set the state low when the PWM is stopped. However when the gpio line is set back to its normal state (via PIO_PER) then the PIO block's settings control that line (and that is often as an input with an internal pull-up). Aria G25 and PWM ================ The Aria G25 module from Acme Systems is based on the AT91SAM9G25 MCU. It has a compatible (but more capable) TC unit. The biggest difference is that each of the 6 counters in the G25 are 32 bits compared to 16 bit counters on the G20. N.B. The G25 has different memory mapped IO locations for its TC and PCM units (but PIOA, PIOB and PIOC controllers are in the same place). So Don't use the scripts below directly on a G25 (but you are free to correct the TC and PCM address locations and then try them). A better approach is to use the g20tc_freq utility for the G20 and the g25tc_freq utility for the G25. The expanded 32 bit counters on the G20 allow frequencies in the (1/131071) Hz to 33.333 MHz (that is around 1.5 days at the low end). The g25tc_freq utility also adds the ability to control the mark space ratio. Also the G25 has its own PWM unit that supports 4 independent PWM lines each with their own 16 bit counter. See the AT91SAM9G25 manual. Example of user space controlled hardware PWM ============================================= Below are some Bourne shell scripts between the lines that start with "vvvv" and finish with "^^^^". The script uses the mem2io utility which writes to the memory mapped control registers on the AT91SAM9G20. The Atmel acronym for the control register is shown at the end of the line. For example PIO_BSR(B) means the BSR register in the PIO section (see that chapter in the manual) for the PB* GPIO block. vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv #!/bin/bash # Set up slowest PWM on PB0 (FoxG20 J7.9). Up for 0.5 second and down # for 1.5 seconds. PB0 is TIOA3 (on "peripheral B") and so is # associated with TC3 (channel 0 on second TC block). # Start and finish PWM with PB0 low. mem2io -w -i 0xfffdc000,0x2 # disable TC3 clock [TC_CCR0] mem2io -w -i 0xfffff604,0x1 # disable normal gpio on PB0 [PIO_PDR(B)] mem2io -w -i 0xfffff674,0x1 # select peripheral B on PB0 [PIO_BSR(B)] mem2io -w -i 0xfffffc10,0x04000000 # turn on TC3 peripheral clock [PMC_PCER] mem2io -w -i 0xfffdc004,0x89c004 # wave=1, wavesel=2, SLCK (32768 Hz) # ASWTRG=2 ACPC=2 ACPA=1 [TC_CMR0] mem2io -w -i 0xfffdc01c,0xffff # RC max value [TC_RC0] mem2io -w -i 0xfffdc014,0xc000 # RA for 75% down [TC_RA0] mem2io -w -i 0xfffdc000,0x1 # enable clock [TC_CCR0] mem2io -w -i 0xfffdc000,0x4 # software trigger [TC_CCR0] sleep 12 mem2io -w -i 0xfffdc000,0x6 # disable clock + soft trig [TC_CCR0] mem2io -w -i 0xfffff600,0x1 # enable normal gpio on PB0 [PIO_PER(B)] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv #!/bin/bash # Set up slowest PWM on PB2 (FoxG20 J7.7). Up for 0.5 second and down # for 1.5 seconds. PB2 is TIOA4 (on "peripheral B") and so is # associated with TC4 (channel 1 on second TC block). mem2io -w -i 0xfffdc040,0x2 # disable TC4 clock [TC_CCR1] mem2io -w -i 0xfffff604,0x4 # disable normal gpio on PB2 [PIO_PDR(B)] mem2io -w -i 0xfffff674,0x4 # select peripheral B on PB2 [PIO_BSR(B)] mem2io -w -i 0xfffffc10,0x08000000 # turn on TC4 peripheral clock [PMC_PCER] mem2io -w -i 0xfffdc044,0x89c004 # wave=1, wavesel=2, SLCK (32768 Hz) # ASWTRG=2 ACPC=2 ACPA=1 [TC_CMR1] mem2io -w -i 0xfffdc05c,0xffff # RC max value [TC_RC1] mem2io -w -i 0xfffdc054,0xc000 # RA for 75% down [TC_RA1] mem2io -w -i 0xfffdc040,0x1 # enable clock [TC_CCR1] mem2io -w -i 0xfffdc040,0x4 # software trigger [TC_CCR1] sleep 12 mem2io -w -i 0xfffdc040,0x6 # disable clock + soft trig [TC_CCR1] mem2io -w -i 0xfffff600,0x4 # enable normal gpio on PB2 [PIO_PER(B)] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ There is also a AT91SAM9G20 specific program for generating PWM (mainly square waves) on TC3, TC4 or TC5 called g20tc_freq. It can generate frequencies from 0.5 Hz to 33 MHz. Note the frequency selection at the high end is limited to 66000000/n where n is an integer, 2 or greater. D. Gilbert 20121101