Difference between revisions of "EBC Exercise 13 Pulse Width Modulation"

From eLinux.org
Jump to: navigation, search
(PWM on the Bone: Added details)
m (PWM on the Bone)
Line 20: Line 20:
 
[[File:PimMux1.png]]
 
[[File:PimMux1.png]]
  
You can control the pin MUXing this way:
+
You can control the pin MUXing this way:
  
 
  beagle$ '''cd /sys/kernel/debug/omap_mux'''
 
  beagle$ '''cd /sys/kernel/debug/omap_mux'''
Line 32: Line 32:
 
  ain6              gpmc_ad8        lcd_data9      mmc0_dat1
 
  ain6              gpmc_ad8        lcd_data9      mmc0_dat1
 
  ain7              gpmc_ad9        lcd_hsync      mmc0_dat2
 
  ain7              gpmc_ad9        lcd_hsync      mmc0_dat2
...
+
...
  
 
There are some 126 pins that you can control what they output.  How do you know which one to change?  Let's use ehrpwm.1:0.  This will show up at ehrpwm1A (the 0 maps to A).  Try:
 
There are some 126 pins that you can control what they output.  How do you know which one to change?  Let's use ehrpwm.1:0.  This will show up at ehrpwm1A (the 0 maps to A).  Try:
Line 48: Line 48:
 
  signals: gpmc_a2 | gmii2_txd3 | rgmii2_td3 | mmc2_dat1 | gpmc_a18 | pr1_mii1_txd2 | ehrpwm1A | gpio1_18
 
  signals: gpmc_a2 | gmii2_txd3 | rgmii2_td3 | mmc2_dat1 | gpmc_a18 | pr1_mii1_txd2 | ehrpwm1A | gpio1_18
  
This says the MUX is presently set on pin '''7'''.  Counting starts on the left with 0.  We can pin '''6'''. So:
+
This says the MUX is presently set on pin '''7'''.  Counting starts on the left with 0.  We want pin '''6'''. So:
  
 
  beagle$ '''echo 6 > gpmc_a2'''
 
  beagle$ '''echo 6 > gpmc_a2'''

Revision as of 06:19, 21 July 2012

thumb‎ Embedded Linux Class by Mark A. Yoder


In a previous exercise (EBC Exercise 11 gpio Polling and Interrupts) you saw how to use the gpio to produce a square wave out using a C program and sysfs. I was able to get a 1.5kHz square wave out; however we can do much better using some built in hardware on the Beagle.

In this exercise we will learn how to use the Beagle's pulse width modulation (pwm) hardware by writing directly to the registers that control it and also learn about pin multiplexing (pin mux) on the way.

PWM on the Bone

The Bone has a PWM interface at /sys/class/pwm/. You can see what's there by:

beagle$ cd /sys/class/pwm
beagle$ ls -F
ecap.0@  ecap.2@      ehrpwm.0:1@  ehrpwm.1:1@  ehrpwm.2:1@
ecap.1@  ehrpwm.0:0@  ehrpwm.1:0@  ehrpwm.2:0@

The AM335x PWM Driver's Guide details what eCAP and eHRPWM are and gives some examples. Before you can use the PWM's, you need to make sure the pin MUXes are set correctly. Check the setting by browsing to http://beagle/pinMux.html (where beagle is the IP address of your Beagle.) to see how the pins are set. You'll see something like:

PimMux1.png

You can control the pin MUXing this way:

beagle$ cd /sys/kernel/debug/omap_mux
beagle$ ls
ain0               gpmc_ad2        lcd_data3      mii1_txd2
ain1               gpmc_ad3        lcd_data4      mii1_txd3
ain2               gpmc_ad4        lcd_data5      mii1_txen
ain3               gpmc_ad5        lcd_data6      mmc0_clk
ain4               gpmc_ad6        lcd_data7      mmc0_cmd
ain5               gpmc_ad7        lcd_data8      mmc0_dat0
ain6               gpmc_ad8        lcd_data9      mmc0_dat1
ain7               gpmc_ad9        lcd_hsync      mmc0_dat2
...

There are some 126 pins that you can control what they output. How do you know which one to change? Let's use ehrpwm.1:0. This will show up at ehrpwm1A (the 0 maps to A). Try:

beagle$ grep ehrpwm *
gpmc_a0:signals: gpmc_a0 | gmii2_txen | rgmii2_tctl | rmii2_txen | gpmc_a16 | pr1_mii_mt1_clk | ehrpwm1_tripzone_input | gpio1_16
gpmc_a1:signals: gpmc_a1 | gmii2_rxdv | rgmii2_rctl | mmc2_dat0 | gpmc_a17 | pr1_mii1_txd3 | ehrpwm0_synco | gpio1_17
gpmc_a2:signals: gpmc_a2 | gmii2_txd3 | rgmii2_td3 | mmc2_dat1 | gpmc_a18 | pr1_mii1_txd2 | ehrpwm1A | gpio1_18
gpmc_a3:signals: gpmc_a3 | gmii2_txd2 | rgmii2_td2 | mmc2_dat2 | gpmc_a19 | pr1_mii1_txd1 | ehrpwm1B | gpio1_19
...

