This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

FreeRTOS with libuarte: incompatibility between app_timer and app_timer_freertos?

Hello,

I intend to use libuarte under FreeRTOS together with the SoftDevice (SDK 17.1.0). An app_timer is used for the RX timeout. I think there might be an incompatibility problem between app_timer and app_timer_freertos.

My application initializes the libuarte as follows:

NRF_LIBUARTE_ASYNC_DEFINE( xLibUarteCOM0, 0, 1, NRF_LIBUARTE_PERIPHERAL_NOT_USED, NRF_LIBUARTE_PERIPHERAL_NOT_USED, 255, 3 );
xErrCode = nrf_libuarte_async_init( ( nrf_libuarte_async_t * )&xLibUarteCOM0, &nrf_libuarte_async_config, pvUartEvtHandler, ( void * )pxLibUarte );

The macro NRF_LIBUARTE_ASYNC_DEFINE creates xLibUarteCOM0 as follows:

static const nrf_libuarte_async_t xLibUarteCOM0 = 
{ 
	.p_rx_pool = &xLibUarteCOM0_rx_pool, 
	.p_rx_queue = &xLibUarteCOM0_rxdata_queue, 
	.p_rtc = 0, 
	.p_timer = 0, 
	.p_app_timer = &xLibUarteCOM0_app_timer, 
	.p_app_timer_ctrl_blk = &xLibUarteCOM0_app_timer_ctrl_blk, 
	.p_libuarte = &xLibUarteCOM0_libuarte, 
	.p_ctrl_blk = &xLibUarteCOM0ctrl_blk, 
	.rx_buf_size = 255, 
}; 

with p_app_timer_t being a pointer to (a pointer to) a variable of type app_timer_t:

static const app_timer_id_t xLibUarteCOM0_app_timer = &xLibUarteCOM0_app_timer_data; 

typedef struct
{
	nrf_sortlist_item_t         list_item;     /**< Token used by sortlist. */
	uint64_t                    end_val;       /**< RTC counter value when timer expires or @ref APP_TIMER_IDLE_VAL. */
	uint32_t                    repeat_period; /**< Repeat period (0 if single shot mode). */
	app_timer_timeout_handler_t handler;       /**< User handler. */
	void *                      p_context;     /**< User context. */
	NRF_LOG_INSTANCE_PTR_DECLARE(p_log)        /**< Pointer to instance of the logger object (Conditionally compiled). */
} app_timer_t;

The structure is then initialized by the macro as:

static app_timer_t xLibUarteCOM0_app_timer_data = 
{ 
	.end_val = 0xFFFFFFFFFFFFFFFFULL, 
}; 

In the FreeRTOS version of app_timer_create() called from nrf_libuarte_async_init(), xLibUarteCOM0_app_timer_data gets overlaid by a different structure. It is recasted to app_timer_info_t:

app_timer_info_t * pinfo = (app_timer_info_t*)(*p_timer_id);

/**@brief This structure keeps information about osTimer.*/
typedef struct
{
	void                      * argument;
	TimerHandle_t               osHandle;
	app_timer_timeout_handler_t func;
	/**
	 * This member is to make sure that timer function is only called if timer is running.
	 * FreeRTOS may have timer running even after stop function is called,
	 * because it processes commands in Timer task and stopping function only puts command into the queue. */
	bool                        active;
	bool                        single_shot;
}app_timer_info_t;

Without further initialization of the structure, app_timer_create() then checks the value of pinfo->active and fails with NRF_ERROR_INVALID_STATE if true.

The pinfo->active variable, however, is part of the pre-initialized 64-bit end_val and has the value 0xff which evaluates to true (!= 0). Hence, the initialization fails.

A possible work-around (although not very clean) is to initialize end_val with 0:

app_timer_t *p_xLibUarteCOM0_app_timer_data = *xLibUarteCOM0.p_app_timer;
p_xLibUarteCOM0_app_timer_data->end_val = 0x0ULL;

Does my analysis sound corrected or is there a another issue somewhere?

Thanks,

Norbert

  • Hi,

    You cannot use app_timer as it is as app_timer uses RTC1 which is the already used by freertos to keep its internal timers uptodate. If you want to use app_timer and app_timer_freertos together, you need to change the freertos to use the different timer. This is easy to achieve if you change the external\freertos\portable\CMSIS\nrf51\portmacro_cmsis.h from

    #define portNRF_RTC_REG        NRF_RTC1
    to 
    #define portNRF_RTC_REG        NRF_RTC2
    and also change
    #define portNRF_RTC_IRQn       RTC1_IRQn 
    to
    #define portNRF_RTC_IRQn       RTC2_IRQn
  • Hi Susheel,

    Sorry, I am a bit confused. By telling libuarte to use app_timer, I thought it really uses the FreeRTOS version of it (app_timer_freertos) which is clocked by the FreeRTOS systick.

    At least that is what I am trying to achieve. If it is not correct what I am doing, then how do I configure libuarte to use app_timer_freertos? NRF_LIBUARTE_ASYNC_DEFINE only proposes TIMER (HW), RTC (HW) or app_timer.

    Thanks

  • Since Freertos is using RTC1 by default, you can give NRF_CLI_LIBUARTE_TIMEOUT_RTC_INSTANCE as 2 inside NRF_LIBUARTE_ASYNC_DEFINE. I haven't tried the freertos libuarte myself, but if the libuarte has done all this correct with taking this RTC instance as a configurable thing, then it should work.

  • I don't think that this would work for me. I need two libuarte instances but there is only one RTC instance left. RTC0 is used for the SoftDevice, RTC1 provides the FreeRTOS systick which leaves only RTC2 to work with. Furthermore, I am not sure for which other purposes/peripherals I might need an RTC later so I want to conserve HW resources as much as possible.

  • OK, then i will not try to push you to use other instances of RTC then, in that case let us go to your initial efforts and look at the issue.

    I think the main issue here is that the helper macros in the NRF_LIBUARTE_ASYNC_DEFINE has not been designed to work with the freertos.

    so probably you can initialize p_app_timer pointing zero initialized structure of app_timer_info_t instead as a clean workaround.

Related