Transmit DMX data with DMA

I’m trying to create some code to transmit DMX preferable with DMA. There are a few topics, however there are not any existing libraries so far that work directly out of the box.

There is an application that transmits DMX (that receives ArtNet data), however the code seems unnecessary low-level. However it seems to work on the Particle devices.

Besides that there are other Teensy libraries mentioned that might be a good starting point:

This seems some interesting pseudo code to transmit DMX by using the default Serial implementation (I suppose the STM32 also support a baudrate setting of 250000?):

I’m wondering of DMA is supported on Serial1 (the TX/RX outputs on the Photon)? I know it’s implemented for SPI. It would be nice if we could send out DMX data directly from the memory in the background, while the Photon keeps rendering light data.

I dived in the firmware and it seems that you can enable DMA on Serial1 (which is USART2 if I found it right).

On line 435 of stm32f10x_usart.c

  * @brief  Enables or disables the USART’s DMA interface.
  * @param  USARTx: Select the USART or the UART peripheral.
  *   This parameter can be one of the following values:
  * @param  USART_DMAReq: specifies the DMA request.
  *   This parameter can be any combination of the following values:
  *     @arg USART_DMAReq_Tx: USART DMA transmit request
  *     @arg USART_DMAReq_Rx: USART DMA receive request
  * @param  NewState: new state of the DMA Request sources.
  *   This parameter can be: ENABLE or DISABLE.
  * @note The DMA mode is not available for UART5 except in the STM32
  *       High density value line devices(STM32F10X_HD_VL).
  * @retval None

This low-level stuff is (still) a bit difficult to understand for me, so I hope someone can give some hints or pseudo code.


I’m trying to port a DMX library made for the STM32F4Discovery board to the Photon. However probably something goes wrong in the DMA/Interrupt configuration.

I’ve tried to modify the code based on different w2812 dma, one wire and the Spark Interval Timer library

I had the idea I might the right selection of DMA Channels, Timers etc. (also based on the STM manual). However after uploading I can’t use the Serial ports anymore. I’m a bit clueless how to debug further.

This is a pretty new topic for me, so I’m not 100% sure if my conclusions are good.

I use now Timer4, which is only used for i2c as far as I’m aware. What I understood as well is that for DMA I need to use timer 2-4, because higher timers (6 and 7 seem free) can’t be used.

I use DMA1, stream5 (which I think is mapped to timer4).

I’ve noticed that I get an error on 'RCC_APB2Periph_GPIOB' was not declared in this scope RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); However all the other low-level GPIO commands seem to be supported.

I tried to work around this with:

GPIO_TypeDef *gpio_port = PIN_MAP[dmxPin].gpio_peripheral;

HAL_Pin_Mode(dmxPin, OUTPUT);

if (gpio_port == GPIOA ) {
    dmxOutputPort = (uint32_t)&GPIOA->ODR;
else if (gpio_port == GPIOB ) {
    dmxOutputPort = (uint32_t)&GPIOB->ODR;

I hope someone that understands the low-level stuff has time to chime in. @bko @peekay123 @BDub

Maybe I overlook something essential.

The whole code on Gist:

My next try would be SPI.transfer. However that limits the DMX output to A5 or D2 (SPI MOSI).

Just an update of this post in case someone comes across it. In the article below I describe how I could make DMA control of the output pins possible for the Photon. The next step is to utilise it for DMX control.


Below the DMX implementation that works with DMA and the Photon. However the new Argon and Boron boards seem also really interesting candidates (I like the BLE addition). However this is a completely different processor unfortunately (documentation of STM32 seems better then from the NRF52). I’ve read something about EasyDMA, but I can’t find the details (if anyone has a pointer, please shout).

1 Like