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

Serial library interrupt frequency.

We are trying to receive high speed data using UART. Currently our source is set to transmit an 8 byte packet once every second. 

I have initialised the serial port in IRQ mode and my baudrate is set to 921600. I have also set a GPIO pin to go high upon receiving an interrupt.

Am I correct in assuming that I should see an interrupt for every byte received? If so, why am I seeing my interrupts so delayed? What is the maximum frequency for interrupts? 

The logic analyser is capturing the incoming data on the RX line, and also the GPIO pin that is set on every "NRF_SERIAL_EVENT_RX_DATA" interrupt. 

My code is as follows:

#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>

#include "nrf.h"
#include "nrf_drv_clock.h"
#include "nrf_gpio.h"
#include "nrf_delay.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_drv_power.h"
#include "nrf_serial.h"
#include "app_timer.h"


#include "app_error.h"
#include "app_util.h"
#include "boards.h"

//Logging
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"

/** @file
 * @defgroup nrf_serial_example main.c
 * @{
 * @ingroup nrf_serial_example
 * @brief Example of @ref nrf_serial usage. Simple loopback.
 *
 */

#define OP_QUEUES_SIZE          3
#define APP_TIMER_PRESCALER     NRF_SERIAL_APP_TIMER_PRESCALER

//Buttons
static uint32_t button_state_1;
static uint32_t button_state_2;

//Payloads
#define payload_size 8
uint8_t tx_payload0[5] = {1,2,3,4,5};//{50,100,150,200,250};
uint8_t tx_payload[payload_size];
uint8_t rx_payload[8];

//RTC
#include "nrf_drv_rtc.h"
const nrf_drv_rtc_t rtc = NRF_DRV_RTC_INSTANCE(0); /**< Declaring an instance of nrf_drv_rtc for RTC0. */
uint32_t timer_old;
uint32_t timer_new;
uint32_t delta;

//Custom TX & RX pins
#define ctx_pin_number 3
#define crx_pin_number 4

char c;

static void sleep_handler(void)
{
    __WFE();
    __SEV();
    __WFE();
}

NRF_SERIAL_DRV_UART_CONFIG_DEF(m_uart0_drv_config,
                      crx_pin_number, ctx_pin_number,
                      RTS_PIN_NUMBER, CTS_PIN_NUMBER,
                      NRF_UART_HWFC_DISABLED, NRF_UART_PARITY_EXCLUDED,
                      NRF_UART_BAUDRATE_921600,
                      UART_DEFAULT_CONFIG_IRQ_PRIORITY);

/*
NRF_SERIAL_DRV_UART_CONFIG_DEF(m_uart0_drv_config,
                      RX_PIN_NUMBER, TX_PIN_NUMBER,
                      RTS_PIN_NUMBER, CTS_PIN_NUMBER,
                      NRF_UART_HWFC_DISABLED, NRF_UART_PARITY_EXCLUDED,
                      NRF_UART_BAUDRATE_921600,
                      UART_DEFAULT_CONFIG_IRQ_PRIORITY);
*/

#define SERIAL_FIFO_TX_SIZE 32
#define SERIAL_FIFO_RX_SIZE 32

NRF_SERIAL_QUEUES_DEF(serial_queues, SERIAL_FIFO_TX_SIZE, SERIAL_FIFO_RX_SIZE);


#define SERIAL_BUFF_TX_SIZE 1
#define SERIAL_BUFF_RX_SIZE 1

NRF_SERIAL_BUFFERS_DEF(serial_buffs, SERIAL_BUFF_TX_SIZE, SERIAL_BUFF_RX_SIZE);

NRF_SERIAL_UART_DEF(serial_uart, 0);

void clocks_start( void )
{
    // Start HFCLK and wait for it to start.
    NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
    NRF_CLOCK->TASKS_HFCLKSTART = 1;
    while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);
}

static void lfclk_config(void)
{
    ret_code_t err_code = nrf_drv_clock_init();
    APP_ERROR_CHECK(err_code);

    nrf_drv_clock_lfclk_request(NULL);
}

static void rtc_handler(nrf_drv_rtc_int_type_t int_type)
{
	//Do nothing. Interrupts are disabled anyway.
		
}


static void rtc_config(void)
{
    uint32_t err_code;

    //Initialize RTC instance
    nrf_drv_rtc_config_t config = NRF_DRV_RTC_DEFAULT_CONFIG;
    //config.prescaler = 4095;
    err_code = nrf_drv_rtc_init(&rtc, &config, rtc_handler);
    APP_ERROR_CHECK(err_code);

    //Power on RTC instance
    nrf_drv_rtc_enable(&rtc);
		//nrf_drv_rtc_int_disable(&rtc,);

}


