I'm trying to develop a simple multi-core application with freeRTOS.
The idea is simple: core Z4_0 controls the LEDs and waits for signals from other tasks that run on other cores. After receiving a signal, core Z4_0 blinks an LED.
The inter-task communication is done with queues. I set up a shared memory segment in the linker file, and put the QueueHandle_t at the memory location accessible for all other cores. The application starts a task on the first core (Z4_0) that controls the LEDs. This task reads from the queue. The other task, which runs on a different core, packs an integer onto the queue. This integer is then being read by the task running on core 1 (Z4_0) and a diode lights up. There are three cores in the project, each core runs a freeRTOS, but one core has no tasks (meaning the task scheduler runs the 'idle' task).
The problem is that this only works only if the sending task (producer task, task that packs the values onto the queue) is located on the third core - Z2. If the sending task is located on the second core (Z4_1) then the application doesn't work (no LEDs blink).
With debugging I can decide which core should start first. If I put the sending task onto the second core, and then unfreeze it as the LAST core, the application works fine. However, if I unfreeze the third, empty core as the last one, the application doesn't work.
It seems that the third core undergoes some initialization that disrupts the functioning of the second core. I don't understand it, because the core is 'empty', it runs only the task scheduler with idle task. Furthermore, only the first core (Z4_0) has any pins enabled - there should be no conflict with the hardware.
How to develop an application that uses all three cores, and is independent from the startup sequence?
I am including memory maps and code snippets.
CORE Z4_0:
- Memory map of /Project_Settings/Linker_Files/linker_flash.ld:
/* Define SRAM */
SRAM_BASE_ADDR = DEFINED(__sram_base_addr__) ? __sram_base_addr__ : 0x40000000;
SRAM_SIZE = DEFINED(__sram_size__) ? __sram_size__ : 256K;
MEMORY
{
flash_rchw : org = 0x00FA0000, len = 0x4
cpu0_reset_vec : org = 0x00FA0000+0x10, len = 0x4
cpu1_reset_vec : org = 0x00FA0000+0x14, len = 0x4
cpu2_reset_vec : org = 0x00FA0000+0x04, len = 0x4
rappid_boot_data : org = 0x00FA0000+0x08, len = 0x8
m_text : org = FLASH_BASE_ADDR, len = FLASH_SIZE
m_data : org = 0x40001000, len = 252K
/************************************************/
shared : org = 0x40000000, len = 4k
/************************************************/
}
- main.c snippet
/* toggles the LED received from the task */
void vToggleLEDonNotification(void* pvParamaters)
{
//8 LEDs: pa4, pa0, pj4,ph5,pc4,ph13,pa7,pa10
while(1){
uint32_t receivedLEDno;
/* read the LED number from the queue */
if(xQueueReceive( *LEDQueue, &receivedLEDno, 500 ) == pdTRUE){
switch(receivedLEDno){
case 0: //PA4
PINS_DRV_TogglePins(PTA, 0x10) ;
break;
case 1: //PA0
PINS_DRV_TogglePins(PTA, 0x1) ;
break;
case 2: //PJ4
PINS_DRV_TogglePins(PTJ, 0x10) ;
break;
default:
break;
}
}
}
}
/*place the queue in commonly shared piece of memory */
QueueHandle_t *LEDQueue =(QueueHandle_t*) 0x40000000;
int main(void)
{
#ifdef PEX_RTOS_INIT
PEX_RTOS_INIT(); /* Initialization of the selected RTOS. Macro is defined by the RTOS component. */
#endif
/* Initialize and configure clocks */
CLOCK_SYS_Init(g_clockManConfigsArr, (uint8_t)CLOCK_MANAGER_CONFIG_CNT, g_clockManCallbacksArr, (uint8_t)CLOCK_MANAGER_CALLBACK_CNT);
CLOCK_SYS_UpdateConfiguration(0U, CLOCK_MANAGER_POLICY_AGREEMENT);
/* Initialize pins */
PINS_DRV_Init(NUM_OF_CONFIGURED_PINS, g_pin_mux_InitConfigArr);
/* queue used to send LED numbeers from one task to another */
*LEDQueue = xQueueCreate( 10, sizeof(uint32_t) );
xTaskCreate(vToggleLEDonNotification, "ToggleLEDonNotificationTask", 128U, NULL, 2, NULL);
vTaskStartScheduler();
#ifdef PEX_RTOS_START
PEX_RTOS_START(); /* Startup of the selected RTOS. Macro is defined by the RTOS component. */
#endif
/*** Processor Expert end of main routine. DON'T MODIFY THIS CODE!!! ***/
for(;;) {
if(exit_code != 0) {
break;
}
}
return exit_code;
} /*** End of main routine. DO NOT MODIFY THIS TEXT!!! ***/
CORE Z2:
- Memory map of /Project_Settings/Linker_Files/linker_flash.ld:
/* Define SRAM */
SRAM_BASE_ADDR = DEFINED(__sram_base_addr__) ? __sram_base_addr__ : 0x40080000;
SRAM_SIZE = DEFINED(__sram_size__) ? __sram_size__ : 256K;
MEMORY
{
flash_rchw : org = 0x00FA0000, len = 0x4
cpu0_reset_vec : org = 0x00FA0000+0x10, len = 0x4
cpu1_reset_vec : org = 0x00FA0000+0x14, len = 0x4
cpu2_reset_vec : org = 0x00FA0000+0x04, len = 0x4
m_text : org = FLASH_BASE_ADDR, len = FLASH_SIZE
m_data : org = SRAM_BASE_ADDR, len = SRAM_SIZE
/************************************************/
shared : org = 0x40000000, len = 4k
/************************************************/
}
- main.c snippet
/* sends LED number on the queue */
void vSendLEDnumber(void* pvParamaters)
{
uint32_t LEDnumber = 0;
//8 LEDs: pa4, pa0, pj4,ph5,pc4,ph13,pa7,pa10
while(1){
vTaskDelay( 763 / portTICK_PERIOD_MS );
/* pack the LED number on to the queue */
xQueueSendToBack( *LEDQueue, &LEDnumber, 0 );
LEDnumber++;
if (LEDnumber > 7){LEDnumber = 0;}
}
}
/*place the queue in commonly shared piece of memory */
QueueHandle_t *LEDQueue =(QueueHandle_t*) 0x40000000;
int main(void)
{
#ifdef PEX_RTOS_INIT
PEX_RTOS_INIT();
#endif
/* Initialize and configure clocks */
CLOCK_SYS_Init(g_clockManConfigsArr, (uint8_t)CLOCK_MANAGER_CONFIG_CNT, g_clockManCallbacksArr, (uint8_t)CLOCK_MANAGER_CALLBACK_CNT);
CLOCK_SYS_UpdateConfiguration(0U, CLOCK_MANAGER_POLICY_AGREEMENT);
xTaskCreate(vSendLEDnumber, "SendLEDnumber", 128U, NULL, 1, NULL);
vTaskStartScheduler();
/*** Don't write any code pass this line, or it will be deleted during code generation. ***/
#ifdef PEX_RTOS_START
PEX_RTOS_START(); /* Startup of the selected RTOS. Macro is defined by the RTOS component. */
#endif
/*** Processor Expert end of main routine. DON'T MODIFY THIS CODE!!! ***/
for(;;) {
if(exit_code != 0) {
break;
}
}
return exit_code;
}
CORE Z4_1
- Memory map of /Project_Settings/Linker_Files/linker_flash.ld:
/* Define SRAM */
SRAM_BASE_ADDR = DEFINED(__sram_base_addr__) ? __sram_base_addr__ : 0x40040000;
SRAM_SIZE = DEFINED(__sram_size__) ? __sram_size__ : 256K;
MEMORY
{
flash_rchw : org = 0x00FA0000, len = 0x4
cpu0_reset_vec : org = 0x00FA0000+0x10, len = 0x4
cpu1_reset_vec : org = 0x00FA0000+0x14, len = 0x4
cpu2_reset_vec : org = 0x00FA0000+0x04, len = 0x4
m_text : org = FLASH_BASE_ADDR, len = FLASH_SIZE
m_data : org = SRAM_BASE_ADDR, len = SRAM_SIZE
/************************************************/
shared : org = 0x40000000, len = 4k
/************************************************/
}
- main.c
int main(void)
{
#ifdef PEX_RTOS_INIT
PEX_RTOS_INIT();
#endif
/* Initialize and configure clocks */
CLOCK_SYS_Init(g_clockManConfigsArr, (uint8_t)CLOCK_MANAGER_CONFIG_CNT, g_clockManCallbacksArr, (uint8_t)CLOCK_MANAGER_CALLBACK_CNT);
CLOCK_SYS_UpdateConfiguration(0U, CLOCK_MANAGER_POLICY_AGREEMENT);
vTaskStartScheduler();
#ifdef PEX_RTOS_START
PEX_RTOS_START();
#endif
for(;;) {
if(exit_code != 0) {
break;
}
}
return exit_code;
}
One more detail: I have not been able to flash all three cores onto the board using the 'Flash' option of the S32DS. It would only write to the first core. The way I program all three cores of the board is:
1. creating a 'launch group' with all the cores.
2. clicking 'run configuration' and selecting the launch group with three cores.
3. Unplugging the device - the program now resides in the flash.
