CAN message gets corrupt inside a FreeRTOS task

I have tried

	if ( xTaskCreate ( main_CSP_task, "main_CSP_task", **30000**/*TASK_STACK_SIZE*/, NULL, TASK_PRIORITY, main_CSP_task_TH ) != pdPASS )
		while(1);

And still it fails! And 30000 means a stack of 30000*4 bytes.

configASSERT is defined in FreeRTOSConfig.h as:

#define configASSERT(x)                                                                                                \
	if ((x) == 0) {                                                                                                    \
		taskDISABLE_INTERRUPTS();                                                                                      \
		for (;;)                                                                                                       \
			;                                                                                                          \
	}

Also in FreeRTOSConfig.h configCHECK_FOR_STACK_OVERFLOW is defined as:

#ifndef configCHECK_FOR_STACK_OVERFLOW
#define configCHECK_FOR_STACK_OVERFLOW 2
#endif

I have no optimization, -O0, that for loop causes a delay of about 500ms. I just use a for loop because this CANtest function is also used outside FreeRTOS, before calling vTaskStartScheduler().
Nevertheless CANtest() will not make to the final code. I just created it because I’m having the same corruption when I run the real code, and I was able to realize that this problem only happens when FreeRTOs is running. It doesn’t happen before starting the scheduler.

Are you sure that the delay really works ?
At least you should do the volatile i trick to ensure the loop is executed as expected.
Or you write your own reliable (microsecond) delay() function.
For FreeRTOS testing better just try/use xTaskDekay.
From the code you posted I guess Txfinished is set by the ISR (caling the callback), right ? This flag should also be declared volatile. Otherwise the code may or may not work.

Finally the problem might be in the ISRs and their interrupt priorities.
If the interrupt priority is set that it’s covered by FreeRTOS configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY to make use of FreeRTOS API calls in those ISRs their interrupts get disabled for a short period of time when FreeRTOS enters a critical section either internally or by application code.
That’s a difference between running the test before and after the scheduler was started.
If you currently don’t use any FreeRTOS API in the ISRs try setting the priorities higher (numerically lower) than configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY.
Do you have very tight ISR/interrupt timing requirements ?

yes I can see that it generates a delay.
I have a scope connected to the CANbus.
It works both in FreeRTOS and outside FreeRTOS.
Due to the callback nature of the CAN API even when the delay is 0 it works fine.

static volatile uint8_t Txfinished = false;

void CAN_1_tx_callback_(struct can_async_descriptor *const descr)
{
	Txfinished = true;
}

while (1)
{
		Txfinished = false;
		can_async_write(&CAN_1, &msgTx);

		while (!Txfinished);
}

The Txfinished variable does the trick!
It’s just the data that becomes corrupt.

I thought about the priorities and I’m using NVIC_SetPriority

NVIC_SetPriority ( MCAN1_INT0_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );
NVIC_SetPriority ( MCAN1_INT1_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );

Is this correct? thanks

Yes. With this setting the interrupts have the highest possible priority covered by FreeRTOS.
Cortex-M interrupt priorities are not easy to get right.
IMO this post Understanding priority levels of ISR and FreeRTOS APIs - #16 by aggarg contains a good and easy to understand explanation. This is also a good posting.

Hi

I see that Atmel library is doing some ‘critical’ stuff when the CAN interface is being initialised!


void atomic_enter_critical(hal_atomic_t volatile *atomic)
{
	*atomic = __get_PRIMASK();
	__disable_irq();
	__DMB();
}

/**
 * \brief Exit atomic section
 */
void atomic_leave_critical(hal_atomic_t volatile *atomic)
{
	__DMB();
	__set_PRIMASK(*atomic);
}


#define MCAN_CRITICAL_SECTION_ENTER() CRITICAL_SECTION_ENTER()
#define MCAN_CRITICAL_SECTION_LEAVE() CRITICAL_SECTION_LEAVE()

#define CRITICAL_SECTION_ENTER()  \
	{   volatile hal_atomic_t __atomic;		atomic_enter_critical(&__atomic); 

#define CRITICAL_SECTION_LEAVE()  \
	atomic_leave_critical(&__atomic); }

