Can't use EEFC on ATSAM4E when FreeRTOS is used

dcrocker wrote on Tuesday, March 27, 2018:

I am converting an existing application running on a ATSAM4E8E processor to use FreeRTOS. I am using the ARM_CM4F port of FreeRTOS 10.0.0.0 and static memory allocation. To get started, I am creating a single task in FreeRTOS that does everything. So the only FreeRTOS API calls I make are one call to xTaskCreateStatic() followed by a call to vTaskStartScheduler(). I have conditional code in my application so that I can compile with or without FreeRTOS.

When I compile without FreeRTOS, the code works (and has done so for many months).

When I compile with FreeRTOS, the code hangs when it tries to call Atmel Software Framework functions that access the EEFC (flash controller peripheral). For example, I have this code in the application startup sequence:

cpu_irq_disable();
const uint32_t rc = flash_read_unique_id(uniqueId, 4);
cpu_irq_enable();

Function flash_read_unique_id calls a RAMFUNC that accesses the EEFC. Disabling interrupts is necessary to prevent code in flash being executed due to an interrupt (in particular, SysTick) while the call is in progress. With FreeRTOS enabled (so that the code executes in the task), it hangs in that code. If I replace the call to flash_read_unique_id by the constant 1 then the code doesn’t hang, the initialisation completes and the firmware runs normally - until I do something that makes it try to use the EEFC again.

Any ideas? I tried replacing cpu_irq_disable/enable calls by taskENTER_CRITICAL/EXIT_CRITICAL but it made no difference. I also tried varying the stack size - but as the code runs perfectly as long as I don’t access the EEFC and the flash functions use very little stack, it can’t be due to stack overflow anyway.

For reference, here is the body of flash_read_unique_id and the function it calls. I have verified that the RAMFUNC is allocated in RAM - in fact it is at the very start of RAM.

uint32_t flash_read_unique_id(uint32_t *pul_data, uint32_t ul_size)
{
uint32_t uid_buf[4];
uint32_t ul_idx;

if (FLASH_RC_OK != efc_perform_read_sequence(EFC, EFC_FCMD_STUI,
		EFC_FCMD_SPUI, uid_buf, 4)) {
	return FLASH_RC_ERROR;
}

if (ul_size > 4) {
	/* Only 4 dword to store unique ID */
	ul_size = 4;
}

for (ul_idx = 0; ul_idx < ul_size; ul_idx++) {
	pul_data[ul_idx] = uid_buf[ul_idx];
}

return FLASH_RC_OK;

}

__no_inline
RAMFUNC
uint32_t efc_perform_read_sequence(Efc *p_efc,
uint32_t ul_cmd_st, uint32_t ul_cmd_sp,
uint32_t *p_ul_buf, uint32_t ul_size)
{
volatile uint32_t ul_status;
uint32_t ul_cnt;

#if (SAM3U4 || SAM3XA || SAM4SD16 || SAM4SD32 || SAM4C32 || SAM4CMS32|| SAM4CMP32)
uint32_t *p_ul_data =
(uint32_t *) ((p_efc == EFC0) ?
READ_BUFF_ADDR0 : READ_BUFF_ADDR1);
#elif (SAM3S || SAM4S || SAM3N || SAM3U || SAM4E || SAM4N || SAM4C || SAMG ||
SAM4CP || SAM4CM || SAMV71 || SAMV70 || SAMS70 || SAME70)
uint32_t *p_ul_data = (uint32_t *) READ_BUFF_ADDR;
#else
return EFC_RC_NOT_SUPPORT;
#endif

if (p_ul_buf == NULL) {
	return EFC_RC_INVALID;
}

p_efc->EEFC_FMR |= (0x1u << 16);

/* Send the Start Read command */

#if (SAM4S || SAM4E || SAM4N || SAM4C || SAMG || SAM4CP || SAM4CM ||
SAMV71 || SAMV70 || SAMS70 || SAME70)
p_efc->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FARG(0)
| EEFC_FCR_FCMD(ul_cmd_st);
#else
p_efc->EEFC_FCR = EEFC_FCR_FKEY(FWP_KEY) | EEFC_FCR_FARG(0)
| EEFC_FCR_FCMD(ul_cmd_st);
#endif
/* Wait for the FRDY bit in the Flash Programming Status Register
* (EEFC_FSR) falls.
*/
do {
ul_status = p_efc->EEFC_FSR;
} while ((ul_status & EEFC_FSR_FRDY) == EEFC_FSR_FRDY);

/* The data is located in the first address of the Flash
 * memory mapping.
 */
for (ul_cnt = 0; ul_cnt < ul_size; ul_cnt++) {
	p_ul_buf[ul_cnt] = p_ul_data[ul_cnt];
}

