linux 3.8 PWM guide?

I’m having a real time trying to figure out how to enable PWM on the BBB.

Apparently in 3.8 you need to use “device trees” which require compiling code to go into /boot/dtbs/.

I’m completely confused on the hows and whys. Everything I read seems to suggest that I not only need some custom version of the kernel, but also a custom version of dtc. Can this be true? It seems kinda nuts, but maybe that’s the state of affairs.

I can use the /sys filesystem to enable pwm’s and enable P8_13, but it’s apparently not muxed (to mode 4?) so none of my changes to the period_ns/duty_ns files seem to do anything.

If anyone has a guide that shows a newbie like me, step by step, what is going on, I would so very greatly appreciate it!

-JNY

It's simpler that you could think:

  modprobe pwm_test
  echo am33xx_pwm > /sys/devices/bone_capemgr.9/slots
  echo bone_pwm_P9_14 > /sys/devices/bone_capemgr.9/slots
  echo 500 > /sys/devices/ocp.2/pwm_test_P9_14.*/period
  echo 250 > /sys/devices/ocp.2/pwm_test_P9_14.*/duty

This will connect PWM to pin P9_14 and generate on the pin ~2MHz
waveform with 50% duty.

j.

pwm_test not found. I thought that was the code from pwm_test.c, which was the kernal patch I was told I didn’t need to use because of magical device trees.

install kernel-module-pwm-test package.

j.

I’m guessing on angstrom? Or will ubuntu work? Which version?

I usually prefer arch, but support on the BBB seems weak on arch. I’m currently flashing the latest angstrom to attempt this method, but would it work on ubuntu as well? Ubuntu has support for JDK7, where I want to do my development.

Thanks big time,
-JNY

I'm using angstrom. Unfortunately I can't help you with ubuntu, but
this may give you some ideas:
http://hipstercircuits.com/enable-pwm-on-beaglebone-with-device-tree-overlays/

j.

I’ve read that 20 times to no avail. haha.

I’m installing angstrom. If I can get it working in any distro, I can figure out how to bring in my tools.

Thank you very much for your time.

-JNY

What version of the kernel / angstrom are you using? It didn’t work on my fresh install of the latest angstrom.

root@beaglebone:/sys/devices/bone_capemgr.8# echo am33xx_pwm > slots
-sh: echo: write error: No such file or directory

Install angstrom from the latest flasher from
http://beagleboard.org/latest-images. Everything worked for me OOTB.

j.

What image did you use?

j.

I am absolutely using this file:

demo_beaglebone_BBB-eMMC-flasher-2013.05.27.xz

I uncompress it to it’s 4gB of glory, then dd it onto my flash card.

Then I put it in and boot (my onboard flash has no image, so it’s definately booting from sdcard)

Then I use those commands and it fails when I try to inable am33xx_pwm

cat slots

6: ff:P-O-- Override Board Name,00A0,Override Manuf,am33xx_pwm

Did you flash the image, or are you trying to configure PWM on system
running from the SD card?

j.

I dd if=[file] of=/dev/sdd and boot it up.

Should I be doing something else after that to get the system live?

Boot from SD card, go for a long walk and after the flashed finishes
work remove the SD card and boot the system from the on-board flash.

j.

I am ashamed…

I didn’t read the last paragraph of the instructions because it all looked to be identical to every other RPi/BB distro I’ve ever used.

I had no idea it was meant to upgrade the eMMC rather than run live from the SD card.

Thanks.

Thanks much for your help good sir. I rebooted this morning and it works beautifully I think. I say I think because this microservo from radioshak just moves to max out when I do a period of 20000000 and any duty cycle between 1666666-6666666 (which should be moving twards the middle.

It just maxes out but I think it could be because it is expecting a higher voltage signal? I’m not sure because if I set it too low the motor stops maxing out.

I have been playing around with Saad Ahmad c++ library code mentioned in the thread:

https://groups.google.com/forum/embed/?place=forum/beagleboard&showsearch=true&showpopout=true&showtabs=true&hideforumtitle=true&parenturl=http%3A%2F%2Fbeagleboard.org%2FCommunity%2FForums%3Futm_expid%3D6702460-6%26utm_referrer%3Dhttp%3A%2F%2Fbeagleboard.org%2FSupport%2FHardware%2520Support#!category-topic/beagleboard/C2tzvRYk1Wg

Plus when I was first playing with these commands, I also found that the pulse was wrong for servos, as the polarity was wrong so for example when I was trying to create a 1500us pulse it was actually creating a 20000-1500us pulse. You can change this by updating the polarity variable/file of the test. For your Duty I would expect the valid ranges in us to within the 500-2500us range or maybe tighter (750-2250us). Obviously need to multiple by 1000 to get to ns.

I did an update to his test program that now looks like;

`
#include “PWM.h”
#include
#include
#include <unistd.h>
int main()
{
const int delayMS = 50;
const long periodNS = 20 * MILLISECONDS_TO_NANOSECONDS;

PWM::Pin pinA(“P8_13”, periodNS); // Since both pins share the same channel, they’re periods must be the same
std::cout << “P8_13 created” << std::endl;

PWM::Pin pinB(“P8_19”, periodNS);
std::cout << “P8_19 created” << std::endl;

int slot = PWM::GetCapeManagerSlot(“P8_13”);
std::stringstream ss;
ss << slot;
std::cout << "Found: " << ss.str() << std::endl;

// Enable both only after we have set the periods properly.
// Otherwise we will have conflicts since each pin will try to set its own period and conflict with the others
std::cout << “Before PinA enable” << std::endl;
pinA.Enable();
std::cout << “Before PinB enable” << std::endl;
pinB.Enable();
std::cout << “Pins Setup and ready to go!” << std::endl;

// I want to do a sweep of the two servos from 500us to 2500us
for (int pw = 500; pw < 2500; pw+=100)
{
pinA.SetDutyUS(pw);
pinB.SetDutyUS(3000-pw); // reverse this one.
usleep(100 * 1000); // delay for a bit maybe 5 pulses per pw
}
// Tell both pins to stop.
pinA.Disable();
pinB.Disable();

std::cout << “Done everything. Quiting now!” << std::endl;
}

`

I have my Saleae logic analyzer hooked up to these pins and have verified that I am now generating what appears to be very good servo like output. The only interesting thing was figuring out the best way to end the pulses. If I set the duty to zero, it created some strange outputs on one of the pins, likewise if I just let the objects get destroyed, one channel generated maybe 6 more pulses… Disable did it cleanly.

Note: I went through the complete steps to rebuild the test_pwm object plus create the SC_PWM overlays like he spelled out in his write up.

Kurt

As you mentioned without doing anything, with the test program, it is probably fine as it simply output the 2nd one during your delay. Will try later to see if removing it helps, but again it probably does not hurt anything for it to output a few extra pulses.

The 2nd test I did of setting the duty to 0, is something I wanted to check out as with my robot, I may wish to issue a command (over the XBee) to tell the motors to relax. So wanted to see if that would do it cleanly… What I found is setting them both to zero, one or both of these channels would output a full 20ms pulse and then every 20ms (my Frame rate), they both output a very short pulse in the nature of .25us. Could be smaller, I have my LA set for 8mhz sample rate. Again not a big deal as setting the enable cleans up nicely.

Thanks again
Kurt

I figured it out! I was thinking of the duty cycles backwards it seems. I needed to give it numbers close to the high end, rather than the low end.

Perhaps this is the “reverse polarity” stuff people were talking about in relation to duty cycles?

I have a driver working now. Thank you very much.