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
  • Hi,

    Have you checked the UART lines using logic analyzer, to see if the GPS is actually sending data? Note that the timeouts are not functional in polling mode, nrf_serial_read will block until it have received the requested number of bytes. If you are receiving data from GPS, is the function blocking on first iteration of the loop, or does it do one/more iterations before it hangs?

    Best regards,
    Jørgen

  • Hi Jørgen

    Yes my GPS sends all the time, every 1 second like shown on the picture:

    Since my receiver waits for every single char, it should return at worst case after ~750 ms. But when it decided to block, it blocks from the beginning. On the same way, when it works (after a reset), it does ad aeternam (or almost ;-) ).

    Meanwhile I have read that UART doesn't timeout in polling mode and start a app_timer just before the while(reading) loop. On timeout, I set the reading flag (which is now a global) to false and it works fine... But basically, the same things happen: OK in the main function, NOT OK after an interruption.

    Best,

    Sébastien

  • Does it also not work if you remove the SD card related code and only keep the flag that you set from the interrupt, or does this not matter?

  • 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.

Reply Children
Related