Wednesday, September 2, 2015

BBB: Kernel - Servo PWM support


Above figure is about servo control signal, period is about 20ms, adjust duration to set servo position. It can be controlled by BBB timers. BBB has 6 timers to output PWM signal. That means it can control 6 servos at same time. But default Kernel doesn't support 20ms period.
By default, Linux Kernel timer period can't be changed, it is hardcoded to be 500000. That is 500K ps = 0.5ms. To control servo,  period must set to about 20ms, so this value should be 20000000 = 20 ms. All servos shares this same period value.

You need to modify Kernel source code to set it. Another thing is, PWM timer is enabled by default, servo will start to work as soon as power is on. It is not expected behaviour. If you have 6 servos, all servos will consume current at same time, they move to initial positions together, it may break power supply. You need to modify pwm dts file to disable PWM output, then let application to enable it when necessary. 

pwm dts file looks like bone_pwm_P8(or 9)_xx-00A0.dts, they are located at kernel\kernel\firmware\capes\
For example, 
kernel\kernel\firmware\capes\bone_pwm_P9_31-00A0.dts

/*
 * 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_P9_31";
version = "00A0";

/* state the resources this cape uses */
exclusive-use =
/* the pin header uses */
"P9.31", /* pwm: ehrpwm0A */
/* the hardware IP uses */
"ehrpwm0A";

fragment@0 {
target = <&am33xx_pinmux>;
__overlay__ {
pwm_P9_31: pinmux_pwm_P9_31_pins {
pinctrl-single,pins = <0x190  0x1>; /* P9_31 (ZCZ ball A13) | MODE 1 */
};
};
};

fragment@1 {
target = <&ocp>;
__overlay__ {
pwm_test_P9_31 {
compatible = "pwm_test";
pwms = <&ehrpwm0 0 500000 1>;
pwm-names = "PWM_P9_31";
   pinctrl-names = "default";
   pinctrl-0 = <&pwm_P9_31>;
enabled = <1>;
duty = <0>;
status = "okay";
};
};
};
};


Modify:
pwms = <&ehrpwm0 0 500000 1>;
to
pwms = <&ehrpwm0 0 20000000 1>;

Modify:
enabled = <1>;
to
enabled = <0>;

Then compile kernel and update image file. DTS files are embedded into Kernel image.

You need to install pwm_test driver which enabled pwm for servo after boot.

insmod pwm_test.ko

Some PWM pins are shared with HDMI tx, to use these pins, disable HDMI tx by edit uEnv.txt file.

more /media/BEAGLEBONE/uEnv.txt
optargs=quiet drm.debug=7 capemgr.disable_partno=BB-BONELT-HDMI,BB-BONELT-HDMIN
capemgr.enable_partno=am33xx_pwm,bone_pwm_P9_31

Add following code in start-up script to enable all 6 PWM timers.

echo am33xx_pwm > /sys/devices/bone_capemgr.9/slots
echo bone_pwm_P9_31 > /sys/devices/bone_capemgr.9/slots
echo bone_pwm_P9_29 > /sys/devices/bone_capemgr.9/slots
echo bone_pwm_P8_36 > /sys/devices/bone_capemgr.9/slots
echo bone_pwm_P8_34 > /sys/devices/bone_capemgr.9/slots
echo bone_pwm_P8_45 > /sys/devices/bone_capemgr.9/slots
echo bone_pwm_P8_46 > /sys/devices/bone_capemgr.9/slots

For example to control PWM P9_31:
start PWM P9_31
echo 1 > /sys/devices/ocp.3/pwm_test_P9_31.12/run

set polarity of duty to be 0, must be 0
echo 0 > /sys/devices/ocp.3/pwm_test_P9_31.12/polarity

set duty to control servo position
echo 50000 > /sys/devices/ocp.3/pwm_test_P9_31.12/duty


No comments:

Post a Comment