Beaglebone Outputs (pwm): To everything – Turn, turn, turn – there is a season

Andrew B. Wright, Ph. D., SM ’88


Previous Post: Beaglebone Inputs (analog): Too many hands on my time, too many feelings, too many things on my mind

Next Post: Beaglebone: A novel encoder interface for measuring speed

I’m using the pwm with the pololu motor controller, 1213.  These controllers can source a steady 3A and peak current of 5A.

The motor I’m using is the Vex EDR 393 motor.  This motor uses steel gears and has a number of different gear ratios.  In the factory shipped option, the motor has 100 rpm no load speed, 1.67 N-m stall torque, a stall current of 4.8 A and a no load current of 0.37 A.  The supply voltage is 7.2 volts.

This is a pretty beefy motor for small robotics applications.  I plan to use 4 motors in the drive system.  This robot can supply 4 x 7.2 v x 3 A = 86 W of power.

On the downside, I discovered that it does not respond to a pwm frequency above 1000 Hz.  This leads to a 1000 Hz tone being broadcast while the motors are at idle.

The 393 seems to be very similar to pololu’s medium power 100 rpm motor, and I may pursue a motor like this in the future once I engage in a significant mechanical revision of the CASSY.

There is also a table of parts on my battery pack page.  I think I should link there.  Since this is all “work in progress,”  it may be a while before I integrate these two activities.

I have another, older list on my “Tutorial introduction” page.

SupplierPart NumberQuantity
Voltage regulatormouserPTN78020WAH2
Controller Switchmouser107-1261B1
Power Switchmouser1241.6831.11200001
8.2k ResistormouserMFR50SFTE52-8K21
ceramic 2.2 uF CapacitormouserFG22X7R1E226MRT061
electrolytic 330 uF Capacitormouser337TTA016M1
rechargeable AA batteriesmouserlots
10 amp automotive fusemouserBK/ATC-102
pololu motor controllerpololu12132
vex 2-wire motor, 393vexrobotics3934

fuse holder contactmouser4
Need to add toolswire wrap tool1

PWM registers

The CM_PER register (0x44E0 0000) contains three important registers: epwmss0clkctrl (0xD4), epwmss1clkctrl (0xcc), epwmss2clkctrl (0xD8) which have to be enabled in order for the PRU to write to the pwm registers.

Bit 8 of the CLKCONFIG register (ePWMCLK_EN = 1) enables the clock. (This should be set by the OS on start up.  I believe it can only be accessed by the ARM.)

Do NOT use CLKCONFIG (ePWMCLK_EN) to try to turn the PWM on/off.  Once that clock is turned off, it cannot be turned back on from within the PRU.

In turning the PWM off, it’s nice to also force the module to go low.  This can be done through the ACQTLA/B register.

Another register that has an interesting module is CONTROL_MODULE (0x44E1 0000).  This register has pwmss_ctrl (0x664), which has the bits timebase_clock_enable for pwm 0, 1, 2.  I have not checked it out yet, but it could be a necessary register.

Set bits 15, 14 of TBCTL (FREE_SOFT) to 2h to allow free running of the PWM.

Set bits 5, 4 of TBCTL (SYNCOSEL) to 3h to disable EPWMxSYNCO signal.

Set bits 12-10 of TBCTL (CLKDIV) to 2h to make the prescaler = 4:1. Set bits 9-7 (HSPCLKDIV) to 0 to set the high speed prescaler to 1.  This makes TBCLK = SYSCLKOUT/CLKDIV/HSPCLKDIV.  If SYSCLKOUT = 100MHz, TBCLK = 25 MHz.

Set the other bits to zero (PHSDIR =0, SWFSYNC=0h, PRDLD=0h, PHSEN=0h, CTRMODE=0h). Among other things, these choices set the counter-mode to ‘up-count.’

Set TBPRD = 0xnn.  This is the frequency of the PWM.  It interacts with TBCLK, such that PWMPERIOD = (TBPRD+1)/TBCLK.  If nn = 99, then PWMPERIOD = 100/25 MHz = 4 usec. (confirmed)

The CMPA register is compared against TBCNT register and actions taken based on AQCTLA register.  Setting AQCTLA (CAU=3h,PRD=0h, ZRO=2h) in count-up mode will give a traditional PWM signal.

