Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Half-duplex UART (single wire) with and two nRF52840-DK

I'm trying to achieve half-duplex UART communication between two nRF52840-DK:s (master/slave) using no external circuitry. I was looking at the thread https://devzone.nordicsemi.com/f/nordic-q-a/15513/nrf52832-single-wire-uart where the OP had a similar objective. I have been experimenting with both libuarte and app_uart(_fifo) without any success. 

The scenario I am trying to exemplify is that the master transmits a byte to the slave followed by the slave receiving that byte and respond with an incremented byte. The master should then receive the incremented byte.

The slave is able to receive the byte sent from the master correctly, and it then transmits the incremented bytes. However, the problem is that the master receives the same byte that it transmitted initially instead of the incremented byte.

This is my code so far for app_uart (libuarte code essentially does the same but does the GPIO reconfiguration in the event handler, results in the same behaviour):

Master:

    nrf_gpio_cfg(
        27,
        NRF_GPIO_PIN_DIR_OUTPUT,
        NRF_GPIO_PIN_INPUT_DISCONNECT,
        NRF_GPIO_PIN_PULLUP,
        NRF_GPIO_PIN_H0D1,
        NRF_GPIO_PIN_NOSENSE);

    uint8_t cr = 5;
    NRF_LOG_INFO("Sent char %d", cr);
    while (app_uart_put(cr) != NRF_SUCCESS);
    nrf_delay_ms(2500);
    nrf_gpio_cfg(
        27,
        NRF_GPIO_PIN_DIR_INPUT,
        NRF_GPIO_PIN_INPUT_DISCONNECT,
        NRF_GPIO_PIN_PULLUP,
        NRF_GPIO_PIN_H0D1,
        NRF_GPIO_PIN_NOSENSE);

    while (app_uart_get(&cr) != NRF_SUCCESS);
    nrf_delay_ms(2500);
    NRF_LOG_INFO("Received char %d\r\n", cr);

Slave:

uint8_t cr;

nrf_gpio_cfg(
    27,
    NRF_GPIO_PIN_DIR_INPUT,
    GPIO_PIN_CNF_INPUT_Connect,
    NRF_GPIO_PIN_NOPULL,
    NRF_GPIO_PIN_H0D1,
    NRF_GPIO_PIN_NOSENSE
);

while (app_uart_get(&cr) != NRF_SUCCESS);
nrf_delay_ms(2500);
nrf_gpio_cfg(
        27,
        NRF_GPIO_PIN_DIR_OUTPUT,
        GPIO_PIN_CNF_INPUT_Connect,
        NRF_GPIO_PIN_NOPULL,
        NRF_GPIO_PIN_S0S1,
        NRF_GPIO_PIN_NOSENSE
    );
NRF_LOG_INFO("Received char %d", cr);
cr += 1;
while (app_uart_put(cr + 1) != NRF_SUCCESS);
NRF_LOG_INFO("Sent char %d\r\n", cr);

In both cases, app_uart has been initialized with

const app_uart_comm_params_t comm_params =
{
    27,
    27,
    RTS_PIN_NUMBER,
    CTS_PIN_NUMBER,
    APP_UART_FLOW_CONTROL_DISABLED,
    false,
    115200
};

APP_UART_FIFO_INIT(&comm_params,
                     UART_RX_BUF_SIZE,
                     UART_TX_BUF_SIZE,
                     uart_error_handle,
                     APP_IRQ_PRIORITY_LOWEST,
                     err_code);

