This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Receiving DMX512 data stream

Parts of this discussion started on this thread: i-am-trying-to-do-dmx512-protocol

I am using SDK 15.2.0 on an nRF52810.  My test board is based off of a Laird BL651 which contains a real (not simulated) nRF52810.  I'm using the Segger IDE.  My code is based off of the ble_app_uart_pca10040e_s112 example.  I made a copy of app_uart_fifo.c and modified to use the nrfx_uarte drivers directly.

I am trying to receive a DMX512 data stream. The DMX controller sends a packet of up to 513 bytes of data at 250KBaud and precedes each packet with a UART BREAK (holds the line low for 90us).  In my test case the controller is only sending 65 bytes of data.

I initiate the read using: nrfx_uarte_rx(&app_uart_inst, dmx_rx_buffer, BUF_READ_SIZE );  where BUF_READ_SIZE  is 513.  Here is my event handler:

static void uart_event_handler(const nrfx_uarte_event_t * p_event, void* p_context) 
{
    app_uart_evt_t app_uart_event; 
    uint32_t err_code;
 
    switch (p_event->type)
    {
        case NRFX_UARTE_EVT_RX_DONE:
            {
                //never reached??
                NRF_LOG_DEBUG("DMX data in:");
                NRF_LOG_HEXDUMP_DEBUG(dmx_rx_buffer, p_event->data.rxtx.bytes);
                (void)nrfx_uarte_rx(&app_uart_inst, dmx_rx_buffer, BUF_READ_SIZE);
            }
            break;

        case NRFX_UARTE_EVT_ERROR:
            app_uart_event.evt_type                 = APP_UART_COMMUNICATION_ERROR;
            app_uart_event.data.error_communication = p_event->data.error.error_mask;

            if (app_uart_event.data.error_communication & UARTE_ERRORSRC_BREAK_Msk)
            {
                size_t amount = nrf_uarte_rx_amount_get(app_uart_inst.p_reg);
                NRF_LOG_DEBUG("DMX err: %d %d %d %d", amount, p_event->data.rxtx.bytes,  dmx_rx_buffer[1],  dmx_rx_buffer[57]);
                (void)nrfx_uarte_rx(&app_uart_inst, dmx_rx_buffer, BUF_READ_SIZE);
            }
            break;
            
        default:
            break;
    }
}

The good news is I'm capturing the data reliably.  The bad news is I can't tell how much data was received.  The EVT_RX_DONE handler never gets called unless I reduce BUF_READ_SIZE from 513 to 65 or less.  The EVT_ERROR handler is correctly detecting BREAK.  I checked it with a scope and the handler gets called consistently 60us after the start of the BREAK which is good.  The handler is also seeing a FRAMING error which is expected.  It doesn't appear to be missing any of the BREAK events.

Once in the EVT_ERROR handler I can't find the amount of data received before the error occurred. 

Also,  if I stop the code and check the 513 byte buffer contents, I can see the correct 65 bytes of DMX data,  but the 65 bytes of data gets replicated throughout the 513 byte buffer, so I see my data at locations 0-64, but also at 65-129, 130-195, ... .

is there a way to find the number of bytes received before the BREAK and can I stop the data from filling the rest of the buffer after the BREAK is received?

