0
\$\begingroup\$

I would like to produce as many 10-bit PWM outputs at 500 Hz or less as possible using a single pin of a microcontroller, in this case an Arduino Uno, and a SIPO shift register.

I found this question which led me to Binary Code Manipulation / Bit Angle Modulation and while this seems to have hints of an answer, my project requires the outputs of the shift register to be PWM. I need to maintain a minimum of 10-bit resolution, but the frequency could be anywhere between 300 and 500 Hz.

I assume I will have to use the 16-bit timer and sacrifice a bit if resolution to succeed. I wasn't sure if it was as simple as 16-10 = 6 outputs, and even if it is, I need a little help getting started, especially assuming it will involve register manipulation. I'm not a strong coder so I'll have to use (probably bad) pseudo code, but I imagined something like:

make an array of n rows with 1024 binary values

interlace this to a single row of 2^16 binary values

output this to a shift register

latch every n timer cycles // (only wire up the first n outputs of the shift register)

accept inputs to any row in the array at any time, but...

only update the single row fed to the shift register every 1/500th of a second

Thanks for any assistance. If it's not too much, I'd also like to know how many pins I can use as an output for the provided method on an ATmega328p if such information isn't apparent in the answer.

Edit: Thank you for the response ElectronicsStudent. I have some AL8861 ICs which accept pwm or analogue input for dimming. I would like to drive one of these per single LED cell, (around 750 mA peak current,) and through experimentation I have found 256 dimming stages to be too abrupt for the fades I want. I only need to find a solution to drive a dozen or so AL8861s initially, but would like the project to eventually accommodate more. The esp32 seemed viable with 16 pwm outputs at 10 bits each, but I still hoped for a way to avoid buying one esp32 for every 16 AL8861 chips.

\$\endgroup\$
6
  • 1
    \$\begingroup\$ If you tell us about your product, we are able to come up with other possibilitys to solve the problem. \$\endgroup\$ Commented Mar 26, 2023 at 18:32
  • \$\begingroup\$ Thanks for the insight! I've edited the post to include more detail but you already saved me a lot of time. \$\endgroup\$
    – eemoob
    Commented Mar 26, 2023 at 18:51
  • \$\begingroup\$ Are you planing to do some LED-Cube/ LED FFT? \$\endgroup\$ Commented Mar 26, 2023 at 18:55
  • \$\begingroup\$ I have white led stips I've cut down to 30cm and removed the resistors from. I'd like to make very bright led bars which smoothly fade and control dozen(s) of these bars independently. I've been working on this project for months and changed aspects many times as I've learned more. \$\endgroup\$
    – eemoob
    Commented Mar 26, 2023 at 19:07
  • 1
    \$\begingroup\$ I don't get the 'analogue logic' definition but: this task would be easily done by a CPLD/FPGA with a UART input for setting each PWM level. A single cheap FPGA could control as many as you'd reasonably want providing you can solder the package, so 100's of outputs with no effort on the circuit's part (unlike the MCU approach). There's plenty of cheap (sub-£25) 'USB stick' boards that'll give you 50-odd outputs plus larger boards. The designing of it's is VHDL or Verilog is not so simple and quite a learning curve if you've not done any digital logic circuit design before but perfectly doable. \$\endgroup\$
    – TonyM
    Commented Mar 26, 2023 at 20:51

1 Answer 1

1
\$\begingroup\$

Okay, let's see.

10Bit Resolution at 300Hz nom. means a "Latch-precision" of

(300Hz)⌃(-1) / 2⌃10 = 3.25us

To have some headroom, you should have a bit extra (Nyquist and so on)! Therefore:

(300Hz)⌃(-1) / 2⌃11 = 1.62us

This is the time available to shift data via the GPIO, setup/reconfigure/execute the Timer ISR, compute the actual bit-states and do the housekeeping in your software.

On a ATMega328p running at 20MHz tops (You can go this high, but it is outside of the recommended range) this equates to:

20MHz * 3.25us = 65 Cycles

So in best case (Highest CPU Clock and lowest resolution) you will have a maximum of 65CPU Instructions (some Instructions aren't even single-cycle).

So in short: Not realy a practicable approach!

Other possible approaches:

  • Implementation in an FPGA
  • External PWM ICs configureable via SPI/I2C
  • More powerful MCU (ARM > 100Hz)
  • MCU with many Timers You could controll like 4 PWM signals via a single Timer. But be aware of phase lag and especially Jitter between timers!
  • Spin a custom CPLD/FPGA for e.g four/eight PWM Channels and make it interfaceable via SPI/I2C

But:

If there are some "options" to constrain your requirements, you can make it work.

  • If all your channels are "the same" signal, you can use discrete logic to multiplex it.
  • If all channels have the same PWM period and phase and you limit the PWM % to 30<x<70 (rough estimate) your controller will have enough time to compute the data for some channels.
  • If all periods are multiples of each other and you limit the PWM % to 30<x<70 (rough estimate) your controller will have enough time to compute the data for some channels.

Edit 1:

After you updated your question, i had a look around. Something like LP5012 could fit the bill. You could either drive the LEDs directly, or - if you require more current - condition the output signal (via Pullup) and feed it into a driver IC/Mosfet.

There is a fair chance you could get this to work even with 400kHz I2C (depends on your requirements).

Only problem is: These chips are not available for lowisch PWM frequencys like 300Hz.

Edit 2:

May i recommend the following approach:

You design a little PCB with an ARM M0+ or M3 running at around 100MHz. Look for an ST-PArt optimized for industrial-/motor-control. They have a nice feature set (many timers, enough processing grunt, communications IO and so on). Each of these PCBs drives a single of your LED-Strips (This way you keep the load per CPU down).

They are connected together with some kind of RS485 (cheap, simple, realiable) and a custom protocoll or maybe even DMX (Or other existing systems for ligth control applications).

This array of slaves is controlled by a single net-ready device like ESP32.

The ESP32 handles the overall business logic (What RGBs with which dimming should be set where and when and so on...)

\$\endgroup\$
3
  • \$\begingroup\$ TY for the help in your edit. I think switching to an esp32 uC will still make the project at least practical and I'll continue to search for IC combinations that would work. Perhaps a different final led driver will solve my issue. \$\endgroup\$
    – eemoob
    Commented Mar 26, 2023 at 19:44
  • 1
    \$\begingroup\$ @eemoob You are welcome. I did another edit. \$\endgroup\$ Commented Mar 26, 2023 at 20:08
  • \$\begingroup\$ Thank you very much! You've given me a great start in my next steps. Maybe I'll post a question about this version in a couple of months. :) \$\endgroup\$
    – eemoob
    Commented Mar 26, 2023 at 20:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.