IchigoJam RのLEDは、ピン配置を見ると汎用入出力(GPIO)のポートAの14番(PA14)を使っていることがわかります。
「GD32VF103のドキュメントより」
コンピュータの仕様書にメモリにマップされたアドレスが記載されています。このアドレスに対して書き込むことで出力を変更できます。
まずは単純に付けてみましょう。出力制御のGPIOx_BOPを使います。PA14は、#40010810の14bit目を1にすればONにできます。(Arm版の例)
MODE RV32C R11=#4 'R1=#40010810 R11<<=12 R11+=1 R11<<=8 R11+=8 R11<<=8 R11+=#10 R12=1 R12<<=14 [R11+0]L=R12 ' set BOP RET
みけCATさんが、RISC-V版にも対応してくれたasm15を使ってアセンブルできます。
「Volume 1, Unprivileged Spec v. 20191213より」
RISC-Vのレジスタは31コ(X0は0固定)。X10〜X17がパラメータ、X10/X11が返り値かつ、元の値を保存せずに使えます。RV32Cの16bit縮小命令で使える範囲外ですが、X5〜X7/X28〜X31も元の値を保存せずに使えます。
asm15ではX??レジスタはR??レジスタとして記述します。
LEDを消すときは上記のset BOP を下記のように変更します
[R11+1]L=R12 ' clear BC
続いて、WS2812Bを制御しましょう、データシートを見ると、1コに付き24bitを、0の時は短く(220ナノ秒)ON、1の時は長めに(580ナノ秒)ONの後、しばらく(580ナノ秒)OFFという制御をすればいいことがわかります。 96MHzで動くRISCアーキテクチャーのコンピューターは1命令を10.417ナノ秒でこなします。220ナノ秒待つためにループを使います。
R10=100 R10+=-1 IF R10 GOTO -1
これで100回ループします。R10-=1という命令はないので、-1を足し算します。フラグがない代わりにレジスタが0じゃないかどうかで判定してのループです。
Armでは1ループ4clockでしたが、RISC-V(GD32VF103)ではどうなるでしょう?割り込みを禁止して、10秒間停止させる実験をしたところ、分岐は1clock短縮の2clock、つまり1ループ、3clockです。
あとは、Arm版のWS2812BのドライバをRISC-V用に改造です。
' LED WS2812B R11とR5を変更でOUTnに変更可能 ' R10 - 開始アドレス 送信byte数low,送信byte数high,G1,R1,B1,G2,R2,B2 .... ' R11 - base address (初期はRAM offset) ' R12 - temp ' R13 - data value ' R14 - data count ' R15 - bit count ' R5 - OUT value ' R8 - wait count ' R9 - wait count MODE RV32C @WS2812B SP+=-2 PUSH R8,0 PUSH R9,1 CPSID R10=R10+R11 'R11=#40010810 R11=#4 R11<<=12 R11+=1 R11<<=8 R11+=8 R11<<=8 R11+=#10 R5=1 R5<<=14 R14=[R10+0]W R10+=1 @LOOP_DATA R15=#8 R15<<=4 R10+=1 R13=[R10+0] @LOOP_BIT [R11+0]L=R5 R9=20 '3clock*20=60 <- 58-100 R8=20 '3clock*20=60 <- 58-100 R12=R13&R15 IF R12 GOTO @SKIP R9=8 '3clock*8=24 <- 22-38 @SKIP R9+=-1 'wait R9*3 clock IF R9 GOTO -1 [R11+4]L=R5 ' *offset 4byte R8+=-1 'wait R8*3 clock IF R8 GOTO -1 R15>>=1 IF R15 GOTO @LOOP_BIT R14+=-1 '+6clock IF R14 GOTO @LOOP_DATA CPSIE POP R9,1 POP R8,0 SP+=2 RET
CPSID/CPSIEに対応させたasm15を使うとアセンブルできます。
WS2812B光りました!12コのWS2812Bの実験プログラム for IchigoJam Rβ
10 POKE#700,61,113,34,192,38,194,243,119,4,48,51,5,181,0,145,69,178,5,133,5,162,5,161,5,162,5,193,5,133,66,186,2,3,87,5,0,5,5,161,71,146,7,5,5,131,70,5,0,35,160,85,0,209,68,81,68,51,246,246,0,17,226 20 POKE#73E,161,68,253,20,253,252,35,162,85,0,125,20,125,252,133,131,237,243,125,23,113,251,243,103,4,48,146,68,2,68,5,97,130,128 30 POKE#800,12*3,0 40 FOR I=0 TO 11:POKE#802+I*3,I,12-I,0:NEXT:?USR(#700,#800):WAIT30 50 FOR I=0 TO 11:POKE#802+I*3,0,12-I,I:NEXT:?USR(#700,#800):WAIT30 60 FOR I=0 TO 11:POKE#802+I*3,12-I,0,I:NEXT:?USR(#700,#800):WAIT30 70 GOTO 40
WS.LED命令として組み込む準備ができました。