BeagleBone Black, FreeBSD and PWMs


October 2013.
Two PWM output from a BeagleBone Black running FreeBSD The FreeBSD logo

Introduction


The BeagleBone black, using its AM335X CPU, provides a number of PWM output. Let's try to make them work.

Trying to find the device


dmesg indicates that the kernel found 3 PWM devices.

am335x_pwm0: mem 0x48300000-0x483000ff,0x48300100-0x4830017f,0x48300180-0x483001ff,0x48300200-0x4830025f irq 86,58 on simplebus0
am335x_pwm1: mem 0x48302000-0x483020ff,0x48302100-0x4830217f,0x48302180-0x483021ff,0x48302200-0x4830225f irq 87,59 on simplebus0
am335x_pwm2: mem 0x48304000-0x483040ff,0x48304100-0x4830417f,0x48304180-0x483041ff,0x48304200-0x4830425f irq 88,60 on simplebus0

devinfo and ofwdump confirm that the corresponding nodes exist.

# devinfo
nexus0
fdtbus0
simplebus0
aintc0
ti_scm0
am335x_prcm0
am335x_dmtimer0
gpio0
gpioc0
gpiobus0
uart0
ti_edma30
sdhci_ti0
mmc0
mmcsd0
sdhci_ti1
mmc1
mmcsd1
cpsw0
miibus0
smscphy0
iichb0
iicbus0
iic0
am335x_pmic0
am335x_pwm0
am335x_pwm1
am335x_pwm2
musbotg0
usbus0
uhub0
ustorage_fs0
usbus1
uhub1


# ofwdump -a
Node 0x38:
Node 0xc4: am335x
Node 0x124: interrupt-controller@48200000
Node 0x1b4: scm@44e10000
Node 0xb24: prcm@44E00000
Node 0xb88: dmtimers@44E05000
Node 0xc6c: gpio
Node 0xd14: serial@44E09000
Node 0xda8: serial@48022000
Node 0xe54: serial@48024000
Node 0xf00: serial@481a6000
Node 0xfac: serial@481a8000
Node 0x1058: serial@481aa000
Node 0x1104: edma3@49000000
Node 0x1188: mmchs0@48060000
Node 0x120c: mmchs1@481D8000
Node 0x12a4: ethernet@4A100000
Node 0x1340: mdio@0
Node 0x1388: ethernet-phy@0
Node 0x13c8: i2c@44e0b000
Node 0x1454: pmic@24
Node 0x1494: pwm@48300000
Node 0x1548: pwm@48302000
Node 0x15fc: pwm@48304000
Node 0x16b0: lcd@4830e000
Node 0x1738: usb@47400000
Node 0x1808: mbox0@480C8000
Node 0x1874: spinlock0@480CA000
Node 0x18c0: pruss@4A300000
Node 0x1944: aliases
Node 0x198c: memory
Node 0x19c4: chosen

# ofwdump -p /am335x/pwm@48300000
Node 0x1494: pwm@48300000
compatible:
74 69 2c 61 6d 33 33 35 78 2d 70 77 6d 00
'ti,am335x-pwm'
#address-cells:
00 00 00 01
#size-cells:
00 00 00 01
reg:
48 30 00 00 00 00 01 00 48 30 01 00 00 00 00 80 48 30 01 80
00 00 00 80 48 30 02 00 00 00 00 60
interrupts:
00 00 00 56 00 00 00 3a
interrupt-parent:
00 00 00 01
pwm-device-id:
00 00 00 00

Using the device


There doesn't seem to be much documentation on how to use these devices.

Reading the kernel indicates that the configuration is done using sysctl.


# sysctl -a | grep pwm
"Giant","am335x_pwm softc"
dev.am335x_pwm.0.%desc: AM335x PWM
dev.am335x_pwm.0.%driver: am335x_pwm
dev.am335x_pwm.0.%parent: simplebus0
dev.am335x_pwm.0.period: 1000
dev.am335x_pwm.0.dutyA: 0
dev.am335x_pwm.0.dutyB: 0
dev.am335x_pwm.1.%desc: AM335x PWM
dev.am335x_pwm.1.%driver: am335x_pwm
dev.am335x_pwm.1.%parent: simplebus0
dev.am335x_pwm.1.period: 1000
dev.am335x_pwm.1.dutyA: 0
dev.am335x_pwm.1.dutyB: 0
dev.am335x_pwm.2.%desc: AM335x PWM
dev.am335x_pwm.2.%driver: am335x_pwm
dev.am335x_pwm.2.%parent: simplebus0
dev.am335x_pwm.2.period: 1000
dev.am335x_pwm.2.dutyA: 0
dev.am335x_pwm.2.dutyB: 0

Jackpot! Let's try settings some values in these registers.


# sysctl dev.am335x_pwm.0.period=100
# sysctl dev.am335x_pwm.0.dutyA=50
# sysctl dev.am335x_pwm.0.dutyB=75
# sysctl dev.am335x_pwm.1.period=1000
# sysctl dev.am335x_pwm.1.dutyA=500
# sysctl dev.am335x_pwm.1.dutyB=50
# sysctl dev.am335x_pwm.2.period=250
# sysctl dev.am335x_pwm.2.dutyA=50
# sysctl dev.am335x_pwm.2.dutyB=150

That's it. Probing the pins confirms that the PWM work.

Pin mapping and muxing








DevicePin
sysctl dev.am335x_pwm.1.dutyAP9.14 (ehrpwm1A)
sysctl dev.am335x_pwm.1.dutyBP9.16 (ehrpwm1B)
sysctl dev.am335x_pwm.2.dutyAP8.19 (ehrpwm2A)
sysctl dev.am335x_pwm.2.dutyBP8.13 (ehrpwm2B)


ehrpwm0 is not muxed in the device tree file, so it's not accessible.

Reference and relevant information