BeagleBone AI-64 + Servo cape

We recently added Servo Cape Device Tree Overlay for BeagleBone AI-64 and this post will be more like a detailed overview of how to use servo cape with BeagleBone AI-64.

Make sure your system is up to date,

debian@BeagleBone:~$ sudo apt update
debian@BeagleBone:~$ sudo apt upgrade

You can follow the link below for more information on updating BeagleBone AI-64 software

It’s very likely that by the time you read this post the overlay is already available on you board but, in case it’s now you can get the new device tree overlay from v5.10.x-ti-unified branch of BeagleBoard-DeviceTrees repository and install it on your board,

debian@BeagleBone:~$ cd 
debian@BeagleBone:~$ git clone
debian@BeagleBone:~$ cd BeagleBoard-DeviceTrees
debian@BeagleBone:~/BeagleBoard-DeviceTrees$ git branch
* v5.10.x-ti-unified
debian@BeagleBone:~/BeagleBoard-DeviceTrees$ make
debian@BeagleBone:~/BeagleBoard-DeviceTrees$ sudo make install_arm64

After confirming the overlay is in place, update the extlinux.conf to load it,

debian@BeagleBone:~$ ls /boot/firmware/overlays/ | grep SERVO

debian@BeagleBone:~$ sudo nano /boot/firmware/extlinux/extlinux.conf

After this the nano text editor will open the extlinux.conf file and now you have to add the fdtoverlays /overlays/BBORG_SERVO-00A2.dtbo line as shown below,

label Linux microSD
    kernel /Image
    append console=ttyS2,115200n8 earlycon=ns16550a,mmio32,0x02800000 root=/dev/mmcblk1p2 ro rootfstype=ext4 rootwait net.ifnames=0 quiet
    fdtdir /
    fdtoverlays /overlays/BBORG_SERVO-00A2.dtbo
    initrd /initrd.img

Reboot the system and make sure the overlay is loaded correctly,

debian@BeagleBone:~$ sudo reboot

debian@BeagleBone:~$ sudo beagle-version | grep UBOOT
UBOOT: Booted Device-Tree:[k3-j721e-beagleboneai64.dts]
UBOOT: Loaded Overlay:[BBORG_SERVO-00A2]

debian@BeagleBone:~$ ls /proc/device-tree/chosen/overlays/
BBORG_SERVO-00A2  name

The servo cape uses PCA9685 PWM chip which is connected to i2c2 and on BeagleBone Ai-64 we have total 7 i2c buses. The bus number for i2c2 is 5.

debian@BeagleBone:~$ dmesg | grep i2c
[    0.912845] i2c /dev entries driver
[    1.009396] omap_i2c 40b00000.i2c: bus 0 rev0.12 at 100 kHz
[    1.009837] omap_i2c 40b10000.i2c: bus 1 rev0.12 at 100 kHz
[    1.031383] omap_i2c 42120000.i2c: bus 2 rev0.12 at 400 kHz
[    1.031967] omap_i2c 2000000.i2c: bus 3 rev0.12 at 400 kHz
[    1.033025] omap_i2c 2010000.i2c: bus 4 rev0.12 at 400 kHz
[    1.057095] omap_i2c 2020000.i2c: bus 5 rev0.12 at 100 kHz
[    1.057679] omap_i2c 2030000.i2c: bus 6 rev0.12 at 400 kHz
[    1.058172] omap_i2c 2050000.i2c: bus 7 rev0.12 at 400 kHz

Fun fact: The i2c2 bus number (5) is different from i2c number (2) because mcu_i2c and wkup_i2c are initialized before main_i2c. The table below should explain it better,

Bus0 - Bus1 = mcu_i2c
Bus2 = wkup_i2c
Bus3 - Bus7 = main_i2c

With all the information above you know that the bus number is 5 for our device. Now let’s see if we have something on that bus at 0x70 which is the address of PCA9685.

debian@BeagleBone:~$ sudo i2cdetect -y -r 5
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:                         -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- 54 -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: UU -- -- -- -- -- -- -- 

We indeed have a device at 0x70 and it seems it’s being used by the driver. Let’s check that,

debian@BeagleBone:~$ ls /sys/bus/i2c/drivers/pca9685-pwm
5-0070  bind  uevent  unbind

Now you are all set to control servos with your servo cape but, before going further you may want go through this piece of code from beagle-tester repository to get an idea of what we are doing to control the servos.

