執筆者: 瀕死
最終更新: 2024/07/03
瀕死(ひんし)と申します。しばらくはマイコン関連の記事を投稿する予定です。 本稿でもよろしくお願いいたします。
RP2040には2つのCPUが搭載されている。 本稿では、RP2040開発ボードにおいて2つのコアを利用する方法について解説する。
そして、コア間通信のために、キューやセマフォを利用する例を紹介する。
本稿では、Raspberry Pi Pico C/C++ SDK(以下SDK)を用いて開発を行う。 詳しいことは、前記事を参照ください。
CMakeLists.txt
のtarget_link_libraries
にpico_multicore
を追記しておく。
そしてmain.cpp
にインクルードファイルを追加する。
#include "pico/multicore.h"
この段階でビルドが成功するか確認する。
タスク間通信を必要としない場合は簡単に実装できる。
multicore_launch_core1(func);
によって、core1に行わせる関数を渡せばよい。
#include "pico/stdlib.h"
#include "hardware/gpio.h"
#include "pico/multicore.h"
#include <iostream>
using namespace std;
#define LED_BUILTIN 25
void core1_main() {
while(true) {
char c;
cin >> c;
cout << "read: " << c << endl;
}
}
// main関数はcore0で動作する
int main() {
// core1_main関数をcore1で実行させる
multicore_launch_core1(core1_main);
stdio_init_all();
gpio_init(LED_BUILTIN);
gpio_set_dir(LED_BUILTIN, GPIO_OUT);
while(true) {
gpio_put(LED_BUILTIN, 1);
sleep_ms(1000);
gpio_put(LED_BUILTIN, 0);
sleep_ms(1000);
}
}
上記の例をビルドして実行すると、1秒間隔でLEDが点滅する。 そして、なにかシリアル通信で送信すると、以下の画面が表示される。
タスク間通信を行う手法として、以下のものがRP2040で実装されている。
このうち、コア間fifoは非常に貴重なリソースで SDK 機能に頻繁に使用されますので独自の目的で FIFO を使用しないことをお勧めします。 とドキュメントに書いてあるので注意する。
本稿ではコア間fifoの代わりとして推奨されている、キューとセマフォの利用法について解説する。
以下のプログラムはどちらもシリアル通信によって送信した値だけLEDを点灯させるプログラムである。
キューはそれ自体がバッファであるため、 値のコピーの処理が必要であったり、 同じ目的の値が複数存在することになるので、デバッグがやりずらいという問題がある。
しかし、他機器との通信など小さいデータが多数発生するなどの状況にはキューが向いていることが多い。
#include "pico/stdlib.h"
#include "hardware/gpio.h"
#include "pico/multicore.h"
#include "pico/util/queue.h"
#include <iostream>
#define LED_BUILTIN 25
using namespace std;
// キューで送受信するデータの構造体型を宣言
typedef struct {
int data;
} led_queue_entry_t;
// キューを宣言
queue_t led_queue;
void core1_main() {
while(true) {
led_queue_entry_t entry;
// キューを受信して取り除く、ない場合は待機
queue_remove_blocking(&led_queue, &entry);
gpio_put(LED_BUILTIN, 1);
sleep_ms(entry.data * 1000);
gpio_put(LED_BUILTIN, 0);
}
}
int main() {
stdio_init_all();
// キューを初期化、サイズは2
queue_init(&led_queue, sizeof(led_queue_entry_t), 2);
multicore_launch_core1(core1_main);
gpio_init(LED_BUILTIN);
gpio_set_dir(LED_BUILTIN, GPIO_OUT);
while(true) {
char c;
cin.get(c);
// 送信のための構造体を作成
led_queue_entry_t entry {
(c-'0') // charをintに変換
};
// いっぱいなら送信待機
queue_add_blocking(&led_queue, &entry);
}
}
セマフォは複数のコアから同時に同じメモリに アクセスしないようにする排他処理の手法の1つである。
セマフォを使うと、安全に変数をコア間で共有できるようになる。
今回の例の場合は、入力したという情報も必要なので、キューか変数に特定の値を入れるなどする必要がある。
#include "pico/stdlib.h"
#include "hardware/gpio.h"
#include "pico/multicore.h"
#include <iostream>
#define LED_BUILTIN 25
using namespace std;
// セマフォ
static semaphore_t sem;
// core0とcore1で共有される変数
static uint32_t led_time = 0;
void core1_main() {
while(true) {
// セマフォを確保
sem_acquire_blocking(&sem);
// セマフォ確保中に処理
int time = led_time;
// セマフォを解放
sem_release(&sem);
cout << time << endl;
gpio_put(LED_BUILTIN, 1);
sleep_ms(time * 1000);
gpio_put(LED_BUILTIN, 0);
}
}
int main() {
stdio_init_all();
// 同時アクセス1まででセマフォを初期化
sem_init(&sem, 1, 1);
multicore_launch_core1(core1_main);
gpio_init(LED_BUILTIN);
gpio_set_dir(LED_BUILTIN, GPIO_OUT);
while(true) {
// セマフォを確保
sem_acquire_blocking(&sem);
// 入力までセマフォ確保したまま待機(よくない)
char c;
cin.get(c);
// セマフォ確保中に処理
led_time = c-'0';
// セマフォを解放
sem_release(&sem);
}
}
この人が書いた記事