I found that while trying to get PWM control for my motors/servos on the BBB many of the old tutorials were no longer working. Using what I found at http://www.phys-x.org/rbots/index.php?option=com_content&view=article&id=106:lesson-3-beaglebone-black-pwm&catid=46:beaglebone-black&Itemid=81 and https://groups.google.com/d/msg/beagleboard/wjbOVE6ItNg/Dym4H4HuI8gJ I modified the driver and firmware and implemented a library on top of it.
- Allows changing the period of EHRPWM modules at run time
- Allows for servo and motor esc control
- Basic examples to show LED brightness fading
NOTE: My kernel building knowledge is limited and these are the stops I followed to make it work. If someone has better/more correct steps please submit them!
Firmware and update driver
Compiling the driver on the BeagleBone
- Download & install build prereqs (Angstrom)
opkg update opkg upgrade opkg install kernel-dev opkg install kernel-headers opkg install task-native-sdk opkg git
- Set up build environment and make the module
cd /usr/src/kernel make scripts ln -s /usr/src/kernel /lib/modules/$(uname -r)/build cd ~ git clone git://SaadAhmad/beaglebone-black-cpp-PWM.git cd beaglebone-black-cpp-PWM/driver make
Compiling the driver and module (Optional)
Follow the instructions at http://beagleboard.org/linux or http://wiki.beyondlogic.org/index.php/BeagleBoneBlack_Building_Kernel to setup your kernel build files.
Copy/paste pwm_test.c into <source_dir>/kernel/drivers/pwm
cp <repo_dir>/driver/pwm_test.c <source_dir>/kernel/drivers/pwm/
- For the firmware files, copy them over to <source_dir>/kernel/firmware/capes/
cp <repo_dir>/firmware/*dts <source_dir>/kernel/firmware/capes/
- Open up <source_dir>/kernel/firmware/Makefile and after the bone_pwm_P9_42-00A0.dtbo \ (line 179) add in the following
sc_pwm_P8_13-00A0.dtbo \ sc_pwm_P8_19-00A0.dtbo \ sc_pwm_P8_34-00A0.dtbo \ sc_pwm_P8_36-00A0.dtbo \ sc_pwm_P8_45-00A0.dtbo \ sc_pwm_P8_46-00A0.dtbo \ sc_pwm_P9_14-00A0.dtbo \ sc_pwm_P9_16-00A0.dtbo \ sc_pwm_P9_21-00A0.dtbo \ sc_pwm_P9_22-00A0.dtbo \ sc_pwm_P9_28-00A0.dtbo \ sc_pwm_P9_29-00A0.dtbo \ sc_pwm_P9_31-00A0.dtbo \ sc_pwm_P9_42-00A0.dtbo \
- Once you have those changes, compile the kernel again so it builds the updated firmware/driver
Using the compiled files
Note you can use the compiled kernel driver file however I'm not sure how easily it will work with different kernel versions. At the time I compiled it for v3.8.13 and it seems to work for that. If the provided file doesn't work then you might want to try rebuilding it.
- First make sure that your beaglebone isn't running any any of the overlays from the current bone_pwm and that the pwm_test module isnt loaded A reboot should fix this however if you dont want to reboot you can do the following steps to unload the driver
cat /sys/devices/bone_capemgr.<WHATEVER YOUR NUMBER IS HERE>/slots # Find the slot for any pwm modules echo -<Slot # for the PWM modules> > /sys/devices/bone_capemgr.<WHATEVER YOUR NUMBER IS HERE>/slots # Repeat for all modules #Once done modprobe -r pwm_test.ko
- Backup the old pwm_test.ko file
cd /lib/modules/<kernel version>/kernel/drivers/pwm/ cp pwm_test.ko pwm_test.ko.orig
Find the built pwm_test.ko file and copy it over to /lib/modules//kernel/drivers/pwm/
Copy over the built dtbo (sc_pwm_P*.dtbo) files to /lib/firmware
Youre done setting up the files! Do a reboot and you should be set
- Load in the am33xx_pwm module and load in which even PWM pins (the names of the dtb files you copied over) you want loaded.
echo am33xx_pwm > /sys/devices/bone_capemgr.<WHATEVER YOUR NUMBER IS HERE>/slots #Example pin firmware would be sc_pwm_P8_13 echo sc_pwm_P<use whatever pins you want> > /sys/devices/bone_capemgr.<WHATEVER YOUR NUMBER IS HERE>/slots
Locate the driver interface. It is in /sys/devices/ocp./pwm_test_
Set the periods to to whatever value you want (Make sure that the period on both channels of each EHRPWM is same) by doing
echo <Period Value> > /sys/devices/ocp.<number>/pwm_test_<Whatever pin name you chose>/period
- Set the duty to to whatever value you want (Make sure that the period on both channels of each EHRPWM is same) by doing
echo <Duty Value> > /sys/devices/ocp.<number>/pwm_test_<Whatever pin name you chose>/duty
Note: As was pointed out by Kurt (https://groups.google.com/d/msg/beagleboard/qma8bMph0yM/nOtE1R-gQpAJ) the polarity by default is inverted. The duty by default repersents the time low instead of the time high. Fix the polarity so that the duty specifies the high time by doing
echo 0 > /sys/devices/ocp.<number>/pwm_test_<Whatever pin name you chose>/polarity
Where 0 is for active high and 1 is for active low (default)
- Once configured, enable the pwm by doing
echo 1 > /sys/devices/ocp.<number>/pwm_test_<Whatever pin name you chose>/run
- If you want to reset the period for an EHRPWM where both channels are active, you need to unload the entire PWM module and restart from step 1. (You can skip loading in am33xx_pwm). This is similar to what you did in the Using compiled files in step 1.
The libary provided wraps most of these functions so that they can be be used in your C++ application. Note this isn't compatible with C however it would be great if people were willing to help out and make it happen!
I have provided a BasicPWMExample.cpp which shows you how to get an LED to fade in and out (NOTE dont actually connect the LED directly to your PWM output otherwise you may damage it). It also includes a MotorExample.cpp and ServoExample.cpp which show you how to use a motor and servo, respectively. Just type "make" in the the library directory and it will compile the examples.
Just copy over the CPP/Header files into your application and you are good to go!
I have described a bit about the problem I found with the PWM and how the fix works at http://saadahmad.ca/using-pwm-on-the-beaglebone-black/
On a smaller note, if anyone knows how to make and submit this as a patch into the BBB kernel I would greatly appreciate some help!