Duty cycle varies between 0 and TBPRD+1 (100%). (confirmed)

There are many, many other things that the ePWM module can do.  This gives the basic operation, which may be all you need.

For mechanical systems, I’ve always liked a 100 kHz frequency.  This puts changes in PWM above most mechanical poles and above hearing frequency, so that PWM switches cannot be heard.  This can be obtained by a prescaler value of 1000 and a TBPRD value of 0.  However, that would give a resolution of the PWM of 1 bit (on-or-off).  Using typical DAC values (powers of 2), TBPRD = 1023 would give a 10 bit resolution.  So, a prescaler of 1 and TBPRD of 1023 would give about 100kHz PWM frequency and allow CMPA to vary between 0 and 1023 (10 bit resolution).

The Vex motors that I have chosen for my project have a filter in the input section which limits the pwm frequency to below 1000 Hz.  I’m not sure why vexrobotics made this decision.

Insert section talking about the actual values of TBPRD, etc.

Chapter 15 of the AM33x TRM contains the description of the Pulse Width Modulation Sub-system (PWMSS).

Table 15-4 indicates some of the registers involved with the PWM: IDVER, SYSCONFIG, CLKCONFIG, CLKSTATUS.


Figure 15-9 gives a good overview of the ePWM submodules (time base [TB], counter compare [CC], action qualifier [AQ], Dead Band [DB], Chopper [PC],  Trip Zone [TZ]), and Event Trigger [ET]).  The CC module sets frequency and duty cycle, while the others can be bypassed unless their functionality is needed.

Base address is (Table 2-3): ePWM0 (0x4830_0200), ePWM1 (0x4830_2200), ePWM2 (0x4830_4200).

Table 15-57 summarizes all the functions and offsets.

In the Time Base module, TBCTL (0), TBSTS (2), TBPHSHR (4), TBPHS(6), TBCNT (8), TBPRD (A) are the registers controlling the time base.

In the Counter Compare module, CMPCTL (E), CMPAHR(10), CMPA (12), CMPB (14) affect operation.

In the Action Qualifier module, AQCTLA (16), AQCTLB (18), AQSFRC (1A), AQCSFRC (1C) affect operation.

In the Deadband module, DBCTL (1E), DBRED (20), DBFED (22) affect operation.

In the Chopper, PCCTL (3C).

In the Trip Zone, TZSEL (24), TZCTL (28), TZEINT (2A), TZFLG (2C), TZCLR (2E), TZFRC (30).

In the Event Trigger, ETSEL (32), ETPS (34), ETFLG (36), ETCLR (38), ETFRC (3A), affects how interrupts are fired from PWM.

The constant table on the PRU allows access to the PWMs.  C18, C19, C20 point to PWM0, PWM1, PWM2.

From Table 9-10 in the TRM, it can be seen that 44e10820 carries the signal, conf_gpmc_ad8 .  On Table 4-1 of the AM3358 data sheet, gpmc ad8 contains the signals: gpmc_ad8 (0), lcd_data23 (1), mmc1_dat0 (2), mmc2_dat4 (3), ehrpwm2A (4), pr1_mii_mt0_clk(5), gpio0_22 (7). From the Beaglebone SRM, Table 12, Expansion Header P8 pinout, gpmc ad8 is carried on pin 19.  Whew!  That’s how you find all those modes and addresses.

Table 4-3 of the TRM has a PRU-ICSS pin list.  That’s useful if you’re trying to find out what pins might carry what functions.

Table 4-21 has PRU system events. Relevant to the epwm/ecap

Int Number Signal Name Source
46 epwm_intr_intr_pend eHRPWM1
43 epwm_intr_intr_pend eHRPWM0
42 ecap_intr_intr_pend eCAP0
37 epwm_intr_intr_pend eHRPWM2
36 ecap_intr_intr_pend eCAP2
35 ecap_intr_intr_pend eCAP1
15 pr1_ecap_intr_req PRU-ICSS eCAP

There are entries in constant table for PWM.

Entry Number Region pointed to Value
3 PRU-ICSS eCAP 0x00030000
4 PRU-ICSS ePWM 0x00026000
18 eHRPWM1/eCAP1/eQEP1 0x48300000
19 eHRPWM2/eCAP2/eQEP2 0x48302000
20 eHRPWM3/eCAP3/eQEP3 0x48304000


