Arduino UNO R4 WiFi上のLEDマトリックスをRustで動かす
春先にarduino uno r4 wifiを購入してからずっと引き出しの奥で眠らせていたので、今回は久しぶりに引っ張り出してなにかしようと思い,LEDマトリックスに絵を描くプログラムをRustで書こうと思いました。(やり方の部分はほとんど日記みたいになっちゃってます🙏)
こんな感じのをRustでできるようにしました!
成果物のリポジトリ
とりあえず動かせるプログラムをどっかから入手
最近ずっとRustを書きたい気分が続いていました。しかしいざやろうとして、ネットを調査しても、ChatGPT,Geminiに聞いてもRustで開発するために必要な答えがなかなか返って来ませんでした。
しばらく調査を進めるとelfmimiさんの書いたrust-rtt-sampleを発見しました。実際にクローンして動かしてみると、arduino uno r4 wifi上で動作することが確認できました。
今回は、そのコードを参考にしつつ、情報の少ないRustでの開発を自分で模索することにします。
Day1
最近,Gemini 2.5 Pro
が使えることになったので、geminiとおしゃべりをしつつ書いていました。(自分でミスを修正したりして、本当にすごかった...)。仕様から、LEDマトリックスへアクセスするためのレジスタを見つけて実際に出力するという素晴らしい成果を挙げてくれたのですが、そこからがどうもうまく行きません。具体的には、操作しているレジスタと実際に光るLEDの座標の関係がちぐはぐな状態でした。トークンも体力も使い果たしDay1は終了しました。
Day2
ここまでだと、「Geminiをうまく使えなかった人」で終わってしまうのでDay2はがんばります。
まず、Geminiを始めとしたAIツールは画像を含んだりしてる仕様書やデータシートを苦手としてるんじゃなかろうかということで、しかたがないので自分で一次情報に当たります。
問題になっているのは、Rustのクレートとして用意されたRA4M1用halでどんなアクセスの仕方をすれば目的の座標のLEDを操作できるのかということ。更には、複数のLEDを同時に点灯するにはどのようにすればいいのかということです。
しばらく、調べているうちに、どうやらLEDは同時についているのではなく、人の目ではわからない程の速さで高速に一つずつ表示されているということがわかりました。
そうなると、とりあえずの目標は一つめに書いた特定の座標のLEDを一つ点灯させる関数を作成することになります。
そうして更に調べていくうちに以下のソースを発見しました!
どうやら、このように少し(かなり??)複雑に見えるのは、Charlieplexingという、複数のLEDを制御する際にポートの数を減らすための工夫のようです。
上のソースで特に重要なのは、1ページ目のLED MATRIX
と2ページめの階段みたいな図です。
2ページ目の内容を表でまとめると以下のようになります
回路図(表中の数字は下の「LEDを表現している図」のLEDの番号に対応)
0列 | 1列 | 2列 | 3列 | 4列 | 5列 | 6列 | 7列 | 8列 | 9列 | 10列 | 11列 | 12列 | 13列 | 14列 | 15列 | 16列 | 17列 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 行(ROW_TOP1) | 1 | 2 | ||||||||||||||||
1 行(ROW_TOP2) | 3 | 4 | 5 | 6 | ||||||||||||||
2 行(ROW_TOP3) | 7 | 8 | 9 | 10 | 11 | 12 | ||||||||||||
3 行(ROW_TOP4) | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | ||||||||||
4 行(ROW_TOP5) | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | ||||||||
5 行(ROW_TOP6) | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | ||||||
6 行(ROW_TOP7) | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | ||||
7 行(ROW_TOP8) | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | ||
8 行(ROW_TOP9) | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 |
9 行(ROW_TOP10) | 91 | 92 | 93 | 94 | 95 | 96 |
LED MATRIXを表現している図
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 | 54 | 55 | 56 | 57 | 58 | 59 | 60 |
61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 |
73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 |
85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 |
2ページ目の階段みたいな回路図をよく見てみると、偶数奇数同士で隣り合う数のペア(例:(1,2) , (3,4), (93,94))は同じピンに接続されています。
偶奇のペアになっているLEDを一つの単位とみて下側に接続されているものをROW_BOT
、上側に接続されているものをROW_TOP
とします。
例えば、LEDの番号が1,2のものはROW_BOT
がROW0,ROW_TOP
がROW1,LEDの番号が17,18のものはROW_BOT
がROW2,ROW_TOP
がROW4になります。目視で確認していってもいいのですが、規則正しく並んでいるので、任意のLEDの番号と接続されているピンの関係性を調べて、できるだけラクしましょう。
結論の数式
LEDの番号を
-
行番号
を求めるr
r = \left\lfloor \frac{\sqrt{4N - 3} - 1}{2} \right\rfloor
※ は、床関数(\lfloor x \rfloor を超えない最大の整数)を表します。x -
列番号
を求めるc
c = N - (r(r+1) + 1)
数式の導出方法
なぜこの式で求められるのかを、ステップごとに解説します。
1. 各行の性質を分析する
まず、表の各行 r
にどのような性質があるかを確認します。
-
各行に含まれる数字の個数
- 行 0: 2個 (
)=2 \times (0+1) - 行 1: 4個 (
)=2 \times (1+1) - 行 2: 6個 (
)=2 \times (2+1) - このパターンから、行
r
には 個の数字が含まれることがわかります。2(r+1)
- 行 0: 2個 (
-
各行の最初の数字 (
)S_r - 行
r
の最初の数字は、行r-1
までに現れたすべての数字の総数に1
を足したものです。 - 行
r-1
までの数字の総数は、 という等差数列の和で求められ、これは2(0+1) + 2(1+1) + \dots + 2((r-1)+1) となります。r(r+1) - したがって、行
r
の最初の数字 はS_r となります。r(r+1) + 1
- 行
2. 数式を組み立てる
上記の性質を利用して、数式を組み立てます。
-
行
r
の特定
ある数 は、行N の最初の数r 以上で、次の行S_r の最初の数r+1 より小さい範囲にあります。S_{r+1}
S_r \le N < S_{r+1}
先ほどの式を代入すると、
r(r+1) + 1 \le N < (r+1)(r+2) + 1
この不等式のうち、 をr(r+1) + 1 \le N について解くと、先に示した行番号r を求める数式が得られます。r -
列
c
の特定
列番号 は、その行の何番目に位置するかを示します(0から始まるインデックス)。これは単純に、数c とその行の最初の数N との差で計算できます。S_r
c = N - S_r
を代入すると、列番号S_r = r(r+1) + 1 を求める数式が完成します。c
LEDの番号から行番号、列番号を判明させるための式がわかったのでRustのコード(点灯させたいLEDとそれに対応するピンへのアクセスを対応させる配列)を生成するpythonのプログラムを書きます。
ここで判明した対応関係をRustのプログラムに貼り付けて実行すると...
やったね🩷
感想
シグマなんて久しぶりに使った、、
Discussion