Better LEDs Through DMA

While regular Hackaday readers already know how to blink a LED with a microcontroller and have moved onto slightly more challenging projects such as solving the Navier-Stokes equations in 6502 assembly, that doesn’t mean there’s not space for newbies. [Rik] has published a great tutorial on abusing DMA for blinkier glowy things. Why would anyone want to learn about DMA techniques? For blinkier glowy things, of course.

This tutorial assumes knowledge of LED multiplexing and LED matrices, or basically a bunch of LEDs connected together on an XY grid. The naive way to drive an 8×8 grid of LEDs is attaching eight cathodes to GPIO pins on a microcontroller, attaching the eight anodes to another set of GPIO pins, and sourcing and sinking current as required. The pin count can be reduced with shift registers, and LED dimming can be implemented with PWM. This concludes our intensive eight-week Arduino course.

Thanks to microcontrollers that aren’t trapped in the 1980s, new techniques can be used to drive these LED matrices. Most of the more powerful ARM microcontrollers come with DMA, a peripheral for direct memory access. Instead of having the CPU do all the work, the DMA controller can simply shuffle around bits between memory and pins. This means blinker projects and glowier LEDs.

[Rik]’s method for DMAing LEDs includes setting up a big ‘ol array in the code, correctly initializing the DMA peripheral, and wiring up the LED matrix to a few of the pins. This technique can be expanded to animations with 64 levels of brightness, something that would take an incredible amount of processing power (for a microcontroller, at least) if it weren’t for the DMA controller.

The setup used in these experiments is an STM32F103 Nucleo board along with the OpenSTM32 IDE. [Rik] has released all the code over on GitHub, and you are, of course, encouraged to play around.

15 thoughts on “Better LEDs Through DMA

  1. Terrific post. I’ve been wrestling with how to properly drive a matrix directly from an MCU without resistors like this. The one thing I can’t figure out about these designs is how they manage the pin current limit. When all anodes are on for a particular row, won’t the current flowing through the cathode be fairly large and exceed the current limit on the GPIO pin? Would love some enlightenment.

    1. My solution to this was to make sure that only 2 pins in each row were active at any one time. It barely worked as the refresh rate was on the edge of flicker perception, but the Atmel was only running at 8MHz so a faster clock would have solved that.

    2. Thanks.
      Like janostman said, with an 8*8 LED matrix you’ll have 1/8th of the current per pin on avarage. For a 16*16 LED matrix it’s 1/16th.
      So even without any resistors the avarage current is still below the max of an LED.

      One thing to keep in mind, most ARM microcontrollers can’t deliver a lot of current, the STM32 used can deliver 20mA per pin but a max of 100mA (from the top of my head) for the whole microcontroller.
      An ULN2803A or a bunch of transistors negate this easily.

      1. Both the LEDs and the pin drivers on the microcontroller have both thermal limits (affected by duty cycle) as well as a maximum permissible current density (which is a strict limit beyond which damage will happen)

        An additional constraint from the other direction, the port drivers may not be designed to be ever capable of sourcing that much current. On many of Microchip’s datasheets (but not all), they document the V-I curves for their pin drivers. Most of them are physically incapable of exceeding their rated per-pin current when operated at 3V or lower.

    3. You know you’re allowed to use external transistors to support the necessary drive current, right? A bunch of little FETs would work great, e.g. AO340x. Some N-fets for the cathode array, P-fets for the anodes.

      The other neat way to do this kind of thing is to realise that APA102 LEDs are SPI without a chip-select pin. ARMs including the STM32F103 support DMA to SPI… and there you go. You can refresh a 1000-LED string at hundreds of Hz in full RGB using DMA to SPI and just two pins.

  2. I started working on a similar project some time ago for driving WS2812, but never got it to works properly. But yeah, the idea of using DMA for PWM is really great, except that it takes up so much memory, if you want any decent resolution.

  3. I’ve actually done it for a commercial project. We used it to implement different led patterns (for user feedback) and to generate multiple perfectly aligned trigger waveforms for sensors. Although waveforms were aligned to each other there was a slight drift in the absolute period due to bus access race between DMA and the core.

  4. Paul’s OctoWS2811 library utilizes DMA on the Teensy. As the library name suggests, it is the digital WS281x signal that is utilized in DMA. Pretty impressive though – I believe you can control thousands of LEDs at a high framerate, using 8 pins

Leave a Reply to Erik SCancel reply

Please be kind and respectful to help make the comments section excellent. (Comment Policy)

This site uses Akismet to reduce spam. Learn how your comment data is processed.