前回(base)ではPico のCPUのデュアルコアそれぞれで独立してジョブを実行させていましたが、今回は2つのコア間で通信させてみます。
Pico にはコア間で通信させるのに便利な共有メモリがあって、FIFOでデータ送信できます。
こんな感じです。
出典:Conceptual diagram of the communication between cores on the RP2040
出典にあるサンプルプログラムやFIFOが分かりやすいLチカプログラムをやってみます。C/C++ を使います。
母艦にpico-sdkをインストール
picoのファームウェア作成や結果表示用にラズパイ4を母艦に使います。
Raspberry Pi OS の最新はBookworm ですがまだ何か不安定な所が見られるので、1つ前のBullseyeのDesktop を使います。
インストール
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
sudo apt update sudo apt install -y build-essential cmake gcc-arm-none-eabi git curl mkdir ~/pico cd ~/pico git clone https://github.com/raspberrypi/pico-sdk cd pico-sdk git submodule update --init echo "export PICO_SDK_PATH=$HOME/pico/pico-sdk" >> ~/.bashrc . ~/.bashrc |
内臓温度センサーを使ってみる
コア 0 を使用して Pico 上のオンチップ温度センサーを読み取るマルチコア プログラムを作成してみます。 データはコア 1 に送信され変換されて、シリアル USB 接続経由で母艦のラズパイ4のディスプレイに表示されます。
pico-sdk をインストールしたpicoフォルダーに作業用のmulticore_fifo_tempというフォルダーを作ります。
1 2 3 |
cd ~/pico mkdir multicore_fifo_temp cd multicore_fifo_temp |
ここに CMakeLists.txtファイルとソースファイルを作成します。
1 |
sudo nano CMakeLists.txt |
以下を記述します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
cmake_minimum_required(VERSION 3.13) include(pico_sdk_import.cmake) project(client_project C CXX ASM) set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 17) pico_sdk_init() add_executable(multicore_fifo_temp multicore_fifo_temp.c ) target_link_libraries(multicore_fifo_temp pico_multicore pico_stdlib hardware_adc ) pico_enable_stdio_usb(multicore_fifo_temp 1) pico_enable_stdio_uart(multicore_fifo_temp 0) pico_add_extra_outputs(multicore_fifo_temp) |
次にソースファイル。
1 |
sudo nano multicore_fifo_temp.c |
コードは以下のとおり。
コア0で生のデータを読んで、FIFO経由でコア1に渡し、変換してシリアルに吐き出して表示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
#include <stdio.h> #include "pico/stdlib.h" #include "pico/multicore.h" #include "hardware/irq.h" #include "hardware/adc.h" // Core 1 interrupt Handler void core1_interrupt_handler() { // Receive Raw Value, Convert and Print Temperature Value while (multicore_fifo_rvalid()){ uint16_t raw = multicore_fifo_pop_blocking(); const float conversion_factor = 3.3f / (1 << 12); float result = raw * conversion_factor; float temp = 27 - (result - 0.706)/0.001721; printf("Temp = %f C\n", temp); } multicore_fifo_clear_irq(); // Clear interrupt } // Core 1 Main Code void core1_entry() { // Configure Core 1 Interrupt multicore_fifo_clear_irq(); irq_set_exclusive_handler(SIO_IRQ_PROC1, core1_interrupt_handler); irq_set_enabled(SIO_IRQ_PROC1, true); // Infinte While Loop to wait for interrupt while (1){ tight_loop_contents(); } } // Core 0 Main Code int main(void){ stdio_init_all(); multicore_launch_core1(core1_entry); // Start core 1 - Do this before any interrupt configuration // Configure the ADC adc_init(); adc_set_temp_sensor_enabled(true); // Enable on board temp sensor adc_select_input(4); // Primary Core 0 Loop while (1) { uint16_t raw = adc_read(); multicore_fifo_push_blocking(raw); sleep_ms(1000); } } |
ここで使われるFIFOを使ったpush , pop などの関数の意味。
詳細は以下を参照
ファームウェアを作成します。
1 2 3 4 5 6 7 |
cp ../pico-sdk/external/pico_sdk_import.cmake . mkdir build cd build export PICO_SDK_PATH=../../pico-sdk cmake -DPICO_BOARD=pico_w .. make -j4 |
buildフォルダー内にファームウェアのuf2ファイルが作成されます。
Pico のBOOTSELボタンを押しながら母艦に再接続して、フォルダーが開いたらuf2ファイルをドラッグ・ドロップします。
ラズパイでminicomなどを使ってモニターします。
1 2 3 |
sudo apt install minicom -y minicom -b 115200 -o -D /dev/ttyACM0 |
内臓LEDを使ってみる
コンソールアプリを作り、コア0ではキーボードからの入力を受け、取得した数値をコア1に送って、その数値の回数だけLEDを点滅させてみます。
入力と点滅は独立したジョブなので、連続して数値を入力させた場合、値はFIFOバッファーに入れられ、点滅ジョブが終了する毎に順番に取り出されます。
全体の手順は上記と同じです。
1 2 3 |
cd ~/pico mkdir multicore_fifo_led cd multicore_fifo_led |
【 CMakeLists.txt】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
cmake_minimum_required(VERSION 3.13) include(pico_sdk_import.cmake) project(client_project C CXX ASM) set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 17) pico_sdk_init() add_executable(multicore_fifo_led multicore_fifo_led.c ) target_link_libraries(multicore_fifo_led pico_multicore pico_stdlib ) pico_enable_stdio_usb(multicore_fifo_led 1) pico_enable_stdio_uart(multicore_fifo_led 0) pico_add_extra_outputs(multicore_fifo_led) |
【 multicore_fifo_led.c】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
#include <stdio.h> #include "pico/stdlib.h" #include "pico/multicore.h" void core1_entry(void) { gpio_init(25); gpio_set_dir(25, 1); gpio_put(25, 0); while(1) { const uint loop = multicore_fifo_pop_blocking(); printf("Inner LED %d times Blink.\n", loop); sleep_ms(1000); for(int i = 0; i < loop; i++) { gpio_put(25, 1); sleep_ms(100); gpio_put(25, 0); sleep_ms(1000); } } } int main() { uint input_value; stdio_init_all(); multicore_launch_core1(core1_entry); while (1) { printf("?-> "); scanf("%d", &input_value); if(input_value == 0){ break; } multicore_fifo_push_blocking(input_value); } printf("end"); return 0; } |
ビルド
1 2 3 4 5 6 7 |
cp ../pico-sdk/external/pico_sdk_import.cmake . mkdir build cd build export PICO_SDK_PATH=../../pico-sdk cmake -DPICO_BOARD=pico_w .. make -j4 |
Pico のBOOTSELボタンを押しながら母艦に再接続してフォルダーが開いたらuf2ファイルをドラッグ・ドロップでコピー。
ラズパイでminicomなどを使ってUSBポートをモニターします。
1 2 3 |
sudo apt install minicom -y minicom -b 115200 -o -D /dev/ttyACM0 |
初期画面は真っ黒です。
試しにキーボードから5を入力してリターンキーを押すと、メッセージが表示されてLEDが5回点滅します。
また、順にリターンキーで9,8,7,6,5,4,3,2,1と入力してそのままほっとけば、点滅が終了する毎に8,7,6,5,4,3,2,1が順に取り出され、メッセージが表示されてその数値の回数LEDが点滅します (入力値は1桁でなくてもかまいません)。
0を入力すればendメッセージが出て終了です。
Pico の構成
Reference
Leave a Reply