Using the MCXA153 LPSPI and eDMA Controller for Digital Waveform Synthesis : Controlling WS2812 Smart LEDs


Aug. 21, 2024
EliHughes-MoreFace_2k
Eli Hughes
1670942658415
Jerry Palacios

Introduction

The Serial Peripheral Interface (SPI) is ubiquitous in embedded systems for interfacing to external peripherals such flash memories, EEPROMs, analog to digital converters and sensors. SPI is a synchronous serial data transmission standard which has a data path from a controller to a peripheral and vice-versa. Data bits are sent synchronous to a clock and there is typically a “chip select” signal to flag an active transaction with a downstream peripheral.

1-byte SPI Transfer in 0,0 Mode. Data Is sampled on the rising edge and shifted on falling edge

Most peripherals expect some sort of multi-byte transaction where data from the controller has an address and/or command structure. At the core of typical SPI controller is a shift register. The shift register is often surrounded by logic to control clock phase, the chip select signaling and input data loading.

The LPSPI Peripheral in the NXP MCXA15x Family of Microcontrollers

Once you understand that SPI is implemented with a shift register with control logic, you can envision using it for applications outside of the typical use cases. Consider the scenario where the bytes 0xFF and 0xAA are transmitted with a chip select.

This example is shown with a gap between data bytes. This is not uncommon for simple MCU software SPI implementations that might poll for when data can be written to the shift register. The MCXA153 has FIFOs in front of the core shift register. This enables the MCU to keep the shift register loaded with data to generate a continuous stream.

In this example, we assumed 8-bit transactions. The SPI controller in the MCXA153 can shift up to 32-bits at a time. Next, let’s remove the chip select and clock signal and then consider the data signal as long series of data bits.

nonstd-spi-7--dk

Precise control of a data stream with a fixed time quanta

If the SPI output shift register is kept loaded with new data as the prior data is being shifted out, we can synthesis arbitrary data patterns with a precise time quanta. The SPI peripheral still has a clock, we are choosing not to expose it. The time quanta δt is set by the internal clocking to the SPI peripheral.

Synthesizing a continuous waveform pattern is achieved by using Direct Memory Access (DMA). The MCXA153 has a DMA controller which can automate transfers of large blocks of data to the SPI peripheral to ensure a 100% continuous data stream

The MCXA Family eDMA Controller

The desired waveform is precomputed, then DMA is used to transfer large blocks of the precomputed data to the SPI peripheral for a continuous data stream. DMA transactions can be linked using a “ping-pong” buffer scheme. The MCU can pre-compute the next data buffer while the DMA controller is moving the current buffer.

Application Example : Controlling WS2812 Intelligent LEDs.

An example of this technique is to efficiently drive WS2812 “intelligent” LEDs with little CPU overhead. These LEDs are designed to be “daisy chained” together with control via a signal bit data stream. You can find them used in very long LED strips and matrix arrays.

Adafruit 8x8 LED Matrix array using the WS2812

The WS2812 command protocol uses a single wire data scheme where data bits are delineated with a pulse width. The period of the symbol is a fixed 2.5μS (or 1.25μs in highspeed mode). The pulse with is adjusted to communicate a “1” or “0” symbol.

The WS2812 data bit symbols encoded in time

The data stream for RGB color data is a long series of these symbols that is propagated down the LED daisy chain. One method to generate this bit stream is to a combination of SPI and DMA. We can adjust the clock rate of the SPI controller such that one data byte spans 2.5uS. Then, we use two different data bytes to represent the “1” and the “0” symbols. Each “byte” of data in the RGB color stream can be encoded as eight bytes in a SPI transaction.

static inline void ws2812_serialize_color(uint8_t *buf,
                                          uint8_t  color)
{
	for (uint8_t i = 0; i < 8; i++) 
    {
		buf[i] = color & BIT(7 - i) ? ONE_FRAME : ZERO_FRAME;
	}
}

A long chain of RGB data can then be precomputed into a larger buffer.

void ws2812_serialize_strip(rgb_pixel_t *led_strip,
                            uint32_t     strip_length,
                            uint8_t     *spi_data)
{
    uint32_t offset = 0;
    
    for(uint8_t i = 0; i < strip_length; i++)
    {
        ws2812_serialize_color(spi_data + (offset)     , led_strip[i].g);
        ws2812_serialize_color(spi_data + (offset + 8) , led_strip[i].r);
        ws2812_serialize_color(spi_data + (offset + 16), led_strip[i].b);
        offset += 24;
    }
}
ws2812_serialize_strip(led_strip,
                           LED_STRIP_LENGTH,
                           spi_ledstrip_data);

    masterXfer.txData   = spi_ledstrip_data;
    masterXfer.rxData   = NULL;
    masterXfer.dataSize = SPI_STRIP_BUF_LENGTH;
    isTransferCompleted = false;
    
    LPSPI_MasterTransferEDMALite(EXAMPLE_LPSPI_MASTER_BASEADDR,
                                 &g_m_edma_handle,
                                 &masterXfer);

The primary advantage with this approach is that very little CPU time is needed to move the data stream. The combination of the DMA controller and SPI controller efficiently shift data in the background. Sample code for that uses the NXP FRDM-MCXA153 here:

https://github.com/wavenumber-eng/mcxa153_spi_neopixel.git

Animated GIF showing the FRDM-MCXA153 controlling WS2812 LEDs with the SPI/DMA approach
Animated GIF showing the FRDM-MCXA153 controlling WS2812 LEDs with the SPI/DMA approach

Conclusion

The DMA controller in the low cost MCXA153 enables some very interesting IO uses cases. In this example we used the SPI controller, however we could have also combined the DMA with a PWM to achieve the same result. SPI is ubiquitous in many MCUs and is a easy to way to synthesize data patterns.

In a future paper, we will look at using SPI slave with DMA to generate a Pulse Density Modulation (PDM) pattern . The goal being to emulate a PDM digital microphone for audio system testing. We hope these examples enable you to consider ways to use a SPI controller with DMA for new and interesting use cases.

References




Engage
jack in