・SH7216用Arduino互換ライブラリプロジェクトRev 1.0・SH7216用Ardunoライブラリの互換情報
▼コチラからダウンロードできます!http://japan.renesasrulz.com/partner_tools/marutsu/m/sh7216_board/default.aspx
この投稿の表題も含めてArduino「互換」ライブラリであるというこは徹底されたほうがよいと思います。
あと著作権と利用ライセンスについても明らかにされたほうが良い気がしますね。
このライブラリはこれで使えるのでしょうか?
japan.renesas.com/.../sh_arduino_ws.jsp
chobichan様
はい、使えます。
SuperH発売20周年記念スペシャルワークショップ続編「Arduinoでさっくりアプリ開発・ワークショップ」ぜひ参加をご検討ください。
KPIT の GNUSH v13.01 Windows Tool Chain (ELF) をダウンロードし、プロジェクト中の Release ビルドと同じコンパイルオプション ‘-m2a -D RELEASE -Os -fno-function-cse -funit-at-a-time -falign-jumps -fdata-sections -ffunction-sections -nostdinc’ を指定して core/arduino/digitalio.cpp をコンパイルしてみたところ、digitalWrite() の
*(unsigned short *)(_PORT_DR_BASE + offset) &= ~bits;
のポートへのビットをリセットする箇所が
28: 62 81 mov.w @r8,r2 2a: 63 11 mov.w @r1,r3 2c: 62 27 not r2,r2 2e: a0 03 bra 38 <_digitalWrite+0x38> 30: 22 39 and r3,r2 38: 21 21 mov.w r2,@r1
というコードに、同じく
*(unsigned short *)(_PORT_DR_BASE + offset) |= bits;
セットする箇所が
32: 63 11 mov.w @r1,r3 34: 62 81 mov.w @r8,r2 36: 22 3b or r3,r2 38: 21 21 mov.w r2,@r1
という 1 命令でポートへの操作が完了しないコードにコンパイルされました。
digitalWrite() はユーザーのプログラムや割り込み処理からも呼び出される関数ですが、同一のポートへの操作がかち合った場合、おかしな動作になってしまうと思います。
Arduinoプロジェクトをダウンロードし、KPITからGNUC v13をインストールし、HEW上からプロジェクトを開いてビルドしたのですが、1488個のエラーが発生しています。
エラーメッセージを見るとRXのツールチェインを呼んでいるみたいで、Arduino.hwpを開いてみるとやはりRXのツールチェインを指定しています。
そちらではビルド通ったのでしょうか?
sh-elf-gcc で直にコマンドラインでコンパイルしました。HEW は使ってません。
HEW で C:/WorkSpace/ 以下に SH7216_Arduino/ を展開してワークスペースを開いてみました。
ワークスペース中の arduino_gcc をアクティブプロジェクトに設定して Debug でビルドしたところ core/arduino/LiquidCrystal.cpp のビルドで
sh-elf-gcc-wrapper.exe は動作を停止しました
というエラーが出た他は凡そコンパイルは問題ない感じでした。但し上のコンパイルが通らないのでリンク成功まで行きません。
Release でビルドするにはインクルードパスにワークスペース以下のディレクトリが登録されておらずうまくいかない感じです。HEW のメニューの「ビルド(B)」→「KPIT GNUSH[ELF] Toolchain…」を開いてインクルードパスの設定を Debug と同様に設定すると概ねコンパイルは通るようです。但し、core/arduino/Arduino.cpp のコンパイルで
C:\WorkSpace\SH7216_Arduino\core\arduino\Arduino.cppPrePhase failed
とエラーになるみたいなのでやっぱりリンク成功まで行かないですね。
Release ビルドで core/arduino/Arduino.cpp のコンパイルに失敗するのは include/arduino/WString.h の中で stdlib.h をインクルードしているにもかかわらず HEW でのコンパイルオプションに ‘-nostdinc’ が指定されているためと判明。外し方が分からん。
外し方が分からん。
KPIT~ の設定で Category: Other の中の ‘Do not search standardなんちゃら’ のチェックを外すと ‘-nostdinc’ が外せることが判明。但しビルドでは相変わらずエラーになる不思議。コマンドラインで直なら問題ないのだがこれだから IDE は謎が多いな。
アクティブプロジェクトの変更をしていませんでした。arduino_gccにしたらコンパイルは通ります。
arduinoが展開されていてarduino_gccがある事に気づかなかった。
avastが一々「怪しいプログラムが起動した!」ってチェックに行っちゃうから、えらい時間が掛かる(笑)。
と、ここでようやく周回遅れのビット操作の話ですが、ビットフィールドを指定してもRead Modify Writeになってしまいますね。
SH2Aからはビット操作命令が追加になっているのですが、例えばBSETまたはBSET,Bの場合、該当レジスタまたはメモリのLSBの8bitのみが操作対象なので、
ちょっと”いやーん”な感じです。
某アーキテクチャみたいにビットバンディングとか、某マイコンみたいにSET/RESET専用レジスタとか有れば、、、
arduino.hwpのツールチェインはなんでSHCではなくRXだったんだろう???(今更)
GCC が SH-2A 用に BSET 命令を吐いてくれることを期待して
void bset(volatile char* port, int bit) { switch (bit) { case 0: *port |= 0x01; break; case 1: *port |= 0x02; break; case 2: *port |= 0x04; break; case 3: *port |= 0x08; break; case 4: *port |= 0x10; break; case 5: *port |= 0x20; break; case 6: *port |= 0x40; break; case 7: *port |= 0x80; break; } }
というコードを試してみたら、
$ sh-elf-gcc -Wall -W -m2a -Os -c bset.c && sh-elf-objdump -d bset.o bset.o: file format elf32-sh Disassembly of section .text: 00000000 <_bset>: 0: e1 07 mov #7,r1 2: 35 16 cmp/hi r1,r5 4: 89 19 bt 3a <_bset+0x3a> 6: 61 40 mov.b @r4,r1 8: c7 01 mova 10 <_bset+0x10>,r0 a: 05 5c mov.b @(r0,r5),r5 c: 05 23 braf r5 e: 61 1e exts.b r1,r1 10: 08 0c mov.b @(r0,r0),r8 12: 10 14 mov.l r1,@(16,r0) 14: 18 1c mov.l r1,@(48,r8) 16: 20 24 mov.b r2,@-r0 18: a0 0e bra 38 <_bset+0x38> 1a: 86 18 bset #0,r1 1c: a0 0c bra 38 <_bset+0x38> 1e: 86 19 bset #1,r1 20: a0 0a bra 38 <_bset+0x38> 22: 86 1a bset #2,r1 24: a0 08 bra 38 <_bset+0x38> 26: 86 1b bset #3,r1 28: a0 06 bra 38 <_bset+0x38> 2a: 86 1c bset #4,r1 2c: a0 04 bra 38 <_bset+0x38> 2e: 86 1d bset #5,r1 30: a0 02 bra 38 <_bset+0x38> 32: 86 1e bset #6,r1 34: e2 80 mov #-128,r2 36: 21 2b or r2,r1 38: 24 10 mov.b r1,@r4 3a: 00 6b rts/n
ポインタの指すメモリに対して直接 BSET してくれないわ、ビット 7 に対してはなんでか OR 命令吐いてくれるわでガッカリなので、期待したコードを吐かせるには
void bset(volatile char* port, int bit) { switch (bit) { case 0: __asm __volatile("bset.b #0, @(0, %0)\n" :: "r" (port)); break; case 1: __asm __volatile("bset.b #1, @(0, %0)\n" :: "r" (port)); break; case 2: __asm __volatile("bset.b #2, @(0, %0)\n" :: "r" (port)); break; case 3: __asm __volatile("bset.b #3, @(0, %0)\n" :: "r" (port)); break; case 4: __asm __volatile("bset.b #4, @(0, %0)\n" :: "r" (port)); break; case 5: __asm __volatile("bset.b #5, @(0, %0)\n" :: "r" (port)); break; case 6: __asm __volatile("bset.b #6, @(0, %0)\n" :: "r" (port)); break; case 7: __asm __volatile("bset.b #7, @(0, %0)\n" :: "r" (port)); break; } }
とかすればいいのかな?
$ sh-elf-gcc -Wall -W -m2a -Os -c bset.c && sh-elf-objdump -d bset.o bset.o: file format elf32-sh Disassembly of section .text: 00000000 <_bset>: 0: e1 07 mov #7,r1 2: 35 16 cmp/hi r1,r5 4: 89 1f bt 46 <_bset+0x46> 6: c7 02 mova 10 <_bset+0x10>,r0 8: 05 5c mov.b @(r0,r5),r5 a: 05 23 braf r5 c: 00 09 nop e: 00 09 nop 10: 0a 10 16 1c movi20 #71196,r10 14: 22 28 tst r2,r2 16: 2e 34 mov.b r3,@-r14 18: 34 09 10 00 bset.b #0,@(0,r4) 1c: 00 6b rts/n 1e: 34 19 10 00 bset.b #1,@(0,r4) 22: 00 6b rts/n 24: 34 29 10 00 bset.b #2,@(0,r4) 28: 00 6b rts/n 2a: 34 39 10 00 bset.b #3,@(0,r4) 2e: 00 6b rts/n 30: 34 49 10 00 bset.b #4,@(0,r4) 34: 00 6b rts/n 36: 34 59 10 00 bset.b #5,@(0,r4) 3a: 00 6b rts/n 3c: 34 69 10 00 bset.b #6,@(0,r4) 40: 00 6b rts/n 42: 34 79 10 00 bset.b #7,@(0,r4) 46: 00 6b rts/n
それでもポートに対してはビット 7 までしか使えないなら機能不足か。
『SH7214グループ、SH7216グループ ユーザーズマニュアル ハードウェア編』見るとポートなんとか・IO レジスタ H とか L とかはアクセスサイズが 8 も可能と書かれていますが、奇数番地アクセスすると上位ビットが操作できたりはしないんですか?
ああ、違うか。内蔵レジスタはビッグエンディアンだから奇数番地は下位ビットになるのかな。
ポートなんとかデータレジスタはアクセスサイズが8bitもあるから、byteアクセスでやっていけば全ポートをビット操作可能なのかもしれない。
SHCもインストールしてみるかな?
byteアクセス可能なら、全ポートをビット操作できるみたいですね shc
bitOperati 30 PA.DR.BIT.B0 = 0;
00000000 02E03800 MOVI20 #-116736,R2; H'FFFE3800
00000004 32090003 BCLR.B #0,@(3,R2)
bitOperati 31 PA.DR.BIT.B0 = 1;
00000008 32091003 BSET.B #0,@(3,R2)
bitOperati 32 PA.DR.BIT.B8 = 0;
0000000C 32090002 BCLR.B #0,@(2,R2)
bitOperati 33 PA.DR.BIT.B8 = 1;
00000010 32091002 BSET.B #0,@(2,R2)
RL78 も純正のコンパイラはそういうコードを吐くのに対して GCC はそうではないところで KURUMI のライブラリがトラブってた気がしますね。
でも SHC 使っても digitalWrite() のポートアクセスは BSET/BCLR にはならん気がするな。
SHC インストールしてみるか…。
SHC を試してみましたがやはり BSET/BCLR 命令は吐いてくれないみたいですね。
00001066 4EF0 _digital MOVMU.L R14,@-R15 00001068 7FF8 ADD #H'F8,R15 0000106A 6E53 MOV R5,R14 0000106C 65F3 MOV R15,R5 0000106E 7504 ADD #H'04,R5 00001070 B015 BSR @_get_reg_info:12 00001072 66F3 MOV R15,R6 00001074 2008 TST R0,R0 00001076 890F BT @H'1098:8 00001078 35F19002 MOVU.W @(H'0004:12,R15),R5 0000107C 06E03800 MOVI20 #H'E3800,R6 00001080 2EE8 TST R14,R14 00001082 356C ADD R6,R5 00001084 8F05 BF/S @H'1092:8 00001086 6251 MOV.W @R5,R2 00001088 64F1 MOV.W @R15,R4 0000108A 6647 NOT R4,R6 0000108C 2269 AND R6,R2 0000108E A003 BRA @H'1098:12 00001090 2521 MOV.W R2,@R5 00001092 66F1 MOV.W @R15,R6 00001094 226B OR R6,R2 00001096 2521 MOV.W R2,@R5 00001098 7F08 ADD #H'08,R15 0000109A 4EF4 MOVMU.L @R15+,R14 0000109C 006B RTS/N
GCC が SH-2A 用に BSET 命令を吐いてくれることを期待したアレも、
00001000 2558 _bset TST R5,R5 00001002 8910 BT @H'1026:8 00001004 6053 MOV R5,R0 00001006 8801 CMP/EQ #H'01,R0 00001008 8911 BT @H'102E:8 0000100A 8802 CMP/EQ #H'02,R0 0000100C 8913 BT @H'1036:8 0000100E 8803 CMP/EQ #H'03,R0 00001010 8915 BT @H'103E:8 00001012 8804 CMP/EQ #H'04,R0 00001014 8917 BT @H'1046:8 00001016 8805 CMP/EQ #H'05,R0 00001018 8919 BT @H'104E:8 0000101A 8806 CMP/EQ #H'06,R0 0000101C 891B BT @H'1056:8 0000101E 8807 CMP/EQ #H'07,R0 00001020 891D BT @H'105E:8 00001022 A01F BRA @H'1064:12 00001024 0009 NOP 00001026 6240 MOV.B @R4,R2 00001028 8628 BSET #0,R2 0000102A 000B RTS 0000102C 2420 MOV.B R2,@R4 0000102E 6240 MOV.B @R4,R2 00001030 8629 BSET #1,R2 00001032 000B RTS 00001034 2420 MOV.B R2,@R4 00001036 6240 MOV.B @R4,R2 00001038 862A BSET #2,R2 0000103A 000B RTS 0000103C 2420 MOV.B R2,@R4 0000103E 6240 MOV.B @R4,R2 00001040 862B BSET #3,R2 00001042 000B RTS 00001044 2420 MOV.B R2,@R4 00001046 6240 MOV.B @R4,R2 00001048 862C BSET #4,R2 0000104A 000B RTS 0000104C 2420 MOV.B R2,@R4 0000104E 6240 MOV.B @R4,R2 00001050 862D BSET #5,R2 00001052 000B RTS 00001054 2420 MOV.B R2,@R4 00001056 6240 MOV.B @R4,R2 00001058 862E BSET #6,R2 0000105A 000B RTS 0000105C 2420 MOV.B R2,@R4 0000105E 6240 MOV.B @R4,R2 00001060 862F BSET #7,R2 00001062 2420 MOV.B R2,@R4 00001064 006B RTS/N
メモリへの BSET/BCLR 命令は吐いてくれないみたいなので、結局は GCC と同じくインラインアセンブラかなんかが必要になるのかな? それ用のコンパイラなのだから内蔵関数とかの機能でサポートはあっても不思議はないが。
japan.renesas.com/.../sh_compiler_features_child.jsp 見たら
void bset(unsigned char *data1, unsigned char data2) メモリ上の指定ビットに1を設定する。 (SH-2A,SH2A-FPU) void bclr(unsigned char *data1, unsigned char data2) メモリ上の指定ビットに0を設定する。 (SH-2A,SH2A-FPU)
やはりそういう機能はサポートされてる模様。
SHC ではこう書くといいらしい。
#include <machine.h> void bsetx(volatile unsigned char* port, int bit) { switch (bit) { case 0: bset(port, 0); break; case 1: bset(port, 1); break; case 2: bset(port, 2); break; case 3: bset(port, 3); break; case 4: bset(port, 4); break; case 5: bset(port, 5); break; case 6: bset(port, 6); break; case 7: bset(port, 7); break; } }
00001000 2558 _bsetx TST R5,R5 00001002 8910 BT @H'1026:8 00001004 6053 MOV R5,R0 00001006 8801 CMP/EQ #H'01,R0 00001008 8910 BT @H'102C:8 0000100A 8802 CMP/EQ #H'02,R0 0000100C 8911 BT @H'1032:8 0000100E 8803 CMP/EQ #H'03,R0 00001010 8912 BT @H'1038:8 00001012 8804 CMP/EQ #H'04,R0 00001014 8913 BT @H'103E:8 00001016 8805 CMP/EQ #H'05,R0 00001018 8914 BT @H'1044:8 0000101A 8806 CMP/EQ #H'06,R0 0000101C 8915 BT @H'104A:8 0000101E 8807 CMP/EQ #H'07,R0 00001020 8916 BT @H'1050:8 00001022 A017 BRA @H'1054:12 00001024 0009 NOP 00001026 34091000 BSET.B #0,@(H'0000:12,R4) 0000102A 006B RTS/N 0000102C 34191000 BSET.B #1,@(H'0000:12,R4) 00001030 006B RTS/N 00001032 34291000 BSET.B #2,@(H'0000:12,R4) 00001036 006B RTS/N 00001038 34391000 BSET.B #3,@(H'0000:12,R4) 0000103C 006B RTS/N 0000103E 34491000 BSET.B #4,@(H'0000:12,R4) 00001042 006B RTS/N 00001044 34591000 BSET.B #5,@(H'0000:12,R4) 00001048 006B RTS/N 0000104A 34691000 BSET.B #6,@(H'0000:12,R4) 0000104E 006B RTS/N 00001050 34791000 BSET.B #7,@(H'0000:12,R4) 00001054 006B RTS/N
bset()/bclr() の第2引数に定数しか指定できないので switch ~ case は必要。そのコストを考慮すると digitalWrite() では BSET/BCLR 命令にこだわらないでポート読み書きの前に必要に応じて割り込み止めたほうが利口。
お、売ってるな。
www.marutsu.co.jp/shohin_238992
www.marutsu.co.jp/shohin_239038
変換基板とSH基板の間が随分開いているのは、E10Aのコネクタ装着時に干渉するからです。
書き込みはE10AまたはFDTからでないとできません。GR-SAKURAの様なストレージのイメージは見えません。
FDTからなのでDIPスイッチの設定が必要ですが、変換基板を搭載するとまったく触る事ができないので書き換えのたびに変換基板を外す必要があります。
以上、どうせ知れることですから。
あと、Arduinoのシールドを搭載すると、すんごくオフセットして搭載することになります。