Enabling PWM on Beagle Bone Black
So I decided to try and get 4 independent PWM ports up and running on the Beagle Bone Black. The process is fairly straightforward with a couple of caveats.
Firstly, the kernel which you are using on the device must be 3.8 (at the time of this writing) and support capemgr, which is essentially the manager for runtime device tree overlays. I previously tried the 3.13 kernel but this had no support for overlays and you will have to edit the dts files after pulling the kernel. This was a little too involved for me so I just changed the kernel version. These overlays enable runtime changes to the device tree blob passed at boot by the bootloader.
By enabling these runtime overlays we can essentially change the hardware configuration on the BBB. The reason why we need to change this hardware configuration is to re-direct the P9 and P8 port muxes to the appropriate hardware block, in our case, the PWM controllers.
The pins which I selected are
Port 8 Pin 13
Port 9 Pins 14, 28 and 42
I avoided selecting the pairs P8 13/19 or P9 14/16 since it seems that changing the PWM period is not allowed with an error of:
sh: echo: write error: Invalid argument”. Having any one from the pair seems to not yield that error, however having both does not seem to work. I even tried first changing the duty cycle to a value much lower than the period but to no avail.
Without further ado, this is what my boot arguments are in my uEnv.txt file which can be edited by mounting
sudo mount /dev/mmcblk0p1 /media/bootfs/
optargs=quiet capemgr.enable_partno=am33xx_pwm,bone_pwm_P8_13,bone_pwm_P9_28,bone_pwm_P9_14,bone_pwm_P9_42,BB-UART1,BB-UART4,BB-UART4,BB-UART5
There are several other PWM pins we can select as well with the caveat mention above.
Above I am also enabling all the UARTs as my project needs them.
To setup all the PWM pins, I created symlinks in my home directory from /sys/devices/ocp.3/pwm_test_P* then I wrote a little script:
#!/bin/sh pwm_port=p8_13 period_ns=1000 duty=750 echo "Setting ${pwm_port} Period: ${period_ns} Duty Cycle: ${duty}" echo 0 > pwm_${pwm_port}/duty echo ${period_ns} > pwm_${pwm_port}/period echo ${duty} > pwm_${pwm_port}/duty pwm_port=p9_14 period_ns=1000 duty=500 echo "Setting ${pwm_port} Period: ${period_ns} Duty Cycle: ${duty}" echo 0 > pwm_${pwm_port}/duty echo ${period_ns} > pwm_${pwm_port}/period echo ${duty} > pwm_${pwm_port}/duty pwm_port=p9_28 period_ns=1000 duty=250 echo "Setting ${pwm_port} Period: ${period_ns} Duty Cycle: ${duty}" echo 0 > pwm_${pwm_port}/duty echo ${period_ns} > pwm_${pwm_port}/period echo ${duty} > pwm_${pwm_port}/duty pwm_port=p9_42 period_ns=1000 duty=125 echo "Setting ${pwm_port} Period: ${period_ns} Duty Cycle: ${duty}" echo 0 > pwm_${pwm_port}/duty echo ${period_ns} > pwm_${pwm_port}/period echo ${duty} > pwm_${pwm_port}/duty
Remember to first chmod 660 the contents of /sys/devices/ocp.3/pwm_test_P* or you will have to invoke the above script with sudo, which is rather annoying.
This will set each PWM pin to a different duty cycle on a 1uS period. the 1uS period is far too agressive, but it was just a test.
Hooking up a scope probe to each pin seems to yield satisfactory results.
- Introduction to Kernel Modules
- Git – Cherry Picking Specific Commit Ranges