Next step in my experiments: Running a SDK task on one core – core1 in my example AND two FreeRTOS tasks on the other core. One of the FreeRTS tasks will communicate with the SDK task using SDK FIFOs and with a FreeRTOS task using a queue,

I added the folder freertos_multi_core to the examples files on my github. In addition you need to add another subdirectory in the main CMakeLists.txt file in root folder.

In the main function I initialize all stdio functions of the pico and start the task taskOnCore1 on core1. Then I prepare a queue and both FreeRTOS tasks for scheduling, which is started with the function vTaskSchdulerStart.

int main()
{
stdio_init_all();
std::cout << "Start main app\n";

multicore_launch_core1(taskOnCore1);

eventQueue = xQueueCreate(5, sizeof(int) );

xTaskCreate(eventGenerator,
"eventGenerator",
256,
nullptr,
1,
&tskHdnl_evGen);

xTaskCreate(stateManager,
"stateManager",
256,
nullptr,
1,
&tskHdnl_stateManager);

vTaskStartScheduler();

while (true)
{
// should only get here if there is insufficient RAM
}
}

Task taskOnCore1 which willl be running on core1 – hence the name – generates a PWM signal on pin 14 and uses the SDK FIFO to first receive data from core0 and afterwards replay using its sending FIFO.

Please note that you may not use FreeRTOS functions like vTaskDelay in this task, hence FreeRTOS is only available on the other core. This means: The function does not know RTOS functions.
void taskOnCore1(void)
{
int pin = 14;
uint32_t fromCore0 = 0;

gpio_init(pin);
gpio_set_dir(pin, GPIO_OUT);
while (true) {
std::cout << ".\n";
gpio_put(pin, 1);
sleep_ms( 200 );
gpio_put(pin, 0);
sleep_ms( 200 );

if(multicore_fifo_rvalid() == true)
{
fromCore0 = multicore_fifo_pop_blocking ();
std::cout << "Message from core 0: " << int(fromCore0) << "\n";

fromCore0 += 10;
std::cout << "Sending to core 0 " << int(fromCore0) << "\n";
multicore_fifo_push_blocking(fromCore0);
}
}
}

Task eventGenerator remains unchanged since the last example therefore I will not mention it here. Task eventManager starts the communication with core1 by using multicore_fifo_push_blocking. This is not essential, just the way I design this example. In a while-loop the task communicates with task eventGenerator using a queue and afterwards checks if there is data available on thr SDK FIFO with function multicore_fifo_rvalid(). If so, the data are read and afterwards a response is sent on the FIFO.

void stateManager(void *p)
{
uint8_t i = 255;
uint32_t fromCore1 = -255;

multicore_fifo_push_blocking(fromCore1);

while(true)
{
if( xQueueReceive(eventQueue, &i, portMAX_DELAY) == pdPASS )
{
std::cout << "received " << i << std::endl;
switch( i)
{
case EVENT_PIN_HIGH: std::cout << "Pin is high\n";
break;
case EVENT_PIN_LOW : std::cout << "Pin is low\n";
break;
default: std::cout << "Unkown state\n";
break;
}
}

if(multicore_fifo_rvalid() == true)
{
fromCore1 = multicore_fifo_pop_blocking ();
std::cout << "Message from core 1: " << int(fromCore1) << "\n";

fromCore1 += 10;
std::cout << "Sending to core 1 " << int(fromCore1) << "\n";
multicore_fifo_push_blocking(fromCore1);
}
}
}

Here is a screenshot of my oscilloscope which shows the two PWM signals.

And her’s some example output:

Sending to core 0 175
.
received
Pin is low
Message from core 1: 175
Sending to core 1 185
received
Pin is high
received
Pin is low
Message from core 0: 185