How to control fine PWM on AI64?

Thanks for your help as always.
This is where I ate lunch a little while ago. :smiley:

For now, I’ll try my hand at writing some C++ code.
Good night!

1 Like

Okay…and we are back,

@ALEX_PARK , I found the correct image w/ the ehrpwm modules located on it…

If you go and get an image w/ /opt/dtbs/ located in that file, use make && sudo make install_arm64.

That should make it accessible for you to use those modules. Now, for the timers and eQEP modules, I have not found out how to utilize them yet, i.e. as I am not in charge of porting the hardware to DTS format nor could I do it anyway.


P.S. I think BONE-PWM{0-2}.dtbo is not the same thing. Is BONE-PWM1 the same as ehrpwm?

Okay. So, w/out further evidence here, I am posting a photo of period and duty_cycle on the ehrpwm channel at P9.25.

I will read more in time and report back. For now, that is what I am getting on my set up. I have been reading on my oscilloscope details. The guide book is okay, I guess. Anyway, I will produce a better reference waveform later in the week, i.e. Sat. or Sun.

I have to get ready for the ole day.

1 Like

That will help w/ a LED strip (I think).

I hope you had a good weekend.

I got the info from the link above.

BONE-PWM2.dts applied. and connected P8.13.

In my list of HEADER PINs, it is specified as EHRPWM0_B.

Hello @ALEX_PARK ,

The weekend was okay. Finally…rest. Anyway, in the new image (Bookworm), there are two pins that are listed as ehrpwm on the /boot/firmware/overlays/ files that one can add in w/ the /boot/firmware/extlinux/extlinux.conf file.

From my knowledge, this does not specifically mean that the other PWMSS pins are not ehrpwm enabled but maybe they are not.

I do not know right now what to make of it.


P.S. BeagleBone cape interface spec — BeagleBoard Documentation

I will test again and see if I cannot get better results like we discussed earlier last week.


Here is the Bookworm page on this forums w/ the ehrpwm peripheral access overlays:

Another Update and Ideas…

  1. I have all my PWM overlays enabled which includes the ehrpwm overlays at P9.25/P8.37.
  2. Do you think testing PWM1 and then ehrpwm at P9.25 will encounter different results on the oscilloscope?
  3. If I encounter different results, I will reply w/ that info. and add photos in the mix.

I had some issues w/ the software on my oscilloscope. Bugs. I should report them to Rigol. I had to erase every form of source from Rigol to get rid of the pop-up installs. Blah.

Anyway, I can test right now even though I need to learn the divisible part of my connections w/ the Rigol in mind. Updates on the way. Also, the link I posted can get you about 200MHz loops from the PRU…

1 Like

I am using bullseye because of EDGEAI.

I happened to be testing BBAI64-P9_25-ehrpwm4_b.dtbo.
If I have any updates, I’ll share them.

1 Like


Just a heads up here. These photos so far mean nothing to me. I need to research exactly what they mean.

The first photo is the ehrpwm overlay being used w/:

  1. echo 500000 > period
  2. echo 10000 > duty_cycle
  3. echo 1 > enable

The second photo is the pwm at file /dev/bone/pwm/1/a/.

  1. echo 500000 > period
  2. echo 10000 > duty_cycle
  3. echo 1 > enable

So far, and as I update firmware to the scope (phew), I have noticed that at the same time and at the same voltage, I have different ideas presented.

Oh and I know what you said earlier about my angle on this discussion which is listed further up the post. No issue but my intentions are to learn more and use this discussion to handle that learning.

Photo 1 of the ehrpwm ss:


Photo 2 of PWMSS:

I will be researching the time and voltage aspects to each photo and output so I can learn. Hopefully, this helps a bit to the trained eye.


P.S. If you need additional info. from me on the oscilloscope, please let me know.


I’m not an embedded developer.

More and more, I’m not sure I’m on the right track.

First, I realized that it’s probably not possible to simply change the values of period, duty_cycle, and enable.

Second, there is too little information about EHRPWM. I have no idea what to do.

I want to make the 0 and 1 codes 1.25us apart, blowing up just one set of 24 bits. :sob: :sob:

