BBB Pulse Width Modulation Linux 3.181-bone1

Hi,

I am trying to get PWM to work on a Beagle Bone Black, 3.18.1 kernel. I have am using Robert C Nelson’s kernel and have managed to compile it. I have also got Device trees to work in that I have a Makefile which creates device trees and compiles them. (Uses cpp, then dtc).

The makefile emulates how the Device Tree is compiled using the build_kermel.sh. So far so good. I got the SPI to work in the that I can see the /dev/spidev1.0 devices. That was simple in that all I had to do was to un-comment the include in the file.

What I am stuck on is how to get PWM’s to work. If Robert or someone could tell me how to set pin P8_13 to be a PWM using device trees using Kernel 3.18.1 that would be very helpful. Also some notes of what to look for in /dev/ and /sys/devices would also be helpful. I see quite a few examples for Kernel 3.8 where the CAPE managers are present, but I do not have a Cap Manager operational in 3.18.1

I see in device tree source:

P8_13_pinmux {
compatible = “bone-pinmux-helper”;
status = “okay”;
pinctrl-names = “default”, “gpio”, “gpio_pu”, “gpio_pd”, “pwm”;
pinctrl-0 = <0x5a>;
pinctrl-1 = <0x5b>;
pinctrl-2 = <0x5c>;
pinctrl-3 = <0x5d>;
pinctrl-4 = <0x5e>;
};

So I think I should use pinctrl-4 somehow to get PWM. I think 0x5e means therefore binary 01011110. But I think this means it is in mode 6 which is a not a valid mode. So I have got the wrong end of the stick here a bit and am misunderstanding something.

Also what else do I need to have to refer back to P8_13 and make that into a Device in /dev like the SPI pins? What is the pinmuxhelper and how can I use that? Should I be trying to use that?

Many thanks Mike.

Hi,

I am replying to my own E-mail. I amanaged to get PWM to work on 3.18.1-bone1. I used the code from:

https://github.com/SaadAhmad/beaglebone-black-cpp-PWM

and the information from:

http://hipstercircuits.com/enable-pwm-on-beaglebone-with-device-tree-overlays/

Both these sites have information for 3.8 kernels and assume you have a working Cape manager. For 3.18.1 there is no cape manager. A a Newbie to this here is what I did to get it to go. May not be a correct way, but I do see in /sys/kernel/debug/pwm

platform/48304200.ehrpwm, 2 PWM devices
pwm-0 ((null) ):
pwm-1 (PWM_P8_13 ): requested enabled

And on an Osilloscope the expected trace of a swuare wave that I can change the Mark-Space ratio on.

There are some newbie things worth nothing here that I did not know until I went through this:

  1. 3.8 Kernel Device Tree Overlays ==> change these to XXX.dtsi files (device tree include files) for 3.18.1-bone1. You can do this by hacking out the target, fragment etc. stuff. Note (it took be a while to realize this) DTC also does an OVERLAY with dtsi and dts files too, so it is not limited to just Capemgr overlays.

  2. You need to get a good control of the DTB generation of the kernel. Robert C . Nelson has this in his build_kernel.sh script.

As shown in this:

https://www.mail-archive.com/beagleboard@googlegroups.com/msg19714.html

you can break that out like this:

cpp -Wp,-MD,src/arm/.am335x-boneblack.dtb.d.pre.tmp -nostdinc -Iinclude -
Isrc/arm -Itestcase-data -undef -D__DTS__ -x assembler-with-cpp -o src/arm/.
am335x-boneblack.dtb.dts.tmp src/arm/am335x-boneblack.dts ; 

dtc -O dtb -o src/arm/am335x-boneblack.dtb -b 0 -i src/arm  -d src/arm/.
am335x-boneblack.dtb.d.dtc.tmp src/arm/.am335x-boneblack.dtb.dts.tmp ; 

cat src/arm/.am335x-boneblack.dtb.d.pre.tmp src/arm/.am335x-boneblack.dtb.d.
dtc.tmp > src/arm/.am335x-boneblack.dtb.d

