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;
}