But it’s harder than just swapping duty_cycle and enable.
In Python or C++, generating 0 code and 1 code once produces multiple waveforms.

I need to clear my head and move on to other things.


Changing the duty_cycle produces 19 waveforms.
(duty_cycle 800 > change duty_cycle 400)
make 24us delay.

1 Like

Hello…you can change them to suit your needs. In source, it is a bit more complicated. You can always try a shell script too (bash).

Just for reference, my photos were the result of using the command line commands: echo 1 > enable

When you say 0 and 1, I am assuming you mean on and off. GPIO is good for this idea. It is either 0 or 1 and can help you w/ ease.

For instance…

timing the GPIO to on and then timing it to off may prove valuable.

There is a built-in called time. You can use the sleep function in the built-in time.

i.e. from time import sleep as s

So, you can sleep instead of just on/off the GPIO to 1/0.


P.S. For LEDs on and off is easy w/ Python3 and sleep from time, i.e. GPIO wise here.

W/ PWM, one can sleep again w/ time in Python3 or usleep in C w/ microseconds.



while true; do
  echo 400 > "${pwm_path}duty_cycle"
  echo 800 > "${pwm_path}duty_cycle"

I created a bash script to alternate the duty cycle between 400 and 800.
Instead of generating and changing one waveform, we generate and change 43 waveforms.

delay 44us

Ps. 24us delay on C++ / 44us delay on bash script / 41us delay on python while

1 Like


You are getting somewhere…

So, if anything, are there any ideas outside of what you know that I can be of service to currently?

I mean…

How can I help?


P.S. Optimization?

1 Like

As I said above, I want to make 24 bits of 0 code, 1 code with 1.25us period (800khz), and when I make one set of 24, I want to send it to PWM.
(If I make 24 bits, I will have 24 waveforms).

I was wondering if there is any other way to do this besides changing the duty_cycle to echo.
For example, DMA?

I’m very grateful for the help. @silver2row

DMA works…I saw in the docs. there was a small section on it and there are PRUs and DSPs.

I am not a fan of PRUs since I cannot do much w/ them so far.

DSPs on the BBAI-64 are out of my league for now and the Cortex-R5s I have not been able to make work. I know some other people on this forum have had success w/ the Cortex-R5s.

GPIO is a route too. I mean you can turn on the GPIO for a period while it is 1 and then off for a period.

So, three bytes or 24 bits of on and off. 0s and 1s…okay.

Memory Mapping should work, like you were discussing.

Now, using PWM in memory mapping may be complicated. I am not sure how you can achieve the feat.

Also, there was another project I found a while back called SimpPRU: Digital Read - simpPRU

The PRU Cookbook is another route and there may be a large LED project listed in it. I need to double check.

1 Like

Thank you so much. @silver2row

  • Note _ I/O with devmem2, simpPRU

@ALEX_PARK I am afraid you will not be able to control the addressable LEDs using a PWM. As you have found you can’t switch the duty cycle fast enough to get the different pulse widths required.

I have just had a quick search to see how the Pi does this, quite interesting as far as I can see. The timing for LED strips is pretty fussy and you are not going to achieve it by using a standard PWM.

Looking at how the Pi does it, there is maybe the option of using SPI and clocking it at a higher frequency and then writing out several bytes to generate your bit pattern. Potentially this would work but not the most efficient way to do it. You also need to fit the whole string into 1 DMA transfer or risk losing the timing.

The Pi code uses 3 SPI bits to set one LED bit, so clocking out 110b from the SPI gives you a 1 and clocking 100b gives a 0.

This only works if you can set the SPI clock to the correct frequency. The Pi can achieve this, however it may not be possible on the AI64. It will all depend on base clock frequency and the various divisors used to set the clock.

I would say your best option for doing this sort of thing is to make use of the PRU’s. Unfortunately documentation is pretty lacking for the AI64. There is at least 1 PRU driver for the BBB family of boards.

While the AI64 has PRUs (in fact it has more) I doubt the code will work as is on the AI64. In fact I doubt this would work on a recent BBB either as it uses UIO to talk to the PRUs which has been deprecated. Neither git repo has been touched for many years.

