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

nrf_serial_read behaving strangely in polling mode

Hi there

For test purposes, I first implemented a simple serial reading & parsing function in polling mode of a gps device (sending @ 1 Hz).

void read_gps_tag(void)
{
	uint8_t cnt = 0;
	char uart_buf[GPS_NMEA_MAX_SIZE];   // Read UART buffer
	char c;                             // Read UART character
	ret_code_t ret;                     // Return value of the nrf_serial_read function
	bool reading = true;                // Reading flag
	char *p_str;                        // Pointer on the string comparison result
	while(reading) {
		ret = nrf_serial_read(&gps_uart, &c, sizeof(c), NULL, 1000);
		APP_ERROR_CHECK(ret);
		uart_buf[cnt++] = c;
		if(c == GPS_NMEA_STOP_CHAR) {
			if(uart_buf[0] == GPS_NMEA_START_CHAR) {
				static char comp[7] = "$GPRMC";
				p_str = strstr(uart_buf, comp);
				if(p_str != NULL) {
					strcpy(cur_tag.raw_tag, uart_buf);
					cur_tag.length = strlen(uart_buf);
					reading = false;
				}
			}
		cnt = 0;
		}
	}
}

Everything works fine when I call the function directly from the main(), e.g. like:

int main (void)
{
    // ...initializations...
    
    while(true) {
        read_gps_tag();
    }
}

But when I embed the function in the following code, it keeps stuck on reading

int main(void)
{
    // ...initializations...
    
    while (true)
    {
		if(ui_rec_start_req) {
			NRF_LOG_INFO("Start request received");
			card_status = sdc_init();
			if(card_status == RES_OK) {
				NRF_LOG_INFO("SD card init done.");
				ff_result = sdc_mount();
				if(ff_result == FR_OK) {
					NRF_LOG_INFO("SD card mounted.");
					read_gps_tag();
				}
				else {
					NRF_LOG_INFO("SD card init failed. Result: %d", ff_result);
					ui_sdc_init_cnt++;
				}
			}
			else {
				NRF_LOG_INFO("SD card check failed. Status: %d", card_status);
				ui_sdc_init_cnt++;
			}
			if(ui_sdc_init_cnt >= 3) {
				ui_rec_start_req = false;
			}
		}
    }
}

For information: the 'ui_rec_start_req' flag is set by interruption when a button is pressed. Everything works basically fine, except 'read_gps_tag' which stays stuck at 'nrf_serial_read(&gps_uart, &c, sizeof(c), NULL, 1000)'. Any idea?

Thanks in advance,

Sébastien

Parents Reply Children
  • With some more testing, it appears to be more like a random process and doesn't matter where the UART function call is.

    When I disable most of the initialization functions and run the UART function in loop (see picture), it works often but sometimes goes in timeout after a button reset.

    And when I uncomment ble_stack_init() (and therefore comment lfclk_init()), then the ratio change: the UART goes often in timeout (even when I increase the timeout value to 2000 ms) and works sometimes. The other functions apparently don't make any change to this behaviour.

    Finally: when the UART works after reset, it works all the time. When not, it never recovers and always goes to timeout, as if some startup initialization had failed.

    And by the way: the UART timeout seem to work even in polling mode!

    Configuration:

    NRF_SERIAL_DRV_UART_CONFIG_DEF(m_uart0_drv_config,
    	GPS_UART_RX_PIN, NRF_UART_PSEL_DISCONNECTED,
    	NRF_UART_PSEL_DISCONNECTED, NRF_UART_PSEL_DISCONNECTED,
    	NRF_UART_HWFC_DISABLED, NRF_UART_PARITY_EXCLUDED,
    	NRF_UART_BAUDRATE_9600, UART_DEFAULT_CONFIG_IRQ_PRIORITY);
    
    NRF_SERIAL_CONFIG_DEF(gps_config,
    	NRF_SERIAL_MODE_POLLING, NULL,
    	NULL, NULL, NULL);

    Polling:

    while(gps_uart_reading) {
    	ret_code_t ret = nrf_serial_read(&gps_uart, &c, sizeof(c), NULL, 1234);
    	DBG_TOGGLE(DBG1_PIN);
    	if(ret == NRF_ERROR_TIMEOUT) {
    		NRF_LOG_INFO("Timeout! Cancelling");
    		gps_uart_reading = false;
    		gps_uart_timeout = true;
    		break;
    	}
        parsing etc...

    ...and after 1.234 second, I get a timeout!

    Regards,
    Sébastien

  • Hello,

    Any clue here? I really don't know how to work around this issue...

  • What is the return from sizeof(c) (the actual value passed to the size parameter of nrf_serial_read)? Have you debugged the application inside nrf_serial_read, to see if it is receiving any bytes? I suppose if the size parameter is larger than 255, you can still get a timeout if enough bytes are received, or you will get the timeout error when all bytes are received.

  • sizeof(c) = 1 (printed after nrf_serial_read return). In case of a timeout, it's printed only once, then breaks. In case of normal behaviour, it comes until the whole tag has been found (either 39 or 71 times).

    Inside the nrf_serial_read, the timeout seem to appear when the 'serial_rx' function always return 0 (line 463 of nrf_serial.c). But it's difficult for me to debug here: first I don't know exactly where to place a breakpoint in a time-critical function, second the error is not completely reproducible and seems to appear more often when I connect my logic analyzer than when I let it run alone... could it be a pull-up issue?

  • I've just set a pull-up to the rx pin in nrf_drv_uart.c (line 119) and the timeout happens much less often with connected logic analyzer... but the issue has not completely disappeared.

Related