|
|
(11 intermediate revisions by 2 users not shown) |
Line 2: |
Line 2: |
| [[Category:ECE497]] | | [[Category:ECE497]] |
| {{YoderHead}} | | {{YoderHead}} |
| + | {{EBC3.8}}This is for the 3.8 kernel. [[EBC Exercise 13 Pulse Width Modulation 3.2]] is for the 3.2 kernel. |
| | | |
| 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 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 you will learn how to use the Beagle's pulse width modulation (pwm) hardware using the sysfs interface and also learn about pin multiplexing (pin mux) on the way. | + | In this exercise you will learn how to use the Beagle's pulse width modulation (pwm) hardware using the sysfs interface. |
| | | |
− | == PWM on the Bone == | + | == Pulse Width Modulation == |
| | | |
− | The Bone has a PWM interface at <code>/sys/class/pwm/</code>. You can see what's there by: | + | (Note: The pwm interface seems to changing. Some of this may not apply in the future.) |
| | | |
− | beagle$ '''cd /sys/class/pwm''' | + | We have to run a couple of commands to make the PWM interface appear. Try |
− | beagle$ '''ls -F''' | + | bone$ '''SLOTS=/sys/devices/bone_capemgr.*/slots''' |
− | ecap.0@ ecap.2@ ehrpwm.0:1@ ehrpwm.1:1@ ehrpwm.2:1@ | + | bone$ '''echo am33xx_pwm > $SLOTS''' |
− | ecap.1@ ehrpwm.0:0@ ehrpwm.1:0@ ehrpwm.2:0@ | + | bone$ '''echo bone_pwm_P9_21 > $SLOTS''' |
| + | bone$ '''cd /sys/devices/ocp.2/pwm_test_P9_21.14''' |
| + | bone$ '''ls''' |
| + | driver duty modalias period polarity power run subsystem uevent |
| | | |
− | The [http://processors.wiki.ti.com/index.php/AM335x_PWM_Driver's_Guide 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. There are two ways to do this, the slick way (which may not work) and the sure way. | + | The units are in ns. |
| + | Try a 1Hz frequency with a 25% duty cycle |
| + | bone$ '''echo 1000000000 > period''' |
| + | bone$ '''echo 250000000 > duty''' |
| + | bone$ '''echo 1 > run''' |
| | | |
− | === The Slick Way ===
| + | Connect the LED from and watch it flash. Try changing the frequency and duty cycle. You may have to set the duty cycle to 0 to change the frequency. Can you guess why? |
| | | |
− | On your Bone
| + | === Challenge === |
| + | Combine the analog in and the PWM by having the pot control the frequency or the duty cycle of the LED. |
| | | |
− | beagle$ '''cd exercises'''
| + | If you have an oscilloscope try probing pin P9_21. I'm getting a nice clean 1Hz signal, with no variation. Let's try a higher frequency, like 10 MHz. |
− | beagle$ '''git pull'''
| + | beagle$ '''echo 50 > duty_ns''' |
− | beagle$ '''cd pinMux'''
| + | beagle$ '''echo 100 > period_ns''' |
− | beagle$ '''ln -s $PWD/pinMux.html /var/lib/cloud9/bone101''' | + | I'm getting a 9 MHz signal that has lots of ringing. The timer in the bone must be off a bit. |
− | beagle$ '''cd /var/lib/cloud9''' | |
− | beagle$ '''git pull''' | |
− | beagle$ '''shutdown -r now'''
| |
| | | |
− | Yup, after updating /var/lib/cloud9 you have to reboot.
| + | The [http://processors.wiki.ti.com/index.php/AM335x_PWM_Driver's_Guide AM335x PWM Driver's Guide] details what eCAP and eHRPWM are and gives some examples. |
− | | |
− | Now, check the settings by browsing to [http://beagle/pinMux.html http://''bone''/pinMux.html] (where ''bone'' is the IP address of your Bone.) to see how the pins are set. You'll see something like:
| |
− | | |
− | [[File:PimMux1.png]]
| |
− | | |
− | === The Sure Way ===
| |
− | | |
− | beagle$ '''cd ~/exercises/pinMux'''
| |
− | beagle$ '''./pinMux.sh'''
| |
− | | |
− | This just lists all the files in the mux directory and their contents.
| |
− | | |
− | === Either Way ===
| |
− | | |
− | This just lists every find in the mux directory.
| |
− | | |
− | 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.
| |
− | | |
− | [[File: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 10 > period_freq'''
| |
− | beagle$ '''echo 25 > duty_percent'''
| |
− | | |
− | Connect the LED from [[EBC_Exercise_10_Flashing_an_LED#Adding_your_own_LED_-_bone]] and watch it flash. Try changing the frequency and duty cycle. You may have to set the duty cycle to 0 to change the frequency. Can you guess why?
| |
− | | |
− | Stick a scope on the pin and see if the frequency and duty cycle are right. What's the highest frequency you can get? What's the lowest?
| |
− | | |
− | [https://groups.google.com/forum/#!searchin/beagleboard/bone$20pwm/beagleboard/alKf67dwMHI/t_tIQpJyM8wJ Good discussion]
| |
− | | |
− | === Assignment ===
| |
− | | |
− | If your git repository is set up just:
| |
− | beagle$ '''cd exercises'''
| |
− | beagle$ '''git pull'''
| |
− | beagle$ '''cd pwm'''
| |
− | (Follow the instructions [[EBC_Exercise_01a_Getting_Exercise_Support_Materials | here]] if you aren't set up for git.)
| |
− | | |
− | # Attach an LED and verify that it's blinking correctly.
| |
− | # Hook up a oscilloscope. Are the PWM outputs doing what you expected?
| |
− | # What's the highest frequency you can generate? What's the lowest?
| |
− | # Verify your understanding of pin MUXing by generating a PWM signal that appears on pin 45 of P8. Document how you did it.
| |
− | | |
− | == PWM on the xM ==
| |
− | '''This section needs updating to use /sys/kernel/debug/omap_mux to get the pin MUXes.'''
| |
− | | |
− | 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 ([http://www.ti.com/product/dm3730#technicaldocuments 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 [[BeagleBoardPinMux#Setting_Mux_Through_u-boot | 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 ([https://groups.google.com/d/topic/beagleboard/RI3qTxn68bY/discussion], [http://git.billgatliff.com/pwm.git/?p=pwm.git;a=commit;h=a49cbfff0fa09bff40d328f8985a0a7a7b951d6f] and [http://git.pengutronix.de/?p=imx/linux-2.6.git;a=commit;h=137654cde98a2ffe548f47f02e7fde512bc2091c]). [[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 [http://esdw.wordpress.com/2010/03/25/a-useful-tool-devmem2/ devmem2] to write to the memory mapped registers from a command line.
| |
− | | |
− | [http://www.jumpnowtek.com/index.php?option=com_content&view=article&id=56&Itemid=63 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 [[EBC_Exercise_01a_Getting_Exercise_Support_Materials | here]] if you aren't set up for git.)
| |
− | | |
− | # Look at the files to see what they are doing.
| |
− | # Run '''make''', then '''pwm-demo'''.
| |
− | # Hook up a oscilloscope. (See Table 22 of the [http://beagleboard.org/static/BBxMSRM_latest.pdf Beagle System Reference manual] to see where to probe.) Are the pwm outputs doing what you expected?
| |
− | # What's the highest frequency you can generate? What's the lowest?
| |
− | # Create a new C program, based on pwm-demo, that takes 3 parameters, the <pwm to use>, <frequency> and <duty cycle>.
| |
− | # 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.
| |
− | # Write a shell file that will do the pin MUXing using '''devmem2'''.
| |
− | # Rewrite '''pwm-demo''' as a shell file that uses '''devmem2'''.
| |
− | | |
− | == Resources ==
| |
− | | |
− | # [[BeagleBoardPWM]] from ECE597
| |
− | # [[BeagleBoard/GSoC/2010_Projects/Pulse_Width_Modulation]] Google SoC project
| |
− | # [[BeagleBoardPinMux]], how to set the pin mux.
| |
− | # [http://www.gigamegablog.com/ Buttons and PWM]
| |
− | # [http://veter-project.blogspot.com/2011/09/real-time-enough-about-pwms-and-shaky.html Shaky PWMs]
| |
− | # [https://groups.google.com/forum/#!searchin/beagleboard/bone$20pwm/beagleboard/alKf67dwMHI/t_tIQpJyM8wJ PWM on the bone]
| |
| | | |
| {{YoderFoot}} | | {{YoderFoot}} |
Embedded Linux Class by Mark A. Yoder
This is for the 3.8 kernel. EBC Exercise 13 Pulse Width Modulation 3.2 is for the 3.2 kernel.
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 you will learn how to use the Beagle's pulse width modulation (pwm) hardware using the sysfs interface.
Pulse Width Modulation
(Note: The pwm interface seems to changing. Some of this may not apply in the future.)
We have to run a couple of commands to make the PWM interface appear. Try
bone$ SLOTS=/sys/devices/bone_capemgr.*/slots
bone$ echo am33xx_pwm > $SLOTS
bone$ echo bone_pwm_P9_21 > $SLOTS
bone$ cd /sys/devices/ocp.2/pwm_test_P9_21.14
bone$ ls
driver duty modalias period polarity power run subsystem uevent
The units are in ns.
Try a 1Hz frequency with a 25% duty cycle
bone$ echo 1000000000 > period
bone$ echo 250000000 > duty
bone$ echo 1 > run
Connect the LED from and watch it flash. Try changing the frequency and duty cycle. You may have to set the duty cycle to 0 to change the frequency. Can you guess why?
Challenge
Combine the analog in and the PWM by having the pot control the frequency or the duty cycle of the LED.
If you have an oscilloscope try probing pin P9_21. I'm getting a nice clean 1Hz signal, with no variation. Let's try a higher frequency, like 10 MHz.
beagle$ echo 50 > duty_ns
beagle$ echo 100 > period_ns
I'm getting a 9 MHz signal that has lots of ringing. The timer in the bone must be off a bit.
The AM335x PWM Driver's Guide details what eCAP and eHRPWM are and gives some examples.
Embedded Linux Class by Mark A. Yoder