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

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

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

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

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

    Yes, that seems to be the case. Would be nice if the SDK design team would also consider FreeRTOS as on one hand libuarte is the recommended UARTE API (AFAIK) and FreeRTOS is a supported RTOS.

    For the time being I will continue with the workaround. With my prototype build I cannot yet test RX but the TX seems to work.

    I will continue this thread in a couple of days if there are further incompatibility issues.

    Thanks,

    Norbert

  • Thanks Nobert. 

    Yes, that macro clearly needs a fix but I am not sure that will be prioritized soon as most of the team is working on nRF Connect SDK. I will in any case create an internal ticket as your use case and request make sense.

  • Just a quick update: I got the libuarte running with two instances (one for each physical UART) and FreeRTOS timers. I implemented the work-around mentioned above. So far, I did not come across any other issues.

    Note that the second libuarte instance so far has only been tested in TX which means that the second timer instance didn't do anything really.

  • Thanks for verifying this Norbert.

    This seems to be a feature request to make the macros compatible with external RTOS. To be very transparent, this might not be prioritized as feature requests are frozen on nRF5 based SDK. 

    Your description and conclusion with very good details makes this thread very valuable to others who might encounter this. Thanks again for your contributions and coming back here after so many days to give the final touches to this thread.

Related