By default we have two PWMs exported already i.e pwm0 & pwm1,

debian@BeagleBone:~$ ls /sys/bus/i2c/drivers/pca9685-pwm/5-0070/pwm/pwmchip0
device  export  npwm  power  pwm0  pwm1  subsystem  uevent  unexport

If you want to export 3rd PWM or any other PWM out of 16 available you can use the command below,

debian@BeagleBone:~$ echo 2 > /sys/bus/i2c/drivers/pca9685-pwm/5-0070/pwm/pwmchip*/export

debian@BeagleBone:~$ ls /sys/bus/i2c/drivers/pca9685-pwm/5-0070/pwm/pwmchip0
device  export  npwm  power  pwm0  pwm1  pwm2  subsystem  uevent  unexport

Now connect your servo to S1 header pin location on cape and supply 5V via terminal block for the servo. Follow the PWM configuration bits and you should see your servo moving.

Set pwm0 period to 100Hz (10ms)

debian@BeagleBone:~$ echo 10000000 > /sys/bus/i2c/drivers/pca9685-pwm/5-0070/pwm/pwmchip0/pwm0/period

Set pwm0 duty cycles to 1ms

debian@BeagleBone:~$ echo 1000000 > /sys/bus/i2c/drivers/pca9685-pwm/5-0070/pwm/pwmchip0/pwm0/duty_cycle

Enable pwm0 PWM output

debian@BeagleBone:~$ echo 1 > /sys/bus/i2c/drivers/pca9685-pwm/5-0070/pwm/pwmchip0/pwm0/enable

Set pwm0 duty cycles to 2ms

debian@BeagleBone:~$ echo 2000000 > /sys/bus/i2c/drivers/pca9685-pwm/5-0070/pwm/pwmchip0/pwm0/duty_cycle

Set pwm0 duty cycles to 1ms

debian@BeagleBone:~$ echo 1000000 > /sys/bus/i2c/drivers/pca9685-pwm/5-0070/pwm/pwmchip0/pwm0/duty_cycle

Disable pwm0 PWM output

debian@BeagleBone:~$ echo 0 > /sys/bus/i2c/drivers/pca9685-pwm/5-0070/pwm/pwmchip0/pwm0/enable

Congratilation if you got your servo moving. Let me know if you found any issue with the instruction above.

1 Like

To simplify the testing process you can also use the script below.

Create file to store the code,

debian@BeagleBone:~$ cd
debian@BeagleBone:~$ touch
debian@BeagleBone:~$ nano

Now paste the code below in the nano editor that just opened,


function disable {
        echo 0 > $servo1/enable

function enable {
        echo 1 > $servo1/enable

echo "Servo attached to S1 must be running now..."

echo 10000000 > $servo1/period
echo 1000000 > $servo1/duty_cycle

sleep 1
echo 2000000 > $servo1/duty_cycle
sleep 1
echo 1000000 > $servo1/duty_cycle
sleep 1
echo 2000000 > $servo1/duty_cycle
sleep 1
echo 1000000 > $servo1/duty_cycle

Now make the script executable and execute it to move the servo.

debian@BeagleBone:~$ chmod +x
debian@BeagleBone:~$ ./ 
Servo attached to S1 must be running now...

Your servo on S1 header pin location should be moving now…

1 Like

A post was split to a new topic: BBAI64: GPIO numbers

Hi @lorforlinux - thank you very much for putting this together. I have a recently purchased BBAI64 and the servo cape. Followed these instructions but am not seeing servo movement. Some of the main differences between my setup and the one you documented is that I’m running off the eMMC, not a microSD and when I do dmesg | grep i2c, I get two additional messages:

  1. gb_i2c: module is from the staging directory, the quality is unknown , you have been warned.
  2. gb_gbphy: registered new driver i2c

But I do see that I have a device at 0x70 and tried moving the servo between S1 and S2 and ran the test commands on the appropriate pin# to see if I would get movement from either position. Do you have any troubleshooting tips I can use? And what other board information would be useful for me to post?

Hey @eileen, Sorry for the trouble. I will test everything again with the latest linux image and let you know if any fix is required to make it to work.

Hi @lorforlinux , I followed this tutorial but I also didn’t get a movement from the servo. Were you able to test this again with the latest linux image?

Hi @eileen did you find a solution to this?

Thank you!