static void serial_event_handler(struct nrf_serial_s const * p_serial,
nrf_serial_event_t event) 
{
    switch (event)
	{
	case NRF_SERIAL_EVENT_TX_DONE:
	    break;
	case NRF_SERIAL_EVENT_RX_DATA:
			nrf_gpio_pin_set(LED_2);
			//nrf_serial_read(&serial_uart, &rx_payload, sizeof(rx_payload), NULL, 0);
			nrf_queue_read(p_serial->p_ctx->p_config->p_queues->p_rxq, &c, sizeof(c));
			nrf_gpio_pin_clear(LED_2);
			//NRF_LOG_DEBUG("%s", rx_payload);
	    break;
	case NRF_SERIAL_EVENT_DRV_ERR:
	    break;
	case NRF_SERIAL_EVENT_FIFO_ERR:
	    break;
	default:
	    break;
	}
	
}

NRF_SERIAL_CONFIG_DEF(serial_config, NRF_SERIAL_MODE_IRQ,
                      &serial_queues, &serial_buffs,serial_event_handler, NULL);




uint32_t logging_init( void )
{
    uint32_t err_code;
    err_code = NRF_LOG_INIT(NULL);

    NRF_LOG_DEFAULT_BACKENDS_INIT();

    return err_code;
}

void gpio_init( void )
{

		nrf_gpio_cfg_output(LED_1);
		nrf_gpio_cfg_output(LED_2);

    // Workaround for PAN_028 rev1.1 anomaly 22 - System: Issues with disable System OFF mechanism
    nrf_delay_ms(1);

    bsp_board_init(BSP_INIT_LEDS);
}



int main(void)
{
    ret_code_t ret;

    ret = nrf_drv_clock_init();
    APP_ERROR_CHECK(ret);
    ret = nrf_drv_power_init(NULL);
    APP_ERROR_CHECK(ret);
		
    nrf_drv_clock_lfclk_request(NULL);
    ret = app_timer_init();
    APP_ERROR_CHECK(ret);
	
		//CLOCKS
		clocks_start();
		//timer
		rtc_config();
		//lfclk_config();
		gpio_init();
	
    ret = nrf_serial_init(&serial_uart, &m_uart0_drv_config, &serial_config);
    APP_ERROR_CHECK(ret);

		//Init Logging
		logging_init();
    static char tx_message[] = "Hello nrf_serial!\n\r";
		NRF_LOG_DEBUG("MM Serial initialised");

    /*ret = nrf_serial_write(&serial_uart,
                           tx_message,
                           strlen(tx_message),
                           NULL,
                           NRF_SERIAL_MAX_TIMEOUT);
    APP_ERROR_CHECK(ret);
		uint32_t timer;*/
    while (true)
    {
				NRF_LOG_PROCESS();
    }
}

/** @} */

Thanks for you help! 

  • Hi,

    The NRF_SERIAL_EVENT_RX_DATA is triggered on NRF_DRV_UART_EVT_RX_DONE, which is not the same as NRF_UARTE_EVENT_RXDRDY event. The NRF_UARTE_EVENT_RXDRDY event is not propagated to the serial_event_handler().

    At 921600 baud there is a byte received every 8.6us, likely the serial_event_handler() will not be able to execute that fast in any case. If you need to know when each byte is received you need to use the uarte driver directly, instead of the serial library.

    Best regards,
    Kenneth

  • Alternatively I would recommend to try nrf_libuarte_async driver for UARTE and lossless reception without HWFC. There are experimental_cli_libuarte and experimental_libuarte example in the SDK that show usage. They are labelled experimental due to lack of documentation but it has been thoroughly tested. The stability and quality of the libuarte is very goodThe libuarte library requires one TIMER, one RTC or TIMER, couple of PPI channels (~3 if recall correctly). It is using TIMER via PPI to count exact number of bytes received without stopping uarte.

    Best regards,
    Kenneth

  • Kenneth, libuarte_async looks like exactly what we need for a cellular module stack we're working on. Do you know if it's been tested with FreeRTOS? I'm not looking for guarantees, and I'm happy to do the legwork to test and do some light porting, but if you know for sure it doesn't work and it ain't gonna because X, Y, and Z, that would save us quite a bit of time.

    Thanks!

    - Chris.

Related