static inline void hri_mcan_write_TXBC_reg(const void *const hw, hri_mcan_txbc_reg_t data)
{
	MCAN_CRITICAL_SECTION_ENTER();
	((Mcan *)hw)->MCAN_TXBC = data;
	MCAN_CRITICAL_SECTION_LEAVE();
}

static inline void hri_mcan_clear_TXBC_reg(const void *const hw, hri_mcan_txbc_reg_t mask)
{
	MCAN_CRITICAL_SECTION_ENTER();
	((Mcan *)hw)->MCAN_TXBC &= ~mask;
	MCAN_CRITICAL_SECTION_LEAVE();
}

static inline void hri_mcan_toggle_TXBC_reg(const void *const hw, hri_mcan_txbc_reg_t mask)
{
	MCAN_CRITICAL_SECTION_ENTER();
	((Mcan *)hw)->MCAN_TXBC ^= mask;
	MCAN_CRITICAL_SECTION_LEAVE();
}

Can this somehow interfere with FreeRTOS?
Although this initialisation takes place before the FreeRTOS scheduler is started!

thanks

I think using multiple, different implements for critical sections is problematic.
I wonder if the Atmel lib is intended to be used together with FreeRTOS.
FreeRTOS provides taskENTER/EXIT_CRITICAL_FROM_ISR() for critical sections in ISRs and without the FROM_ISR suffix for task code.
Maybe the atmel specific critical sections are also used later on when using their driver from the task. This might be a problem since FreeRTOS and the driver code could both manipulate the (low level) PRIMASK.

I have created a request for support with Atmel regarding this. Maybe they have some explanation for what is happening.

thanks for the support.

FreeRTOS manipulates the BASEPRI register - which just masks interrupts below a certain logical priority. The code from Atmel is manipulating PRIMASK, which is effectively disabling all interrupts. That in itself should not be a problem for FreeRTOS.

A couple of other thoughts - where is msgTx declared? Make sure it is not on the stack of main() as that stack will no longer be in context once the scheduler starts and is actually re-claimed for use as the interrupt stack.

What is the revision number of the Cortex-M7 core? There is a specific FreeRTOS port for r0p1 cores that works around some silicon bugs in regards to how interrupt disabling works. If you have an r0p1 core then make sure you use that specific version, otherwise you should be able to use the Cortex-M4F kernel port.

@rtel

called in main_CSP_task. That should be ok.

The functions that call the critical enter and leave are I believe only used during initialisation of the Atmel CPU, just after entering main.

int main(void)
{
	/* Initializes MCU, drivers and middleware */
	atmel_start_init();       <<== Calls to critical enter and leave are made here

	/* Replace with your application code */
	while (1)
	{
		extern int main_CSPv71(void);

		main_CSPv71();

I’m using a ATSAMV71-XULT board which has a ATSAMV71Q21 AAB processor.
The FreeRTOS was taken from Atmel Start and it’s version 10.0.0

I can send you the file port.c that I have. How can I attach a file in the forum?

Another point - How many other tasks do you have? The reason I ask is to determine the possibility of the task calling CAN1test getting interrupted at a point where it should not have been. An easy way to determine can be to raise main_CSP_task priority.

Thanks.

At this moment main_CSP_task is the only task running.
The other tasks are created later on, but since CAN1test() is in a forever loop it doesn’t end.

Did you try raising it’s priority?

Also, do ISR for MCAN1_INT0_IRQn and MCAN1_INT1_IRQn use any FreeRTOS API? If not, you can increase their priority as well.

Hi
thanks for the suggestions.

The CAN ISR does not use any FreeRTOS API, it sets a flag only.

void CAN_1_tx_callback_(struct can_async_descriptor *const descr)
{
	Txfinished = true;
}

I have changed the CAN ISR priorities from:

NVIC_SetPriority ( MCAN1_INT0_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );
NVIC_SetPriority ( MCAN1_INT1_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );

to:

NVIC_SetPriority ( MCAN1_INT0_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY +1 );
NVIC_SetPriority ( MCAN1_INT1_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY +1 );

But no changes in the outcome.

Use configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY -1 for Cortex-M NVIC to bump the priority (above the FreeRTOS covered range).

Changed to:

NVIC_SetPriority ( MCAN1_INT0_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY -1 );
NVIC_SetPriority ( MCAN1_INT1_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY -1 );

Still the same result, all CAN data comes out corrupted.