Table 15-57 gives the registers in the ePWM module.  There are lots.


This is where I am right now.  I’ve switched to putting together the battery pack, voltage regulator, and pwm driver.  When I have that, I’ll complete the full code for turning a pwm.  For now, this code does generate the pwm signal.  But, I haven’t done all the enable signals.  The last time I got to this point, I fried my beaglebone.  So, this is a back-up in case I repeat that step.

The archive

Place this in /root/code and unpack it.  It will create a directory /root/code/pwm.  The executable is pwm, and it will set a pwm signal on all three modules and both channels (total of six pwms).

This does not use the pwms attached to the PRU.  Right now, I only need four pwms (1 per motor x 4 motors).  The other two channels could be used for a manipulator.  If that won’t get ‘r done, then the PRU pwms (2 more, I think) can be added.

Battery Pack and Voltage Regulator

In order to turn a motor, some electrical engineering needs to be completed.


ARM access to pwm

The ARM part of the system, the bit running Linux, is the easiest way to get started with PWM.  You need to reserve the header pin using the config-pin to write to the pad control registers and mux the pwm to the output pin on the P9 header.

There are several pins connected to each of the six PWM output signals (PWM0A, PWM0B, PWM1A, PWM1B, PWM2A, PWM2B).  Setting the PWM banging away will put a signal on each pin to which it is connected, assuming the mux for that pin has been set to connect the pin to the PWM module.  So, make sure you only mux those pins that you want to be active.

BBK Header Pin PWM signal Other signals
P9 – 21 0B spi, uart, i2c, pwm, pru_uart
P9 – 22 0A gpio?
P9 – 14 1A gpio?
P9 – 16 1B gpio?
P9 – 28 ECAPPWM2 gpio?
P9 – 42 ECAPPWM0 gpio?
P8 – 19 2A gpio?
P8 – 13 2B (mode 4) gpmc_ad9, lcd_data22, mmc1_dat1, mmc2_dat5, pr1_miii0_col, gpio0_23
P9-29 unavailable gpio, R30:0, HDMI
P9-31 unavailable gpio, R30:1, HDMI
P8 x gpio?

This gives all the 8 PWMs that are available on the Beaglebone Black.  NOTE:  it seems that ECAPPWM are not the same as what’s in the PWMSS.  I have not experimented with setting these channels up.

P9-21, P9-22

Use config-pin to set P9-21 and P9-22 into pwm mode:

: config-pin P9-21 pwm

:config-pin P9-22 pwm

These pins will be channel 1 and channel 0 on pwm0.

Go to /sys/devices/platform/ocp and look for epwm entries,

:ls -l | grep epwm

You probably see something like




Since we’re attempting to use pwm0, the first entry is where to go.

:cd 48300000.epwmss

which has a directory

:cd 48300200.pwm

which has a directory

:cd pwm


There should be a directory to pwmchipX, where X could be a different number each time.

:cd pwmchipX

Now, the directory has some files, include export.

:echo 0 > export

:echo 1 > export

to create the entries for channel 0 and channel 1.

I got directories



Now, set the parameters (enable, period, duty_cycle) for channel 0, and look for a signal on P9-21 (pwm-1:1) and P9-22 (pwm-1:0).

I had to set period first, then duty, then enable.



  1. IR proximity sensor
  2. TOF range finder
  3. Distance and gesture sensor
  4. Lidar lite

After that … encoder interface.  Connect channel A and channel B to two R31 channels on the PRU1.  Use deterministic nature of the PRU at high speed in lieu of capture circuitry.

Could it be … there are audio input and output features to the Beaglebone Black.  The eCAP module might be usable to sample audio signals.  Could use this to enable the tone based identity and distance measurement.

Finally … need to investigate image capture, lidar, sonar, and other distance sensor technologies to expand cassy’s range.

On the arm … need to wire up the bumper switches to digital inputs.

Need to update the gui to use either bluetooth or ethernet sockets.  Both are available on the iPad, although bluetooth might involve a bit of juggling.

Some notes for future:

UCSD Advanced Digital Systems course

Novus robotics cape (Strawson Design)


Sparkfun parts for Beaglebone ( – Ga Tech)

PRU is a growing topic at Embedded Linux Conference.

Posted in: Robotics

Comments are closed.