Gumstix PWMLast Updated on Monday, 12 September 2011 19:37 Controlling PWM outputs from an OMAP3 based Linux systems.
OverviewThere are 12 general purpose timers available on the OMAP3, four of them can be used to generate PWM outputs. GPT8 - GPT11 are the PWM capable timers. They are exposed on the Overo expansion card 40 pin headers as
PWM Kernel ModuleThere is a PWM kernel module available on Github here - omap3-pwm. The module provides a character device interface that allows standard file operations to control all four of the PWM timers. root@overo# insmod pwm.ko timers=10 And you could measure Pin28 to check the value. Send a zero for the duty cycle or unload the module to turn off the PWM signal. The driver also supports a 'servo' mode of operation with a 50 Hz signal and a duty cycle range of 1-2 ms. See the project README for details on building and using.
Command Line - /dev/memNOTE: The devmem2 procedure won't work with kernel 2.6.39 or greater. The source clocks for PWM are now disabled by default and have to be explicitly enabled before the timer registers can be accessed. The devmem2 steps below do not do this. Refer to the omap3-pwm driver and look for pwm_enable_clock() in pwm.c to see how to enable the clocks in a driver.
Any userspace program that can access /dev/mem can operate a PWM timer. Since devmem2 is part of all the standard Gumstix images, it's a convenient program to use. Here's how to start PWM10 from the command line with a frequency of 1kHz and a duty cycle of 50%. root@overo# devmem2 0x48086024 w 0 The signal can then be measured on Pin28 on the expansion board header using Pin15 as ground.
BreakdownHere is what those devmem2 calls above did.
1. root@overo# devmem2 0x48086024 w 0Disables the timer completely before any configuration changes.
2. root@overo# devmem2 0x48002176 h 0x0002Change the PAD multiplexing to allow PWM10 off this pin instead of its current configuration as GPIO_145. (Note: You can change the mux configuration for any pad/pin on a running system using this same procedure.)
3. root@overo# devmem2 0x4808602C w 0xFFFFFFE0Set the frequency of the PWM signal to 1024 Hz.
4. root@overo# devmem2 0x48086038 w 0xFFFFFFEFThis sets the duty cycle of the PWM signal to 50%, ON time one half of cycle time.
5. root@overo# devmem2 0x48086028 w 0xFFFFFFE0This primes the timer counter for the first cycle. Primed with the same value as the frequency.
6. root@overo# devmem2 0x48086024 w 0x01843This starts the timer in PWM mode.
Further Breakdown1. root@overo# devmem2 0x48086024 w 0I'll skip step 1 above as it will be obvious later. You'll need the OMAP3 Technical Reference Manual (TRM) to follow the rest of this.
2. root@overo# devmem2 0x48002176 h 0x0002The OMAP3 allows multiple functional uses for many of the pads coming out of the chip. Gumstix has brought some of the pads out as pins on the expansion header. The functionality of a pad is controlled by its Pad Configuration Register. Each register controls two pads. Each pad can have up to 7 different modes, but most have only a few. The address 0x48002176 comes from the TRM Table 7.5 (page 838 if you are looking at Revision D). The register names in the table refer to the Mode 0 functionality of the pad controlled by the lower 16 bits of the register. So for instance,
The PWM timers are a Mode 2 configuration. The reason for 0x48002176 is because gpt10_pwm_evt is the upper 16 bits of physical address 0x48002174 or 0x48002174 + 2. The PADCONF registers are 32 bits, but they can be accessed at 16 bit offsets. 0x0002 is the value being written to the register. The fields of the PADCONF register are defined in Section 7.6.3 of the TRM, Table 7-86. The value 0x0002 sets the muxmode to 2 and all other fields to zero or disabled.
3. root@overo# devmem2 0x4808602C w 0xFFFFFFE0Chapter 16 is all about timers. Section 16.2.4.6 talks about Pulse-Width Modulation. Section 16.3 has the register offsets and descriptions. Each timer has 19 registers that can be configured. To access a timer register, you first find the base address for the timer and then add the offset for the particular register you are interested in. The base addresses for each timer can be found in Table 16-12. Here are the PWM capable timer base addresses. Each timer has 4K bytes of memory assigned for registers.
Only 4 of the registers need modification to control PWM functionality, here are the names and offsets.
So the address 0x4808602C refers to the TLDR register for Timer 10.
The TLDR register controls the frequency of the PWM signal (Section 16.2.4.6). The formula for the frequency calculation is FREQUENCY = GPTi_FCLK / ((0xFFFF FFFF - TLDR) + 1) where GPTi_FCLK defaults to
For this PWM10 example, a TLDR value of 0xFFFF FFE0 results in a frequency of FREQUENCY = 32 kHz / ((0xFFFF FFFF - 0xFFFF FFFE0) + 1) The TLDR value also determines the number of settings or adjustment granularity you have for duty-cycle adjustments. You can calculate it this way NUM_SETTINGS = 0xFFFF FFFE - TLDR In this example there will be NUM_SETTINGS = 0xFFFF FFFE - 0xFFFF FFE0 = 0x1E = 30
4. root@overo# devmem2 0x48086038 w 0xFFFFFFEFAddress 0x48086038 is for the TMAR register for Timer 10.
The TMAR register controls the duty-cycle of the PWM signal. It's the on-time for the PWM pulse.
TMAR values are in the range (TLDR + 1) to 0xFFFF FFFE or as calculated above there are NUM_SETTINGS possible values for TMAR. Calculate an appropriate TMAR for a particular duty-cycle as follows TMAR = TLDR + (NUM_SETTINGS * DUTY_CYCLE_PERCENTAGE) In this example to get a 50% duty-cycle the calculation is TMAR = 0xFFFF FFE0 + (30 * (50 / 100)) To get a 10% duty-cycle it would be TMAR = 0xFFFF FFE0 + (30 * (10 / 100)) You do need to keep TMAR in the range TLDR + 1 to 0xFFFF FFFE. 5. root@overo# devmem2 0x48086028 w 0xFFFFFFE0Address 0x48086028 is the TCRR register for Timer 10. This is the timer counter register which counts up and gets reset to the TLDR value during PWM operation whenever 0xFFFF FFFF or overflow is reached. The TMAR register is compared to the TCRR to know when to trigger a change in the output. We prime it here by giving it an initial value of TLDR but any value from TLDR to 0xFFFF FFFE would work. Bad explanation, I'll get back to this... 6. root@overo# devmem2 0x48086024 w 0x01843Address 0x48086028 is the TCLR register for Timer 10. Unlike the other PWM timer registers which took values interpreted as numbers, the TLDR register is interpreted as a series of bit fields. From table 16-21 of the TRM:
TCLR Register Description
So the value 0x1843 written to the TCLR register translates to
To be continued... Additional ReferencesCurtis Olson has an Overo PWM article Gumstix Overo, RC Servos and PWM Signal Generation |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Gumstix PWM