                          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
