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

nRF52: Set UART Break on Tx line

Hello,

I am using the nRF52832 Development Kit platform w/ nRF Connect SDK.

I have an application using UART which is configured to talk LIN to a SN65HVDA100 package https://www.ti.com/lit/ds/symlink/sn65hvda100-q1.pdf

Wanting to setup multiple Development Kits so 1 is the Master and all the rest are configured as Slaves.

When running as a LIN Master, the Master must hold the LIN Bus Low for 14 bits minimum.

I have the UART configured with 8 bit word size.

My question is, is there any available Zephyr UART API call to create a UART Break (hold the Tx pin low for 14 bits minimum)?

No obvious answer lurks in the API docs https://docs.zephyrproject.org/apidoc/latest/group__uart__interface.html

Parents
  • Hi,

    I can't say about Zephyr API but the simple trick that works is to lower the baudrate for a short period and send a 0x00 character.

  • Thanks for the suggestion. It would be nice if it were that simple.

    However, I have an overlay file which declares the uart0 with current-speed as 19200.

    arduino_serial: &uart0 {
        status = "okay";
        compatible = "nordic,nrf-uart";
        current-speed = <19200>;
        tx-pin = <17>;
        rx-pin = <16>;
    };

    When attempting to configure the baud rate at runtime, using the uart_configure() function with uart_config property baudrate set to say 4800 is accepted. Then writing a zero to the uart peripheral, the baud rate still looks to be 19200 when looking at the UART Tx with an oscilloscope, not the updated 4800.

    FWIW, I am using interrupt driven UART.

    CONFIG_SERIAL=y
    CONFIG_UART_INTERRUPT_DRIVEN=y
    CONFIG_UART_LINE_CTRL=n

    New question: Is it even possible to change the UART baud rate at run time for Zephyr / nRF Connect SDK?

    The baud rate has been statically declared in the .overlay file with a set value, calling uart_configure() with another baud rate seems to have no effect. Would using asynchronous UART implementation work?

  • To actually change baudrate, the UART should be disabled and re-enabled again. If Zephyr doesn't do this in uart_configure(), the baudrate will not be updated. You can check this by resetting port via ENABLE register directly after changing baudrate:

    NRF_UARTE0->ENABLE = (UARTE_ENABLE_ENABLE_Disabled << UARTE_ENABLE_ENABLE_Pos);
    (void) (NRF_UARTE0->ENABLE);
    NRF_UARTE0->ENABLE = (UARTE_ENABLE_ENABLE_Enabled << UARTE_ENABLE_ENABLE_Pos);

Reply
  • To actually change baudrate, the UART should be disabled and re-enabled again. If Zephyr doesn't do this in uart_configure(), the baudrate will not be updated. You can check this by resetting port via ENABLE register directly after changing baudrate:

    NRF_UARTE0->ENABLE = (UARTE_ENABLE_ENABLE_Disabled << UARTE_ENABLE_ENABLE_Pos);
    (void) (NRF_UARTE0->ENABLE);
    NRF_UARTE0->ENABLE = (UARTE_ENABLE_ENABLE_Enabled << UARTE_ENABLE_ENABLE_Pos);

Children
  • Thanks Dmitry.

    I was able to successfully toggle the baud rate at run time from 19200kbps to 9600kps back to 19200kbps again. 

    Attached working code snippet of re-configure and toggling UART at run-time.

    #define LIN_BAUD_RATE_NORMAL       19200
    #define LIN_BAUD_RATE_BREAK        9600
    
    #ifdef LIN_MASTER
    static void lin_driver_toggle_uart_enable_register(void)
    {
        NRF_UART0->ENABLE = (UART_ENABLE_ENABLE_Disabled << UART_ENABLE_ENABLE_Pos);
        (void) (NRF_UART0->ENABLE);
        NRF_UART0->ENABLE = (UART_ENABLE_ENABLE_Enabled << UART_ENABLE_ENABLE_Pos);
    }
    #endif
    
    #ifdef LIN_MASTER
    static void lin_driver_set_slow_baud_rate(void)
    {
        int ret;
    
        uart_service.cfg.baudrate = LIN_BAUD_RATE_BREAK;
        ret = uart_configure(uart_service.dev, &uart_service.cfg);
        if (ret != 0)
        {
            //DEBUGGING:
            //DEBUG_PUSH_PRINT("UART LIN> uart_configure() error = %d", ret);
        }
    
        lin_driver_toggle_uart_enable_register();
    
        //DEBUGGING:
        //DEBUG_PUSH_PRINT("REM Baud %ubps (Slow)", LIN_BAUD_RATE_BREAK);
    }
    #endif  // LIN_MASTER
    
    #ifdef LIN_MASTER
    static void lin_driver_set_normal_baud_rate(void)
    {
        int ret;
    
        uart_service.cfg.baudrate = LIN_BAUD_RATE_NORMAL;
        ret = uart_configure(uart_service.dev, &uart_service.cfg);
        if (ret != 0)
        {
            //DEBUGGING:
            //DEBUG_PUSH_PRINT("UART LIN> uart_configure() error = %d", ret);
        }
    
        lin_driver_toggle_uart_enable_register();
    
        //DEBUGGING:
        //DEBUG_PUSH_PRINT("REM Baud %ubps (Normal)", LIN_BAUD_RATE_NORMAL);
    }
    #endif
    
    static int lin_driver_uart_setup(void)
    {
        int ret;
    
        // Initialise
        uart_service.dev = device_get_binding("UART_0");
        if (uart_service.dev == NULL)
        {
            DEBUG_PUSH_PRINT("UART LIN> Error device_get_binding() failed");
            return -ENODEV; // Value = 19
        }
    
        // Configure
        uart_service.cfg.baudrate = LIN_BAUD_RATE_NORMAL;
        uart_service.cfg.parity = UART_CFG_PARITY_NONE;
        uart_service.cfg.stop_bits = UART_CFG_STOP_BITS_1;
        uart_service.cfg.data_bits = UART_CFG_DATA_BITS_8;
        uart_service.cfg.flow_ctrl = UART_CFG_FLOW_CTRL_NONE;
        ret = uart_configure(uart_service.dev, &uart_service.cfg);
        if (ret != 0)
        {
            DEBUG_PUSH_PRINT("UART LIN> uart_configure() error = %d", ret);
            return ret;
        }
    
        // Receive
        uart_irq_callback_set(uart_service.dev, lin_driver_uart_cb);
        uart_irq_rx_enable(uart_service.dev);
    
        return 0;
    }

Related