Enable PWM on BeagleBone with Device Tree overlays

device_tree_pwmIn order to enable peripherals (spi/i2c/pwm/adc) for BeagleBone that is running Linux kernel > 3.6, you need to understand device tree overlays. This post deals with adding PWM support to the Replicape. In total the Replicape has three high power MOSFETs that are controlled directly from the BeagleBone. The instructions assume you have a system set up for compiling the Linux kernel. If you do not, have a look at this post.

This was all done with the latest version of Robert Nelsons wonderful repository of patches for BegleBone etc.

The Device Tree overlays are for enabling devices, muxing the pins and connecting them with device drivers.

Mux the pins right
To mux the pins for the PWMs, the pins must be specified. The target to overlay is am33xx_pinmux. This is compatible with the driver “KERNEL/drivers/pinctrl/pinctrl-single”:

fragment@0 {
		target = <&am33xx_pinmux>;
		__overlay__ {
			pwm_mosfet_ext1_pins: pinmux_pwm_mosfet_ext1_pins {
				pinctrl-single,pins = < 					0x024  0x4		/* gpmc_ad9  = ehrpwm2B = P8_13 = Heater_ext1 | MODE 4 */ 				>;
			};						
			pwm_mosfet_ext2_pins: pinmux_pwm_mosfet_ext2_pins {
				pinctrl-single,pins = < 					0x020  0x4      /* gpmc_ad8  = ehrpwm2A = P8_19 = Heater_ext2 | MODE 4 */ 				>;
			};						
			pwm_mosfet_hbp_pins: pinmux_pwm_mosfet_hbp_pins {
				pinctrl-single,pins = < 					0x150  0x3		/* spi0_sclk = ehrpwm0A = P9_14 = Heater_HBP  | MODE 3 */ 				>;
			};										
		};
	};

The two arguments that go in pinctrl-single, pins is the address in memory for the pin and the mux mode.
The address is relative to the base address of the pin gpmc_ad0.
The base address which is 0x44e10800. So 0×20 becomes 0x44e10800 + 0×20 = 44e10820.
To view the pins, do a:

cat /sys/kernel/debug/pinctrl/44e10800.pinmux/pins

Page 754 in am335x technical reference manual lists the different pins:

Enable the device (PWM)
To enable a device in the device tree using overlays, you need to override the “status” field for the device. So to enable the ehrpwm0 and ehrpwm2 devices, we set the status to “okay”. The pwmss (pulse width modulation sub system) needs to enabled as well:

	fragment@2 {
		target = <&epwmss2>;
		__overlay__ {
			status = "okay";
		};
	};

	fragment@3 {
		target = <&ehrpwm2>;
		__overlay__ {			
			status = "okay";			
		};
	};

	fragment@4 {
		target = <&epwmss0>;
		__overlay__ {
			status = "okay";
		};
	};

	fragment@5 {
		target = <&ehrpwm0>;
		__overlay__ {			
			status = "okay";			
		};
	};

The “target” here matches the device in the file “KERNEL/arch/arm/boot/dts/am33xx.dtsi”.
If you want to use these drivers through their standard interface, which means flicking registers directly, you can specify the pins directly in these nodes. If you do not, you will see some error messages in dmesg saying “ehrpwm 48304200.ehrpwm: unable to select pin group”
and such and such.

Connect the device to a user interface driver
If you want to test the PWM from command line, you must connect it to a user interface driver.
To connect the device with a user interface, specify the “compatible” field in the “ocp” section. ocp stand for On Chip Peripherals, BTW. The compatible field should match the driver you want to use. At the time of this writing, the only driver that I got working was the backlight driver. This however is not very useful for other intents since it connects with any display you my have connected. There was a start of a device interface called “pwm_test”, but it did not work very well..

Therefore I had to fix it. The patch has not been sent in yet, but hopefully it will soon. Meanwhile, here is the file:pwm_test.c

Put this in the folder “KERNEL/drivers/pwm/pwm_test.c”.

