How to add RS‑485 DE pin control to console/shell UART on nRF52840?

Hello,

On my board I implemented an RS-485 interface using the ST4E1216IDT transceiver. The DE (Driver Enable) and RE (Receiver Enable) pins are tied together and connected to a pin (de pin) of the nRF52840, in order to act as a tx data enable pin. On my application I am able to use the RS-485 UART by setting the de pin HIGH just before transmission, and then LOW on UART_TX_DONE event. Using this, I have validated that by board is operational.

Bellow is a code snippet that described this operation:

/* UART Callback to handle transmission completion */
static void uart_cb(const struct device *dev, struct uart_event *evt, void *user_data)
{
    switch (evt->type) {
    case UART_TX_DONE:
        /* Set DE pin LOW when transmission is finished */
        gpio_pin_set_dt(&uart_depin_dev, 0);
        break;
    default:
        break;
    }
}

    // Set DE pin HIGH to enable the transmitter
    gpio_pin_set_dt(&uart_depin_dev, 1);

    // Start asynchronous UART transfer
    ret = uart_tx(uart, tx_buf, sizeof(tx_buf), SYS_FOREVER_MS);

What I would like to achieve is to connect the zephyr console and the shell on that UART (RS-485). In order to do that the UART should support a DE hw control pin, because the backend should change the state of the DE pin depending on transmitting or receiving, since the RS-485 is a half duplex serial protocol.

Is there a way to achieve the console and shell UART to have an RS-485 operation.

Thank you in advance

Avgerinos

  • You cant use UART shell directly here. 

    But there is also the dummy shell backend. Mcumgr subsystem uses that to tunnel shell commands over the mucmgr (smp) protocol - you may be able to do something roughly similar with your rs485 operations.

  • You cannot make console/shell toggle the DE pin with nRF52840 without changes to the uarte driver and possible the dts property of the uarte. Maybe you can use an rs-485 with auto direction capability so that the uart part remains the same as what nordic chips can support.

  • Hello,

    I tried your suggestion of using an RS-485 with auto direction capability and it worked.

    More specifically I used the THVD1426DR (RS-485 Transceivers with Auto-direction Control) from Texas instruments and found out that the Zephyr shell is working as well as the MCUmgr on downloading a file with no issues, through the RS-485 half duplex connection.

    Thank you   for your suggestion!

  • I had the same problem and managed to solve it using the PPI (DPPI on nRF54L).
    Simply connect the UARTE TX_READY to the SUBSCRIBE_SET and the TX_END to SUBSCRIBE_CLR of an unused GPIOTE instance.
    No need for any changes in the DT or drivers.

    Here's how I achieved it on the nRF54L, it should not be difficult to port to the nRF52:

    static int enable_uart_de(void)
    {
        // Assert P1.02/UART_DE when transmitting on UARTE21
    
        NRF_UARTE21->PUBLISH_DMA.TX.READY = (1 << UARTE_PUBLISH_DMA_TX_READY_CHIDX_Pos) |
                                            (UARTE_PUBLISH_DMA_TX_READY_EN_Enabled << UARTE_PUBLISH_DMA_TX_READY_EN_Pos);
        NRF_UARTE21->PUBLISH_DMA.TX.END   = (2 << UARTE_PUBLISH_DMA_TX_END_CHIDX_Pos) |
                                            (UARTE_PUBLISH_DMA_TX_END_EN_Enabled   << UARTE_PUBLISH_DMA_TX_END_EN_Pos);
    
        NRF_GPIOTE20->SUBSCRIBE_SET[5] = (1 << GPIOTE_SUBSCRIBE_SET_CHIDX_Pos) |
                                         (GPIOTE_SUBSCRIBE_SET_EN_Enabled << GPIOTE_SUBSCRIBE_SET_EN_Pos);
        NRF_GPIOTE20->SUBSCRIBE_CLR[5] = (2 << GPIOTE_SUBSCRIBE_CLR_CHIDX_Pos) |
                                         (GPIOTE_SUBSCRIBE_CLR_EN_Enabled << GPIOTE_SUBSCRIBE_CLR_EN_Pos);
        NRF_GPIOTE20->CONFIG[5]        = (GPIOTE_CONFIG_MODE_Task   << GPIOTE_CONFIG_MODE_Pos)|
                                         (GPIOTE_CONFIG_OUTINIT_Low << GPIOTE_CONFIG_OUTINIT_Pos) |
                                         (2 << GPIOTE_CONFIG_PSEL_Pos) |
                                         (1 << GPIOTE_CONFIG_PORT_Pos);
    
        NRF_DPPIC20->CHENSET = (DPPIC_CHENSET_CH1_Enabled << DPPIC_CHENSET_CH1_Pos);
        NRF_DPPIC20->CHENSET = (DPPIC_CHENSET_CH2_Enabled << DPPIC_CHENSET_CH2_Pos);
        
        return 0;
    }
    
    SYS_INIT(enable_uart_de, EARLY, 20);
    

Related