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?

  • I was wrong about the data replicating throughout the buffer.  I was checking this by pausing the code and examining the memory with the debugger.  I'm guessing that stopping the code doesn't stop ongoing UART-DMA operations so the buffer continues to fill after the break, which is good for me.

    I still need a way to find the number of bytes received before the BREAK.

  • Not sure if it's an issue or not but the max Rx count on the nRF52810 is 1024 bytes, comfortably above the 513 you need, but note the receive structure appears to be only 8-bit and it looks like the code above is trying to use this (256-byte limit):

    /**
     * @brief Structure for UARTE transfer completion event.
     */
    typedef struct
    {
        uint8_t * p_data; ///< Pointer to memory used for transfer.
        uint8_t   bytes;  ///< Number of bytes transfered.
    } nrfx_uarte_xfer_evt_t;
    
    #define UARTE0_EASYDMA_MAXCNT_SIZE 10
    

    Just checked and the nRF52832 has an 8-bit register, but the nRF52810 has a 10-bit register.. This is a software bug, methinks, since the 10-bit size is checked against an 8-bit register if the nrfx_uarte_xfer_evt_t() code above is the correct version (15.2.0).

    65? Don't know how that ties up ..

  • That does look like a problem (bug?).  But I also tried calling nrf_uarte_rx_amount_get() which returns a uint32_t and I'm still seeing 0 bytes transfered.   The UARTE documentation makes it sound like the RXD.AMOUNT register isn't updated until the receive operation is complete and it sounds like an ERROR is not considered complete.  I even tried reading the RXD.PTR and subtracting my buffer address and it still gives me 0.

  • Yes, the problem is an Error does not generate an END event, so the break does not stop reception and populate the count register. You can manually generate a Stop within the Break Error interrupt handler which would work. Also nrf_uarte_rx_amount_get() doesn't return 32-bits, only 10-bits in a 32-bit field. Not sure why Nordic limited it to 10-bits ..

    Regrettably there is no SHORT between Error and End or Stop; if there were you could just use that instead of manually doing it in the error event .. let's ask Nordic to add it to the next die revision :-)

  • 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.

Related