As you have already discovered, the multi threading facilities of the Rust std
library rely on the facilities of an OS kernel which are not available when working in a bare metal embedded environment.
The actual process of getting the second core to execute code is a little complex and low level. It is described in the RP2040 datasheet in the section titled "2.8.2. Launching Code On Processor Core 1".
In summary - after the second core boots up, it goes into a sleep state waiting for instructions to be sent to it over the SIO FIFO, which is a communications channel between the two cores. The instructions sent through provides an interrupt vector table, a stack pointer and an entry point for the core to begin executing.
Luckily, the rp2040_hal crate provides a higher level abstraction for this . The example below is from the multicore
module of this crate:
use rp2040_hal::{pac, gpio::Pins, sio::Sio, multicore::{Multicore, Stack}};
static mut CORE1_STACK: Stack<4096> = Stack::new();
fn core1_task() -> ! {
loop {}
}
fn main() -> ! {
let mut pac = pac::Peripherals::take().unwrap();
let mut sio = Sio::new(pac.SIO);
// Other init code above this line
let mut mc = Multicore::new(&mut pac.PSM, &mut pac.PPB, &mut sio.fifo);
let cores = mc.cores();
let core1 = &mut cores[1];
let _test = core1.spawn(unsafe { &mut CORE1_STACK.mem }, core1_task);
// The rest of your application below this line
}
In the above example, the code within the core1_task
function will be executed on the second core, while the first core continues to execute the main
function. There are more complete examples in the crate's examples directory.
Disclaimer: I have not used this crate or microcontroller myself - all info was found from online documentation.