When the Raspberry Pi Pico runs with two cores, vital resources must be protected by semaphores (Mutual Exclusion). This examples uses Peterson’s algorithm, which is rather simple for two threads / cores.
Note: The semaphore variables and the housekeeping variables are set up as ‘volatile’. This turned out to be necessary for the code to work.
References:
[1] https://wiki2.org/en/Peterson%27s_algorithm
[2] https://stackoverflow.com/questions/3896952/testing-a-semaphore-by-counting/a>
/*
* Implementation of Peterson's Algorithm
* See: https://wiki2.org/en/Peterson%27s_algorithm
*/
/*
* Semaphore variables
*/
volatile uint8_t flags[2] = {false, false};
volatile uint8_t turn = 0;
/*
* Housekeeping variables
*/
volatile uint8_t core0 = 0;
volatile uint8_t core1 = 0;
long errors = 0L;
/*
* Test variable
*/
volatile long shared = 0L;
void inc() {
shared++;
}
void dec() {
shared--;
}
void setup() {
uint8_t i;
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
}
void setup1() {
delay(1);
}
void loop() {
long i;
Serial.println( "Starting Peterson test loop ..." );
for (i = 0L; i < 10000000L; i++) {
flags[0] = true;
turn = 1;
while( (flags[1] == true) && (turn == 1) ) {
// busy wait
;
}
/* Critical Section Code of the Process */
// prevent compiler from doing optimizations
inc();
dec();
/* End of Critical Section */
flags[0] = false;
//Serial.print( "." );
}
// wait until core 1 is finished
while (core1 != 1) {
Serial.println("Waiting for core 1 to finish ...");
delay(100);
}
if (core1 == 1) {
Serial.println("core 1 finished!");
delay(1000);
}
if (shared != 0L) {
errors++;
}
Serial.print( "shared = " );
Serial.print( shared );
Serial.print( " (errors = " );
Serial.print( errors );
Serial.println( ")" );
// start all over
shared = 0L;
// indicate core 0 has finished the main loop and check
core0 = 1;
delay(1000);
core0 = 0;
}
void loop1() {
long i;
for (i = 0L; i < 10000000L; i++) {
flags[1] = true;
turn = 0;
while( (flags[0] == true) && (turn == 0) ) {
// busy wait
;
}
/* Critical Section Code of the Process */
// prevent compiler from doing optimizations
inc();
dec();
/* End of Critical Section */
flags[1] = false;
}
// indicate core 1 has finished the main loop
core1 = 1;
// wait until core 0 has finished the main loop plus check
while (core0 != 1) {
delay(1);
}
// start all over
core1 = 0;
}
// start all over
shared = 0L;
// indicate core 0 has finished the main loop and check
core0 = 1;
delay(1000);
core0 = 0;
}
