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

app_uart_put() before NVIC_SystemReset()

Hi,

I'm trying to send out 3 bytes just before I reset the chip. I am using nRF51, SD 130 1.0 and SDK v10.0.0. UART works well in other parts of code.

My original solution was:

    app_uart_put(0x01);
	app_uart_put(0x02);
	app_uart_put(0x03);
	
	app_uart_flush();	
	NVIC_SystemReset();

but I only see 0x01 sent out. So the reset must be happening too fast. I tried multiple versions of above snippet, trying to send out all bytes before reset, but none works. This one is very hardcore and I really have no explanation why I see only first byte, but not others:

    app_uart_put(0x01);
	nrf_delay_ms(1);
	app_uart_put(0x02);
	nrf_delay_ms(1);
	app_uart_put(0x03);
	nrf_delay_ms(1);
	
	app_uart_flush();
	
	nrf_delay_ms(500);		
	NVIC_SystemReset();

What is happening here? How can I send out three bytes via UART before reset?

  • Hi

    In the first solution I think it is pretty obvious that you get an overflow. app_uart_put() is a non-blocking function as documented in app_uart.h. This means that you can't call it one after another like that before you are certain the first byte is transmitted. The first byte, however should be transferred without a problem.

    Regarding the second solution; what baudrate do you use? If you use e.g. 9600 the transmission of a byte will actually take ~1 ms. So with only 1 ms pause you might still get an overflow. It works on my system though. Did you try longer pauses?

    You can wait until the UART is ready like this:

    while(app_uart_put('a'))
       ;
    while(app_uart_put('b'))
       ;
    while(app_uart_put('c'))
       ;
    

    although this will block your application if something goes wrong so it is not very elegant. So the best thing would probably be to look into app_uart_fifo which allows you to send strings.

  • I don't think I should get overflow because I am already using app_fifo:

    uint32_t app_uart_put(uint8_t byte)
    {
        uint32_t err_code;
    		
    	err_code = app_fifo_put(&m_tx_fifo, byte);
        if (err_code == NRF_SUCCESS)
        {
    	    // The new byte has been added to FIFO. It will be picked up from there
            // (in 'uart_event_handler') when all preceding bytes are transmitted.
            // But if UART is not transmitting anything at the moment, we must start
            // a new transmission here.
            if (!nrf_drv_uart_tx_in_progress())
            {
                // This operation should be almost always successful, since we've
                // just added a byte to FIFO, but if some bigger delay occurred
                // (some heavy interrupt handler routine has been executed) since
                // that time, FIFO might be empty already.
                if (app_fifo_get(&m_tx_fifo, tx_buffer) == NRF_SUCCESS)
                    err_code = nrf_drv_uart_tx(tx_buffer, 1);
            }
        }
    	
        return err_code;
    }
    

    And even with your solution (while) only first byte gets transmitted. I use 115200 baudrate and I tried with longer pauses (5s).

    What did work is to start the timer in-place of NVIC_SystemReset() and then calling reset from there but it seems like an overkill.

  • I've posted my comment in the form of answer because I couldn't fit all the contents here.

  • I am having nRF52840, SDK15.3 and using Keil uVision5.

    I am having the same problem. I want to transmit 2 bytes. after transmitting one, system goes to breakpoint condition in debug mode. No API after this is executed, even simple delay function.

    while(app_uart_put(MSB) = !NRF_SUCCESS);

    I tried this way also but problem is still there.

    Looking for help!

Related