/* To stop the read mode */
p_efc->EEFC_FCR =

#if (SAM4S || SAM4E || SAM4N || SAM4C || SAMG || SAM4CP || SAM4CM ||
SAMV71 || SAMV70 || SAMS70 || SAME70)
EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FARG(0) |
EEFC_FCR_FCMD(ul_cmd_sp);
#else
EEFC_FCR_FKEY(FWP_KEY) | EEFC_FCR_FARG(0) |
EEFC_FCR_FCMD(ul_cmd_sp);
#endif
/* Wait for the FRDY bit in the Flash Programming Status Register (EEFC_FSR)
* rises.
*/
do {
ul_status = p_efc->EEFC_FSR;
} while ((ul_status & EEFC_FSR_FRDY) != EEFC_FSR_FRDY);

p_efc->EEFC_FMR &= ~(0x1u << 16);

return EFC_RC_OK;

}

rtel wrote on Tuesday, March 27, 2018:

Can’t see any obvious reason for this.

Is this code executing in the task or before you start the scheduler?

Is anything else using the RAM occupied by the RAM function? Perhaps if
there was a mistake in the linker script then without FreeRTOS it just
happened that there were no clashed in RAM, but with FreeRTOS and having
different memory requirements there is.

dcrocker wrote on Tuesday, March 27, 2018:

Hi Richard, thanks for responding. The code is executing within the task. I could move that particular piece of code to execute before I start the scheduler, but there are two other sections of code that need to use the EEFC (including one called from all the fatal exception handlers, to log the exception details to the user signature area of the flash) that also crash in the FreeRTOS build.

The linker memory maps for RAM look identical up to the point where RAM variables for FreeRTOS are allocated.

Where does FreeRTOS put the stack used by handlers? [EDIT: I think I found it in prvPortStartFirstTask(), it gets the top of stack from the first element of the vector table.]

Is there anything different about the execution context when it is operating as a task? Obvously it’s using a different stack, but as far as I can tell from the FreeRTOS code it’s still running in privileged mode. I have not enabled the MPU.

rtel wrote on Tuesday, March 27, 2018:

Hi Richard, thanks for responding. The code is executing within the
task. I could move that particular piece of code to execute before I
start the scheduler, but there are two other sections of code that need
to use the EEFC (including one called from all the fatal exception
handlers, to log the exception details to the user signature area of the
flash) that also crash in the FreeRTOS build.

I was not recommending moving it to before the scheduler is started, I
was just wanting to know if it was simply adding the FreeRTOS code in
that was causing the issue, or actually running in the context of a task
that was the issue.

The functions being called do not look alarming in any way so it is
curious - we need to work out what the issue is though.

Out of curiosity - if you were to create another RAM function that is
not doing anything with the flash - does it still crash? If so, then it
would seem to be just the act of running from RAM that was the issue.

Where does FreeRTOS put the stack used by handlers?

Handlers use the stack that is otherwise allocated to main() - otherwise
that RAM is not recoverable after the scheduler has started - it does
mean you loose any variables declared in main() though but there is no
way of returning to main() anyway.

dcrocker wrote on Tuesday, March 27, 2018:

Thanks again. I made some progress: I added code to check whether the contents of the relocate segment in ram (which includes the ramfunc) still matches the original in flash that it is initialised from. It revealed that there is corruption in that memory area, starting with the very first byte of it (which is the very first byte of RAM). I also used vTaskGetInfo() to check that I am not running out of task stack, and added a separate check that there is plenty of handler stack space left. Now I just need to find the source of the memory corruption.

dcrocker wrote on Tuesday, March 27, 2018:

More data: the corruption is 3 dwords starting at the beginning of RAM:
first dword is 1
second dword is the address of the array that provides the stack for the task I create
third dword is the address of the StaticTask_t obkect that I provide for the main task

dcrocker wrote on Tuesday, March 27, 2018:

I found a solution. I noticed that the corruption matched the last 3 parameters passed to xTaskCreateStatic(). So it occurred to me that the compiler might be storing those parameters at the start of RAM instead of on the stack. I had declared the function that calls xTaskCreateStatic() and vTaskStartScheduler() with attribute “naked” on the grounds that it never returns, therefore it doesn’t need to save/restore any registers. I removed the “naked” attribute and the corruption is gone. I guess I don’t completely understand what that attribute does.

rtel wrote on Wednesday, March 28, 2018:

Thanks for reporting back.

Using the naked attribute will prevent the compiler from inserting any
function prelude code - the asm code that executes to set up a stack
from before any of the function’s C code executes. That is definitely a
bad thing if any stack is used at all, which is will be in the function,
as stack accesses are then basically uninitialised.