Parents
  • Here is an update.  The data in the buffer looks like I expect it to which is good,  but I still can't tell how many bytes were written.

    I tried adding a call to nrfx_uarte_rx_abort in the error handler, but didn't get the results I was hoping for.  The documentation says an RX_DONE event will be generated, but the event handler sees the event. 

    Calling nrfx_uarte_rx_abort has some undesired side effects too.  I sometimes get an extra ERROR event on the first character when I call nrfx_uarte_rx to do the next read.

    Except for the not knowing how many bytes were sent, the code I added in the first post seems to be working fine.

  • Maybe the error is real, and the uart needs to be stopped after the abort before re-priming for the next message packet.

    Why does the DMX controller need to send a Break anyway? When the receiver needs to stop and process an incoming packet, usually it works better to attach the Rx input to a timer input in addition to the Uart, such that when no transition occurs within some specified interval an end Rx condition can be triggered. That timer monitoring can be initiated on the first Rx edge transition.

  • The DMX controller sends a Break because that is how DMX is defined.  It is a pretty old standard. Here is a link if you are interested: DMX.  Basicly the signal goes low for 88us-1sec, then high for about 10us, then you get up to 513 bytes of data at 250Kbaud with two stop bits, but delays can occur between bytes as long as the whole packet takes less than 1 second, but then next packet can start right away if it wants to.  Typically a packet take about 22ms, but it can be much quicker if not much data is sent. Most UARTs detect the initial low as a Framing error or as a Break, and handle the remaining incoming data just fine. The nRF52810 seems to be handling the data just fine too, except I haven't found a way to determine how many bytes just got sent.  If I had a dedicated micro, I could just put it in a tight loop and count the characters as they come in, but the nRF52810 has other things to do, so that is not an option.

    Wouldn't a timer input that detects a low signal for say 60us, have the same issue I'm currently having?  The UART would still cause a framing or break error.  Also the re-priming you mentioned could be a big issue too since there might only be 40us before the data gets sent.  I can loose an occasional packet, but loosing too many would affect the performance too much.

    Questions for you:

    • You said something about re-priming the uart.  Do you have any information on how much time is required after an abort before data can be received again?
    • Regarding the missing RX_DONE event, in the code from my first post, I replaced the call to nrfx_uarte_rx() with a call to nrfx_uarte_rx_abort so that when the BREAK is handled the RX stops.  Should that cause an NRFX_UARTE_EVT_RX_DONE event that gets seen by the handler?  (It doesn't currently)
    • Is there any other way to find the number of bytes received?

    My backup plan it to fill the buffer with known data and scan it after the data has been received to see what has changed, but that's a terribly brute force approach and may not work.  Plus I have to deal with issues like what if the data sent matches my preset values.  

Reply
  • The DMX controller sends a Break because that is how DMX is defined.  It is a pretty old standard. Here is a link if you are interested: DMX.  Basicly the signal goes low for 88us-1sec, then high for about 10us, then you get up to 513 bytes of data at 250Kbaud with two stop bits, but delays can occur between bytes as long as the whole packet takes less than 1 second, but then next packet can start right away if it wants to.  Typically a packet take about 22ms, but it can be much quicker if not much data is sent. Most UARTs detect the initial low as a Framing error or as a Break, and handle the remaining incoming data just fine. The nRF52810 seems to be handling the data just fine too, except I haven't found a way to determine how many bytes just got sent.  If I had a dedicated micro, I could just put it in a tight loop and count the characters as they come in, but the nRF52810 has other things to do, so that is not an option.

    Wouldn't a timer input that detects a low signal for say 60us, have the same issue I'm currently having?  The UART would still cause a framing or break error.  Also the re-priming you mentioned could be a big issue too since there might only be 40us before the data gets sent.  I can loose an occasional packet, but loosing too many would affect the performance too much.

    Questions for you:

    • You said something about re-priming the uart.  Do you have any information on how much time is required after an abort before data can be received again?
    • Regarding the missing RX_DONE event, in the code from my first post, I replaced the call to nrfx_uarte_rx() with a call to nrfx_uarte_rx_abort so that when the BREAK is handled the RX stops.  Should that cause an NRFX_UARTE_EVT_RX_DONE event that gets seen by the handler?  (It doesn't currently)
    • Is there any other way to find the number of bytes received?

    My backup plan it to fill the buffer with known data and scan it after the data has been received to see what has changed, but that's a terribly brute force approach and may not work.  Plus I have to deal with issues like what if the data sent matches my preset values.  

Children
No Data
Related