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

Delay before starting DMA'd UART transfer

I need to send data over ModBus-RTU (basically RS485) from an nRF52840. For this, I use uarte. The transceiver's transmit enable input is controlled through a GPIO pin, which in turn is controlled from the PPI (NRF_UARTE_EVENT_TXSTARTED and  NRF_UARTE_EVENT_TXSTOP events). When I check on the scope, I see a varying time between the enable pin being raised and the start of the actual transfer. For example: in the below capture, the delay between TXD (in blue) and the enable pin (in red) is 23.67 usec, This delay varies from 0 up to one bittime (I've seen a 103 usec delay when transmitting on 9600 bps).

Can I remove these delays or otherwise at least stabilize them so that they always are the same?

This is my code for initialization:

void rs485_init ( void )
{
    uint32_t task_addr;
    uint32_t event_address;
    static bool _init_done = false;
    nrfx_uarte_config_t uarte_config = NRFX_UARTE_DEFAULT_CONFIG;
    uarte_config.pseltxd  = MODBUS_TX_PIN;
    uarte_config.pselrxd  = MODBUS_RX_PIN;
    uarte_config.hwfc     = NRF_UARTE_HWFC_DISABLED;

    nrfx_gpiote_out_config_t nrfx_gpiote_out_config = NRFX_GPIOTE_CONFIG_OUT_TASK_TOGGLE(0);

    uarte_config.baudrate = NRF_UARTE_BAUDRATE_9600;
    uarte_config.parity = NRF_UARTE_PARITY_INCLUDED;
    
    if (_init_done) nrfx_uarte_uninit(&uarte); 
    APP_ERROR_CHECK(nrfx_uarte_init( &uarte, &uarte_config, uarte_event_handler)); // Init in non-blocking mode

    if ( !nrfx_gpiote_is_init() ) 
    {
        nrfx_gpiote_init();
    }
    else
    {
        nrfx_gpiote_out_uninit( MODBUS_RTS_PIN );
    }

    // Initialize the RTS pin as output, to be driven from UART TX via PPI
    APP_ERROR_CHECK(nrfx_gpiote_out_init( MODBUS_RTS_PIN, &nrfx_gpiote_out_config ));
    nrfx_gpiote_out_task_enable( MODBUS_RTS_PIN );

    // Setup PPI to set enable on start of transmission
    APP_ERROR_CHECK( nrfx_ppi_channel_alloc( &_ppi_channel_start ) ); 
    event_address = nrfx_uarte_event_address_get( &uarte, NRF_UARTE_EVENT_TXSTARTED );
    task_addr = nrfx_gpiote_out_task_addr_get( MODBUS_RTS_PIN );
    APP_ERROR_CHECK( nrfx_ppi_channel_assign( _ppi_channel_start, event_address, task_addr ) );
    nrfx_ppi_channel_enable( _ppi_channel_start );

    // Setup PPI to clear enable on end of transmission
    APP_ERROR_CHECK( nrfx_ppi_channel_alloc( &_ppi_channel_stop ) ); 
    event_address = nrfx_uarte_event_address_get( &uarte, NRF_UARTE_EVENT_TXSTOPPED );
    task_addr = nrfx_gpiote_out_task_addr_get( MODBUS_RTS_PIN );
    APP_ERROR_CHECK( nrfx_ppi_channel_assign( _ppi_channel_stop, event_address, task_addr ) );
    nrfx_ppi_channel_enable( _ppi_channel_stop );

    // Receiver initialization removed for brevity

    _init_done = true;
    NRF_LOG_INFO( "RS485 initialized" );
}

Related