The PRU’s are certainly the best way to do this sort of thing. While the Pi driver I saw claims to be able to do 2 strings of 2700 LEDS, You really do not want to drive such a long string as the update rate will be terrible if you want to do any sort of animation effects.

By contrast the BBB PRU code can drive 48 strings of 512 LEDs at 30 FPS for a total of 24576 LEDS.

On the AI64 you may also be able to do this using I2S to clock out bits but it is not going to be easy. Probably your easiest route to get this working is to use SPI assuming you can get the correct SPI clock frequency.

1 Like

Thank you.
I gave up on PWM and turned to SPI, I was setting up an overlay.

debian@BeagleBone-AI64:/sys/class/spi_master/spi0$ sudo beagle-version 
[sudo] password for debian: 
dogtag:[ Debian Bullseye Xfce Image 2023-08-05]
bootloader:[/dev/mmcblk0boot0]:[tiboot3.bin]:[U-Boot SPL 2021.01-gea96725b (Apr 05 2023 - 22:07:31 +0000)]
bootloader:[/dev/mmcblk0]:[/boot/firmware/tiboot3.bin]:[U-Boot SPL 2021.01-gea96725b (Aug 03 2023 - 15:43:32 +0000)]
bootloader:[/dev/mmcblk0]:[/boot/firmware/tispl.bin]:[U-Boot SPL 2021.01-gea96725b (Aug 03 2023 - 15:43:32 +0000)]
bootloader:[/dev/mmcblk0]:[/boot/firmware/u-boot.img]:[U-Boot 2021.01-gea96725b (Aug 03 2023 - 15:43:32 +0000)]
bootloader:[/dev/mmcblk1]:[/boot/firmware/tiboot3.bin]:[U-Boot SPL 2021.01-gea96725b (Aug 03 2023 - 15:43:32 +0000)]
bootloader:[/dev/mmcblk1]:[/boot/firmware/tispl.bin]:[U-Boot SPL 2021.01-gea96725b (Aug 03 2023 - 15:43:32 +0000)]
bootloader:[/dev/mmcblk1]:[/boot/firmware/u-boot.img]:[U-Boot 2021.01-gea96725b (Aug 03 2023 - 15:43:32 +0000)]
UBOOT: Booted Device-Tree:[k3-j721e-beagleboneai64.dts]
UBOOT: Loaded Overlay:[BONE-SPI0_1.kernel]
UBOOT: Loaded Overlay:[BONE-SPI1_0.kernel]
pkg check: to individually upgrade run: [sudo apt install --only-upgrade <pkg>]
cmdline:[root=/dev/mmcblk1p2 ro rootfstype=ext4 rootwait net.ifnames=0 quiet]
dmesg | grep optee
[    0.862287] optee: probing for conduit method.

BONE-SPI0_1.kernel Loaded.

not found

debian@BeagleBone-AI64:/sys/class/spi_master/spi0$ tree /dev/bone
|-- pwm
`-- uart
    `-- 0 -> ../../ttyS2

I need to set something up more.

If you run


Is the spidev driver loaded ?

debian@BeagleBone-AI64:~$ lsmod | grep spi
gb_spi                 20480  0
gb_gbphy               20480  4 gb_spi,gb_uart,gb_i2c,gb_gpio
gb_spilib              16384  2 gb_spi,gb_firmware
greybus               118784  13 gb_bootrom,gb_spi,gb_raw,gb_log,gb_hid,gb_netlink,gb_uart,gb_i2c,gb_firmware,gb_gbphy,gb_gpio,gb_loopback,gb_spilib

Is it loaded?

doesn’t look like it, can you try

modprobe spidev

I think it is spidev

ebian@BeagleBone-AI64:~$ modprobe spidev
debian@BeagleBone-AI64:~$ sudo su
root@BeagleBone-AI64:/home/debian# modprobe spidev

not found… :frowning:


debian@BeagleBone-AI64:~$ sudo insmod /lib/modules/5.10.168-ti-arm64-r108/kernel/drivers/spi/spidev.ko.xz
insmod: ERROR: could not insert module /lib/modules/5.10.168-ti-arm64-r108/kernel/drivers/spi/spidev.ko.xz: File exists