beaglebone PWM -- can't write to registers (reads are fine)

Hi folks. I’ve been working to add PWM support to Alex Hiam’s PyBBIO project (, which uses the python mmap module to manipulate the BeagleBone uC’s memory directly. For GPIO access, Alex’s project works great. I’m trying to add some simple, Arduino-style PWM-based analog output capabilities.

The reference manual is starting to make sense, and I think the only thing holding me back from implementing analogWrite()-like functionality is my inability to change the system’s state, rather than incomprehension of what that state should be.

But although I’ve got the module clock enabled, I can’t seem to get writes to the PWMSS memory block to take. Once the module has been enabled via CM_PER, I can read the PWMSS registers just fine. But writing to configure them does nothing. You can see some example debug output demonstrating the problem here:

I suspect I’m missing something obvious, but I’m not familiar enough with the norms of the AM335x processor family to guess what it might be. FWIW I’m able to write to the GPIO registers (which Alex’s code manipulates) just fine. I imagine there’s some initialization procedure for the PWMSS that I’m overlooking, but so far I haven’t stumbled across the relevant part of the reference manual.

I’d be grateful for any thoughts you might have – I really would like to get this work into decent shape so that it can be made available to others in the community. You can find the present state of my code here: if any of the above is unclear.


The Python code that Steve Galle posted to this discussion works for
me, both read and write:

However, I've only used it with CM_PER_EPWMSS1_CLKCTRL and
CM_PER_EPWMSS2_CLKCTRL, so that probably doesn't help you.

If you are working with the eCAP PWM registers, then I have the same
problem as you when writing to them through the file system - what I
write gets thrown away.

For convenience, I've pasted Steve Galle's Python code below:

from mmap import mmap
import struct

MMAP_OFFSET = 0x44c00000 # base address of registers
MMAP_SIZE = 0x48ffffff-MMAP_OFFSET # size of the register memory

CM_PER_BASE = 0x44e00000 - MMAP_OFFSET

with open("/dev/mem", "r+b") as f:
    mem = mmap(f.fileno(), MMAP_SIZE, offset=MMAP_OFFSET)

def _andReg(address, mask):
    """ Sets 32-bit Register at address to its current value AND mask.
    _setReg(address, _getReg(address)&mask)

def _orReg(address, mask):
    """ Sets 32-bit Register at address to its current value OR mask.
    _setReg(address, _getReg(address)|mask)

def _xorReg(address, mask):
    """ Sets 32-bit Register at address to its current value XOR mask.
    _setReg(address, _getReg(address)^mask)

def _getReg(address):
    """ Returns unpacked 32 bit register value starting from address.
    return struct.unpack("<L", mem[address:address+4])[0]

def _setReg(address, new_value):
    """ Sets 32 bits at given address to given value. """
    mem[address:address+4] = struct.pack("<L", new_value)


Thanks for the response, Dan. I appreciate the sample code, but I
think it's functionally identical to what I've got. For instance, I
placed Steve's code in, then, using the constants from my
additions to Alex's PyBBIO:

import test
import bbio


test._setReg(bbio.EPWM1+bbio.EPWM_CMPA, 0xffff)


Steve's _setReg/_getReg functions don't reflect the fact that
EPWM_CMPA is only 16 bits wide, but for purposes of this example I
don't think it ought to matter -- the registers are little-endian, and
when I write past its end with a full 32-bit word the same effect is