3)   I found I had to edit the include dtsi files: am33xx.dtsi and 
am335x-bone-common-pinmux.dtsi to remove conflicts, some of which do not become
apparent before you load the kernel and look a dmesg upon boot.

4)   in the &am335x_pinmux bit. You can add pins with any name so long 
as you do not have a label that matches something else already there.

5)   in the &ocp bit, if you have more than one device driver, e.g. bone-pinmux-helper 
that tries to grab a pin as well as your driver, in my case pwm_test, P8_13 then the 
kernel module fails to load on boot, and dmesg shows errors. Fix this by commenting out
conflicts in the device tree files. (Not sure if this is the right way, but it worked
for me).

6)   You need to know a bit about your silicon. In the TI Sitara AM335x not 
all the components are switched on by default, you need to "turn on" in the device 
tree. So as well as configuring the pin, you need to turn on the EHRPWM and Clocks.
And make a note of which EHRPWM and which *channel* of the EHRPWM to use for the pin
that you want to use PWM on. For P8_13 that is EHRPWM2 Channel 1, sometimes called Channel B.

A= 0, B = 1.

Internally in the AM335x Ti Sitara, not all bits are connected to all pins, you you need
to know a bit about the silicon so that the right internal components 
are (1) Turned on and (2) connected up. (Note the AM335x manual is almost 5,000 pages!).

7)    Understanding what is in your device tree is important. I used the reverse dtb to
dts function in the DTC compiler alot. That way you can see if your edits / hacks in
all the dtsi and dts files had the desired effect.

8)   Egrep-ing in all the am33*.dts* files also helps a lot to see where all the names
and labels end up.

When I first looked at a full DTS file it looked like someone was randomly 
bashing a keyboard with something. I soon realized it was his head ... !!!

Hope this helps someone. Best, Mike.

Hi,

O.K. I have distilled it down to copy and paste. This should give you a PWM with 25% duty cycle at 10khz. The graph should look like the attached picture.

  1. include this dtsi file at the end of your XXX.dtb

&am33xx_pinmux {
pwm_P8_P13: pinmux_pwm_P8_P13_pins {
pinctrl-single,pins = <0x024 0xC>;
};
};

&ocp {
P8_13_pinmux {
status = “disabled”;
};

epwmss@48304000 {
status = “okay”;
ehrpwm@48304200 {
status = “okay”;
};
};

pwm_test_P8_13 {
compatible = “pwm_test”;
pwms = <&ehrpwm2 1 100000 1>;
pwm-names = “PWM_P8_13”;

pinctrl-names = “default”;
pinctrl-0 = <&pwm_P8_P13>;

enabled = <1>;
duty = <25000>;
status = “okay”;
};
};

  1. Compile the pwm_test.c into a pwm_test.ko by following instructions from:

https://github.com/SaadAhmad/beaglebone-black-cpp-PWM

and installing as a kernel module.

  1. You should get:

/sys/devices/ocp/ocp:pwm_test_P8_13# ls -l
total 0
lrwxrwxrwx 1 root root 0 Jan 4 19:09 driver → …/…/…/bus/platform/drivers/pwm_test
-rw-r–r-- 1 root root 4096 Jan 4 19:09 driver_override
-rw------- 1 root root 4096 Jan 4 19:09 duty
-r–r--r-- 1 root root 4096 Jan 4 19:09 modalias
-rw------- 1 root root 4096 Jan 4 19:09 period
-rw------- 1 root root 4096 Jan 4 19:09 polarity
drwxr-xr-x 2 root root 0 Jan 4 19:09 power
-rw------- 1 root root 4096 Jan 4 19:09 run
lrwxrwxrwx 1 root root 0 Jan 4 19:09 subsystem → …/…/…/bus/platform
-rw-r–r-- 1 root root 4096 Jan 4 18:56 uevent

And you can echo 10000 > duty

or

echo 100000 > period

To change the PWM.

Best, Mike.

hippo.png

Hi,

I am having some trouble trying to follow this, please will you elaborate on
the XXX.dtb, I am not sure how to create this file.

please also share your method for compiling pwm_test.c as I tried multiple time
with no success?

Thank you,

Graham