This shows that ehrpwm1A shows up in the file gpmc_a2. Look in the file

beagle$ cat gpmc_a2
name: gpmc_a2.gpio1_18 (0x44e10848/0x848 = 0x0007), b NA, t NA
mode: OMAP_PIN_OUTPUT | OMAP_MUX_MODE7
signals: gpmc_a2 | gmii2_txd3 | rgmii2_td3 | mmc2_dat1 | gpmc_a18 | pr1_mii1_txd2 | ehrpwm1A | gpio1_18

This says the MUX is presently set on pin 7. Counting starts on the left with 0. We want pin 6. So:

beagle$ echo 6 > gpmc_a2
beagle$ cat gpmc_a2
name: gpmc_a2.ehrpwm1A (0x44e10848/0x848 = 0x0006), b NA, t NA
mode: OMAP_PIN_OUTPUT | OMAP_MUX_MODE6
signals: gpmc_a2 | gmii2_txd3 | rgmii2_td3 | mmc2_dat1 | gpmc_a18 | pr1_mii1_txd2 | ehrpwm1A | gpio1_18

Now it's mode 6, which is the PWM output. Refresh you pin MUX web page to see.

PinMux2.png

Notice header P9, pin 14 has changed! Now let's turn on the PWM.

beagle$ cd /sys/class/pwm/ehrpwm.1\:0
beagle$ echo 1 > run
beagle$ echo 100 > period_freq
beagle$ echo 10 > duty_percent

Stick a scope on the pin and you should see a 100Hz, 10% duty cycle square wave.


Good discussion

Look in cloud9/bonescript/index.js to see how to do pinMuxing via /sys/kernel/debug/omap_mux/

PWM on the xM

PWM and pin MUXing

The DM3730 has 11 general purpose timers, 4 of which (gpt8-gpt11) can be brought out of the chip and used for pulse width modulation (DM3730 TRM page 2689). The problem is the DM3730 has more internal lines than hardware I/O pins. The solution is that I/O pins run though a MUX that selects which internal lines appear on I/O pins. A given pin can have one from as many as eight lines assigned to it.

These MUXes are set at boot time, and must be set when the kernel boots, or in u-boot. I couldn't set them during kernel boot with the 2.6.32 kernel, so I used u-boot. BeagleBoardPinMux is a good place to learn about the pin MUXing. The u-boot details are here.

BeagleBoardPWM is a nice overview of how to do PWM on the Beagle. The version of the kernel and u-boot that I've given you should already be configured to access the PWM pins. If it isn't you'll have to recompile the Kernel and u-boot.

The standard way to interface with the outside world in Linux is through Kernel Drivers. Currently there are no standard PWM driver for the Beagle, though a couple have been proposed ([1], [2] and [3]). BeagleBoardPWM takes a more traditional MCU approach by accessing the memory mapped PWD registers directly using mmap in a C program. Although this approach works, it is really transitional until a standard can be established.

You could even do PWM from a shell command by using devmem2 to write to the memory mapped registers from a command line.

Here's another PWM lead.

Assignment

If your git repository is set up just:

beagle$ cd exercises
beagle$ git pull
beagle$ cd pwm

(Follow the instructions here if you aren't set up for git.)

  1. Look at the files to see what they are doing.
  2. Run make, then pwd-demo.
  3. Hook up a oscilloscope. (See Table 22 of the Beagle System Reference manual to see where to probe.) Are the pwd outputs doing what you expected?
  4. What's the highest frequency you can generate? What's the lowest?
  5. Create a new C program, based on pwm-demo, that takes 3 parameters, the <pwm to use>, <frequency> and <duty cycle>.
  6. Create a shell file that will call your new program and set up the three pwm's that appear on the expansion header and program them to do something interesting.
  7. Write a shell file that will do the pin MUXing using devmem2.
  8. Rewrite pwm-demo as a shell file that uses devmem2.

Resources

  1. BeagleBoardPWM from ECE597
  2. BeagleBoard/GSoC/2010_Projects/Pulse_Width_Modulation Google SoC project
  3. BeagleBoardPinMux, how to set the pin mux.
  4. Buttons and PWM
  5. Shaky PWMs
  6. PWM on the bone




thumb‎ Embedded Linux Class by Mark A. Yoder