Arduino IDEによるRaspberry Pi Picoでのプログラムはパラレル出力などでかなり速くなり,128x64RGBLEDパネルを4096色で動かせました。
Raspberry Pi Pico で128X64RGB LEDディスプレイを動かしてみた

Raspberry Pi Picoはデュアルコア(マルチコア)でもあり,画面出力部を並列処理にまわしておくと動きなどのデータ処理が楽になると思い試してみました。


今回の目標は
1) Raspberry Pi Picoのマルチコア機能を使ってみる
2) RGB各5bit階調,32,768色を試してみる
です。


戸惑いもありつつ動かすところまでは来ましたのでメモしておきます(^^)。

今日は節分で鬼もいます。





出来の悪い動画ですが,,少しだけ遊んでみました。






[Raspberry Pi Picoのマルチコア機能]

Raspberry Pi Pico(RP2040)は独立して動く2つのコアを持っていて,Arduino IDEでも使うことができます。

さて,どうしたら良いかと参考にしたWebページです。
(私の使っているarduino-picoライブラリ(ボード)関係になります。)

Raspberry Pi Pico のマルチコアの使い方 imo Lab. 

earlephilhower/arduino-pico Multicore Processing

raspberrypi.com rp2040-datasheet 2.3.1. SIO


1) Arduino IDE でのデュアルコア(マルチコア)の書き方

・ core0のいつもの setup(), loop()にcore1のsetup1(), loop1()を追加すれば動く

・include や両方のcoreで使う変数は初頭のグローバル領域に書いておけば良い

・一方のcoreを止めてその間にデータを書き換えたり,待たせたりもできる

・core0とcore1との直のやりとりはグローバル変数でもできるが,専用のFIFOを使うと良い

下図はSingle-cycle IO block (SIO)と呼ばれるRP2040のI/O系の部分です。

私には良く分からない事だらけの図ですが,core間のコミュニケーション用にFIFO(FirstIn, FirstOut)が双方向に置かれているのが見えます。




2) arduino-picoライブラリのマルチコア用の関数
 関数の働きの詳しい説明は上記のgithubに書かれています。
 
Pausing Cores
 void rp2040.idleOtherCore()
 void rp2040.resumeOtherCore()
 void rp2040.restartCore1()

Communicating Between Cores
 void rp2040.fifo.push(uint32_t)
 bool rp2040.fifo.push_nb(uint32_t)
 uint32_t rp2040.fifo.pop()
 bool rp2040.fifo.pop_nb(uint32_t *dest)
 int rp2040.fifo.available()

 今回は上記の関数のうち下線の関数でFIFO経由でcore0から画像バッファの番号をcore1に送り(push),core1はその数値が届いたら(available),受け取る(pop)というのだけ使っています(^^;;;;;;

なお,FIFOは32bitx8(deep)の容量です。Mailboxと呼ばれているぐらいですからcore間の連絡用でしょう。

大量のデータをお互いのcoreで処理する時はcore同士ぶつからないように,どちらかに待ってもらって書き込みを行うなどの方法になるようです。


[動画のプログラム]

すっきりしない下手なプログラムですが,大まかな構成はま,こういうものではないかと,,,(^^;;;;


マルチコアでも両方のcoreに関わるライブラリの追加やピンの宣言などは同じですね。





31行の"rgbBuffer"がcore0で作り,core1でLEDに出力するデータです。
setup()では SDカードから読み込んでまずはオリジナルデータを作っています。





SDカードから読み取ったオリジナルデータ(8bit階調)は最上位bitから順にbitごとのグループに区分けして,core1から直にパラレル出力できる配列に変換しています。
ESP32-DevKitCで128x64RGBLEDディスプレイを512色表示にしてみた





出力データのバッファができていると,core0のloop()部ではバッファ番号をcore1にpushで送り,画像の出力時間待ちをしているだけになります(^^;;;;;;;

今後は画像データを動かしたり加工したりの仕事を行っていくはず,,,です。







core1のsetup1()とloop1()です。
setup1ではpinの出力設定だけ行っています。core0のsetupに置いても良いとは思いますが,ま,出力担当部なので。

loop1ではFIFOを通してcore0からバッファ番号を受け取り,その番号のバッファを規定回数表示するルーチンを呼び出しています。







gpioへの1画面の出力を担当しているパートです。
rgbデータと行アドレスをgpio_put_masked()でパラレルに出せるので随分高速になりました(^^)。

ただgpio_put()は10nsのパルスが出せるのでパルス幅には気をつけないと動作が不安定になります。出力先が74HCシリーズのシフトレジスタだと大体15〜17nsのパルスが必要のようです。

PICOからは20nsぐらいのパルスは出しておくのが安全だと思います。






画面の描画速度計測のために行アドレスの最上位bitのサイクルをロジアナでみると,1サイクル(色1階調の1画面)の描画は約0.5msでした。




今回は5bit階調の色表示で,1画面の完成には31回重ね書きします。
1画面にかかる時間は0.5ms X 31 =15.5msで60Hzに限りなく近づいてきました。

ただこれはcore1だけが担当している事なので,データの読み込みや変換,加工などを担当するcore0には影響はなく,むしろ余力があります。


うーむ,デュアルコアというのはこういうダイナミック点灯のLEDパネルのコントロールとか,目が離せない機器との接続などに向いていますかね。

PICO(RP2040)にはI/Oをもっと高速にする Programmable input/output block (PIO)というのまであることはあるのですが,,ちょっと私には敷居が高いかな,というところです(^^;;;;;;。