fragment@6 {
		target = <&ocp>;
		__overlay__ {			
			#address-cells = ;
			#size-cells = ;

			mosfet_ext1 {
				compatible      = "pwm_test";
				pinctrl-names   = "default";
				pinctrl-0       = <&pwm_mosfet_ext1_pins>;
				pwms 			= <&ehrpwm2 1 500000 1>;
				pwm-names 		= "Mosfet_Ext_1";
				enabled			= <1>;
				duty			= <0>;
				status 			= "okay";
			};
			mosfet_ext2 {
				compatible      = "pwm_test";
				pinctrl-names   = "default";
				pinctrl-0       = <&pwm_mosfet_ext2_pins>;
				pwms 			= <&ehrpwm2 0 500000 1>;
				pwm-names 		= "Mosfet_Ext_2";
				enabled			= <1>;
				duty			= <0>;
				status 			= "okay";
			};
			mosfet_hbp {
				compatible      = "pwm_test";
				pinctrl-names   = "default";
				pinctrl-0       = <&pwm_mosfet_hbp_pins>;
				pwms 			= <&ehrpwm0 0 500000 1>;
				pwm-names 		= "Mosfet_HBP";
				enabled			= <1>;
				duty			= <0>;
				status 			= "okay";
			};
		};

This might seem a bit random at first. Where are the fields and values coming from? This has not been very well documented yet so the best thing to do is to use the force. I mean use the source. The field “compatible” is what ties this device to the driver. This field can be found again in the driver source. The “pinctrl-0″ links to the pins that should be muxed for this device. In the case of a PWM, it is one pin or each and they are specifed in fragment 0. the “pwms” field specifies which pwm-driver should be tied in. The three next arguments are channel (0 or 1), period in nanoseconds and polarity (Normally high/normally low). The “pwm-names” is a friendly name that shows up in the sysfs tree. (Do a “find /sys -name *pwm*” to see pwm related stuff. ). The fields enabled and duty are made by me and specifies whether the device should be running on boot  (<0> or <1>) and what the duty in nanoseconds should be (0-500000).

Testing that it is working
Once you have booted up, the debug file system will tell you the info you need about the PWMs:

cat /sys/kernel/debug/pwm

To check that all the pins are muxed right, cat the pinctrl device:

cat /sys/kernel/debug/pinctrl/44e10800.pinmux/pins

If you want to see the period, duty, state(enabled/disabled), free/requested etc. of a device, just cat the files in the folder:

cat /sys/devices/ocp.2/mosfet_ext1.12/* 2>/dev/null

To set duty to 50% (period is 500000):

echo 250000 > /sys/devices/ocp.2/mosfet_ext1.12/duty

Note that this driver is very basic. It has little error checking and not a very fancy user interface, but okay for programming against. Remember that the duty (in nanoseconds) must be less than the period. Also remember that the polarity can only be changed when the device is not running.

Further reading
The file KERNEL/Documentation/devicetree/overlay-notes.txt is good for getting a basic understanding of how overlays work. Also, the other files in the “devicetree” folder are useful:
usage-model
dynamic-resolution-notes
dt-object-internal

If you want to be safe, stick to the 3.2-branch of the Linux Kernel. If you want to be ripping your hair out for no particular reason other than getting something that wasn’t working top work, go for the 3.8-branch.

36 thoughts on “Enable PWM on BeagleBone with Device Tree overlays

  1. Pingback: Enable SPI 1.0 and 1.1 with device tre overlays on BeagleBone | Hipstercircuits

  2. Okay, I can follow that guide. Question though – since the capes generally come with eeproms in them to tell the beaglebone when a particular cape is installed, how do you instantiate an eepromless cape?

  3. Nathaniel, If you do not have a cape, but want to hard code a device tree overlay, I suggest you look in the file
    KERNEL/arch/arm/boot/dts/am335x-bone-common.dtsi
    Above the node “capemaps” you will see “slots” where you can specify different cape configurations. I must say that I have not tried this, but it says to be compatible with “kernel-command-line” and “runtime”. I would guess this means that you can either load it from command line or somehow “probe” the firmware after boot.

    • Found the answer. If you have a cape that does not have an eeprom (so no auto detect), you add a cape entry like any other cape to tell what device tree overlay to use, its name, and its version. The you add a slot entry like the geiger cape and nixie cape. To get the cape to load, edit the kernel boot parameters in your uEnv.txt. Add a parameter like “capemgr.extra_override=BB-BONE-GEIGER:00A0″

  4. I’m getting the select pin group error in Ubuntu? Could you elaborate a bit more on what you mean by standard interface and nodes?

    • If you are getting that error in dmesg, it might still be ok. What it means is that the data you have supplied for the “probe” function, does not have a pingroup. Since we are supplying the pingroup later on in the ocp overlay, it should be ok. Why do you want to know?

  5. hi Elias:
    I do some pwm test on my beaglebone board. I copy the bone-pwm-p8_19_00A0.dts, and named bone-pwm-p8_19_00A1.dts. I follow your instructions (overlay epwmss2 and ehrpwm2 both). however, i failed to eable my new dtbo to the device tree. There are error messages in dmesg saying “ehrpwm 48304200.ehrpwm: unable to select pin group”. Can you help me?

    btw (my kernel version is 3.8.13-bone24.4 )

    thanks a lot!

    • “Unable to select pin group” is not necessarily an error, just a warning. However, look in the folder /lib/firmware. There should be pre-compiled overlay files for all the PWMs. Also, if you have specific revision of the DTO, make sure you specify that on the command line:
      “:00A1″

      • Thanks for you quick reply. :)
        I echo the right DTBO version to the device tree.
        But i can’t find anything about (duty, freq file ) under /sys/devices/ocp.2/pwm_test_p8_19/ and when I unload the DTBO , it cases something crashed.

        i’ll paste my dts file , would you take a look? thanks a lot!

      • /*
        * Copyright (C) 2013 CircuitCo
        * Copyright (C) 2013 Texas Instruments
        *
        * This program is free software; you can redistribute it and/or modify
        * it under the terms of the GNU General Public License version 2 as
        * published by the Free Software Foundation.
        */
        /dts-v1/;
        /plugin/;

        / {
        compatible = “ti,beaglebone”, “ti,beaglebone-black”;

        /* identification */
        part-number = “bone_pwm_P8_19″;
        version = “00A1″;

        /* state the resources this cape uses */
        exclusive-use =
        /* the pin header uses */
        “P8.19″, /* pwm: ehrpwm2A */
        /* the hardware IP uses */
        “ehrpwm2A”;

        fragment@0 {
        target = ;
        __overlay__ {
        pwm_P8_19: pinmux_pwm_P8_19_pins {
        pinctrl-single,pins = ; /* P8_19 (ZCZ ball U10) | MODE 4 */
        };
        };
        };

        fragment@1 {
        target = ;
        __overlay__ {
        status = “okay”;
        };
        };

        fragment@2 {
        target = ;
        __overlay__ {
        status = “okay”;
        };
        };

        fragment@3 {
        target = ;
        __overlay__ {
        pwm_test_P8_19 {
        compatible = “pwm_test”;
        pinctrl-names = “default”;
        pinctrl-0 = ;
        pwms = ;
        pwm-names = “PWM_P8_19″;
        enabled = ;
        duty = ;
        status = “okay”;
        };
        };
        };
        };

      • I’ve just typed “dmesg” and it printed a very long list. Where to check?
        And what is this:
        # cat /sys/devices/bone_capemgr*/slots
        0: 54:PF—
        1: 55:PF—
        2: 56:PF—
        3: 57:PF—
        4: ff:P-O-L Bone-LT-eMMC-2G,00A0,Texas Instrument,BB-BONE-EMMC-2G
        5: ff:P-O-L Bone-Black-HDMI,00A0,Texas Instrument,BB-BONELT-HDMI
        7: ff:P-O-L Override Board Name,00A0,Override Manuf,am33xx_pwm
        8: ff:P-O-L Override Board Name,00A0,Override Manuf,bone_pwm_P8_13
        9: ff:P-O-L Override Board Name,00A0,Override Manuf,bone_pwm_P9_21
        10: ff:P-O-L Override Board Name,00A0,Override Manuf,bone_pwm_P9_42
        11: ff:P-O-L Override Board Name,00A0,Override Manuf,bone_pwm_P9_14

        Can you show me how to disable the conflict?

  6. Pingback: การใช้ GPIO ใน Linux ของ BeagleBone Black | BeagleBone Lover in Thailand

  7. About the PWM_test.c file, do we have to compile it (ie copy it in the KERNEL/drivers/pwm/pwm_test.c and rebuild the kernel). Or we just put the file in the beaglebone (KERNEL/drivers/pwm/ of beaglebone) directly?

  8. Hello,

    we are currently working on a Beaglebone Black project and we are having problems with our device tree overlays. In our project we continued another groups work but they worked with a Beaglebone White and with an older kernel version where sys/kernel/debug/omap_mux was still there. We tried to create the same functionality with device trees. we got several sensors on a self made cape running and we need to set the pinmodes correctly for the cape.

    (for reference our new dts file: http://pastebin.com/MD0LzHqX
    and the old script: http://pastebin.com/QUX7in4j)

    Compiling and activating our overlay works fine. (we also disabled the hdmi framer and other unused capes)
    But when we manually check the pinmux setting for the pins (cat /sys/kernel/debug/pinctrl/44e10800.pinmux/pins) nothing changed and the pinmodes from the dts aren’t set.

    Why can’t we set the pinmodes via our dts file?

    • If I understand you correctly, you want to mux the direction of the pins the DTS? If that is the case, it might be difficult, by design. I did make some changes to the PRU driver once to enable direction muxing and I think that made it into the kernel. Search older posts to see what you can find on PRU and pin muxing.

  9. I am working on BeagleBone Black and having problem with PWM.
    I am trying to use P8_13 and p8_19, I have enable both and when i am tryng to change the period i get the following error :
    root@BBB:/sys/devices/ocp.2/pwm_test_P8_19.11# echo 10000000 > period
    [ 1406.652632] ehrpwm 48304200.ehrpwm: Period value conflicts with channel 1
    [ 1406.660047] pwm_test pwm_test_P8_19.11: pwm_config() failed
    -sh: echo: write error: Invalid argument

    If i do only one PWM i.e either P8_13 or P8_19 alone then the changes happens but fails on enabling the second.

    Can anyone help me to fix this issue.

  10. Hi
    root@beaglebone:/lib/firmware/#echo BB-GPIOHELP >$SLOTS

    trying to activate GPIO overlay..but getting an error
    ” -sh: echo:write error: file exists ”
    I “dmesg” then it is saying conflict with “HDMI”…but dont know how to go ahead and activate this overlay for using GPIO. and also i want to add new GPIOs and change their mode to MODE 7…can i edit this file and add GPIO offsets and mode value..in the “BB-GPIOHELP-00A0.dts” file.
    Can any one knows how to solve this problem.

    • Hi! There are two overlays for the HDMI, one with audio and one without. If you disable the one with audio, the one without audio will be loaded instead. They are called BB-BONELT-HDMI and BB-BONELT-HDMIN, so just disable BB-BONELT-HDMI or both of you need those pins. You can disable them by adding a parameter on the kernel command line. capemgr.disable_partno=BB-BONELT-HDMI

  11. Pingback: PWM activation on Beaglebone | misrapankaj

  12. hello ,are you know how to look up the the max and min vaule of the PWM? or I may set the value that the bbb allow the max and min value?

  13. Pingback: can spi search results | misrapankaj

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>