Parents
  • Hi,

    I do not think that the UART peripheral will work correctly if you set both TX and RX pin to the same GPIO. You should rather set the RX pin to UART_PIN_DISCONNECTED initially and switch the pins after transmitting the data, by re-initializing the UART library. If you have a 2500 ms delay, there should be plenty of time to do this. You can use the APP_UART_TX_EMPTY event to determine when it is safe to reinit the library.

    Best regards,
    Jørgen

  • Hi Jörgen,

    Thanks for the swift reply.

    I just tried your suggestion, where it currently looks like this:

    Master:

    static void init_uart(uint32_t rx_pin, uint32_t tx_pin);
    
    void uart_error_handle(app_uart_evt_t * p_event)
    {
        if (p_event->evt_type == APP_UART_COMMUNICATION_ERROR)
        {
            APP_ERROR_HANDLER(p_event->data.error_communication);
        }
        else if (p_event->evt_type == APP_UART_FIFO_ERROR)
        {
            APP_ERROR_HANDLER(p_event->data.error_code);
        }
        else if (p_event->evt_type == APP_UART_TX_EMPTY)
        {
            init_uart(27, UART_PIN_DISCONNECTED);
            NRF_LOG_DEBUG("TX Empty");
        }
    }
    
    static void init_uart(uint32_t rx_pin, uint32_t tx_pin)
    {
        uint32_t err_code;
    
        const app_uart_comm_params_t comm_params =
        {
            rx_pin,
            tx_pin,
            RTS_PIN_NUMBER,
            CTS_PIN_NUMBER,
            APP_UART_FLOW_CONTROL_DISABLED,
            false,
    #if defined(UART_PRESENT)
            NRF_UART_BAUDRATE_115200
    #else
            NRF_UARTE_BAUDRATE_115200
    #endif
        };
    
        APP_UART_FIFO_INIT(&comm_params,
                           UART_RX_BUF_SIZE,
                           UART_TX_BUF_SIZE,
                           uart_error_handle,
                           APP_IRQ_PRIORITY_LOWEST,
                           err_code);
        APP_ERROR_CHECK(err_code);
    }
    
    int main(void)
    {
        .
        .
        .
        init_uart(UART_PIN_DISCONNECTED, 27);
        
        uint8_t cr = 5;
        NRF_LOG_INFO("Sent char %d", cr);
        while (app_uart_put(cr) != NRF_SUCCESS);
        nrf_delay_ms(2500);
        
        while (app_uart_get(&cr) != NRF_SUCCESS);
        nrf_delay_ms(2500);
        NRF_LOG_INFO("Received char %d\r\n", cr);
        .
        .
        .
    }

    This results in a fatal error from APP_ERROR_CHECK in init_uart(). Should I not be re-initializing app_uart in the UART event handler? 

Reply
  • Hi Jörgen,

    Thanks for the swift reply.

    I just tried your suggestion, where it currently looks like this:

    Master:

    static void init_uart(uint32_t rx_pin, uint32_t tx_pin);
    
    void uart_error_handle(app_uart_evt_t * p_event)
    {
        if (p_event->evt_type == APP_UART_COMMUNICATION_ERROR)
        {
            APP_ERROR_HANDLER(p_event->data.error_communication);
        }
        else if (p_event->evt_type == APP_UART_FIFO_ERROR)
        {
            APP_ERROR_HANDLER(p_event->data.error_code);
        }
        else if (p_event->evt_type == APP_UART_TX_EMPTY)
        {
            init_uart(27, UART_PIN_DISCONNECTED);
            NRF_LOG_DEBUG("TX Empty");
        }
    }
    
    static void init_uart(uint32_t rx_pin, uint32_t tx_pin)
    {
        uint32_t err_code;
    
        const app_uart_comm_params_t comm_params =
        {
            rx_pin,
            tx_pin,
            RTS_PIN_NUMBER,
            CTS_PIN_NUMBER,
            APP_UART_FLOW_CONTROL_DISABLED,
            false,
    #if defined(UART_PRESENT)
            NRF_UART_BAUDRATE_115200
    #else
            NRF_UARTE_BAUDRATE_115200
    #endif
        };
    
        APP_UART_FIFO_INIT(&comm_params,
                           UART_RX_BUF_SIZE,
                           UART_TX_BUF_SIZE,
                           uart_error_handle,
                           APP_IRQ_PRIORITY_LOWEST,
                           err_code);
        APP_ERROR_CHECK(err_code);
    }
    
    int main(void)
    {
        .
        .
        .
        init_uart(UART_PIN_DISCONNECTED, 27);
        
        uint8_t cr = 5;
        NRF_LOG_INFO("Sent char %d", cr);
        while (app_uart_put(cr) != NRF_SUCCESS);
        nrf_delay_ms(2500);
        
        while (app_uart_get(&cr) != NRF_SUCCESS);
        nrf_delay_ms(2500);
        NRF_LOG_INFO("Received char %d\r\n", cr);
        .
        .
        .
    }

    This results in a fatal error from APP_ERROR_CHECK in init_uart(). Should I not be re-initializing app_uart in the UART event handler? 

Children
No Data
Related