PIC18F14K50+HIDブートローダ~その2~

前回ArduinoUNOを使った書き込み機で、PIC18F14K50のコンフィグビット0x30002番地に0x01を書いたのに読出したら0x21になってしまう件を書きました。
違いはbit5が0か1かで、このbitはデバイス上で何にも割り当てられず、データーシートによると割り当てが無いbitは0として読み出される筈なのに1が出てきているという謎でした。

因みにHID版ブートローダーをビルドするとこの番地は0x01ですがMCHPUSB版ブートローダーでは0x21になっています。この違いがなぜあるのか、特にMCHPUSB版をビルドすると割り当てのないbitがなぜ立つのかは気になりますが、これについてはその内調べたいと思います。で、その前に今回はArduinoに載せたスケッチがバグっているのか、またはPICKit3が何か細工をしているのかを確かめたくて波形を見てみました。

といってもわが家のオシロスコープは古くてこの出力をピンポイントで見るのは困難です。そこであるところからAnalogDiscovery2を借りてきました。

AnalogDiscovery2

そしてまずArduinoUNOで0x30002番地を読み出す瞬間の波形がこれ。
上段の波形がクロックでこの下りエッジで下段のデータを読み取ります。データはLSB側から出てくるので左右反転すると00100001=0x21と読めます。やっぱりデバイスから0x21が出ているんですね。

Arduinoで読み取る瞬間(0x21と出ている)

次にPICKit3で読み出す瞬間も見てみます。こちらはクロックがだいぶ早いですがやはり同じ様に0x21が出ています。

PICKit3で読み取る瞬間(こちらも0x21と出ている)

・・・という事でArduinoに書いたスケッチでもPICKit3でも波形的には’0x21’が出ています。なのにPICKit3の画面には’0x01’と表示されているのは恐らく使用していないbitを無条件に0として表示しているのだと思います。

Arduino用スケッチはどういう対策するのが正しいのでしょう?
使っていないbitなので書き込んだのと違う値が読めるのは当然と考えれば「ベリファイからこのbitは除外」が正解なのかな。でも単に読み出して表示する時には「読んだ通りに表示」しないと紛らわしい気がします。
表示する値とベリファイする値が異なるのは気持ち悪いけど「ベリファイ時は未使用bitを除外し、表示の際は読んだ通りに表示」かな。

というか、そもそも未使用bitなのであまり深く考える必要もないか・・・。

PIC18F14K50+HIDブートローダ

PIC18F14K50にArduino+9V電池方式でHIDブートローダを書込んでみたらベリファイでエラーが出ました。
コンフィグビット0x30002番地に0x01を書いたのに読出したら0x21になっています。

300000+    0  1  2  3  4  5  6  7  9  9  A  B  C  D
書込値 :00 32 01 1e -- 00 01 -- 03 c0 03 e0 03 40
Arduino読:00 32 21 1e 00 00 01 00 03 c0 03 e0 03 40
PICkit3読:00 32 01 1e 00 00 01 00 03 c0 03 e0 03 40

PICKit3で読むと0x01ですがArduinoだと0x21になるのです。
違いはbit5が0か1かですが、このbitはデバイス上で何にも割り当てられていません。PIC18F14K50のデーターシートによると割り当てが無い番地は0として読める事になっているのでPICkit3の結果が正しくArduinoの結果が間違いです。

しかしArduinoのスケッチを見ていますが特に問題なさそうに見えます。またこの番地のこのbit以外は問題が発生していないのも納得がいきません。因みにデバイスを交換しても変化なしでした。

書込み自体はできており問題なく動作はするのですが・・・謎です。

ArduinoでPICマイコンに書込む~AE-PIC18F14K50編~

先日HOI-Linkを製作した時、秋月電子のPIC18F14K50基板「AE-PIC18F14K50」Arduiono UNOを使ってブートローダーを書き込みました。その際以前書いた「ArduinoでPICマイコンに書込む~OpenStickLite(PIC18F14K50)編~」とは若干変更する必要がありました。
またブートローダーだけでなくHOI-Linkのファーム全体を書いてみました。
なおArduinoに入れる書込み用スケッチにミスっていた箇所があったので修正版を掲載しています。

AE-PIC18F14K50基板は秋月電子で¥800 (現時点) で売られています。DIPパッケージ単体では¥220ですが発振子やUSBコネクタも買う事を考えると基板もそんなに割高ではありません。
以前DIP版のPIC18F14K50にArduinoからブートローダーを書き込んだのと同様にこの基板にも書込んでみました。

前回DIPパッケージ版と今回のAE-PIC18F14K50とで異なるところ

前回の回路図はこれ。この時マイコンのVDDにはArduinoから3.3Vを供給し、VUSB端子もVDDに直結していました。

PIC14K50WriteByUNOsch
ArduinoUNOでPIC18F14K50に書き込んでみた回路図。

一方AE_PIC18F14K50基板はVUSB端子が外部に出ていません。VUSBはチップ内にレギュレータを持っていて3.3Vが出力されるのでVDDに少し高い電圧(まあ5Vですよね)を入れてやればVUSBには外から印加する必要はありません。PICkit3でもそうなっていますしね。

という事で次の様な回路で上手くいきました。
上と違うのは電源を5Vに変えたのとVUSBには接続していない事。
なおVUSB端子はGNDとの間にコンデンサを接続する必要がありますがAE-PIC18F14K50は基板内に0.22μFを内蔵しています。

AE-PIC18F14K50基板に書き込む配線

ブートローダーだけでなくファームウェア本体も書いてみる。

といつもはブートローダーだけを書き込み、そのブートローダーから本体のファームウェアを書き込んでいました。今回ちょっと試しにブートローダー+HOI-Linkのファーム全体を書き込んでみます。

まずその前に書き込みデータを作ります。PICkit3を接続してファーム書込み済のマイコンからプログラムを読み出し、HEXファイルに書きだしました。このファイルにはフラッシュに書かれたプログラムとコンフィグデータ以外にEEPROMの内容も含んでいます。しかしArduino上の書込みスケッチをEEPROMには対応させていないのでテキストエディタでEEPROMに関する行を消しておきます。

そして出来たのがこのファイル→HOI-LinkAndBootloader.zip
解凍すると次のHEXファイルが出てきます。
HOI-LinkAndBootloader.hex
これをメモ帳で開いてTeratermにコピペする事でAE-PIC18F14K50に書き込みます。このあたりの手順は前回の記事に書いています。

そしてファーム全体を書き込むと1分程度で何事もなく終わりました。
因みにブートローダーだけだと約10秒です。Teratermの設定で速度を下げているので専用PICライタに比べると時間が掛かりますが、これは 書き込みデータ全てを Arduinoのメモリーに保存できないのでシリアル通信でPCから順次送りながら書き込んでいる為です。この時PCとArduinoの間でフロー制御できればよいのですが、Arduinoの素の状態ではこれが出来ないので送り込み速度の方を落としているのです。

続いてベリファイをしてみると・・・なんだかエラーが出ます。調べてみるとArduino上の書込みスケッチのベリファイルーチンでチェックサムの計算をミスっていたので、これを修正するとベリファイもエラー無く終了しました。
なお書込みルーチンでもチェックサムを計算していますがこちらは正常です。
書き込みとベリファイは殆ど同じ処理なので上手くサブルーチンで共有すればいいのに面倒になってコピペで作成した為、デバッグの時にベリファイ側の修正を忘れていた様です。

修正版のArduino UNO用書込みスケッチ→PICWrite18F14K50_190621.zip

という事で・・・

秋月電子のAE-PIC18F14K50基板に専用PICライタを使わずファームを書き込めるようになりました(Arduinoは必要ですけど)。 直接ファームを書いても良し、ブートローダーを書いてUSB経由でファームを送り込むのも良しでお手軽にUSB工作が楽しめます。

3Dプリンタ2号機~その8~

やっぱり二代目3Dプリンターにラズパイを取付けました。
初代RaspberryPiのModelBです。

3dp28_1

Raspberry Piをねじ止め。

ラズパイにモニターやキーボードは取付けていませんが、Xwindowの画面をメインPCに飛ばしPronterfaceを実行できます。
又はTeratermでログインしてPronsoleを使う事も。。。

フロントパネルにはラズパイ専用の電源スイッチとシャットダウンボタンを設置したのでLCDコントローラだけで動作させる場合にはラズパイ電源はOFFにできます。

3dp28_2

手持ちのスイッチを取付け。

なお特に対策をしなければラズパイ専用電源をOFFにしてもArduinoからの電圧でラズパイのLEDが点いてしまいます。正常動作する程の力はない様ですがArduino側のレギュレータに負荷が掛かりそうです。気持ち悪いのでUSBコネクタの+5V端子にカプトンテープを貼って絶縁するという、いい加減な対策をしました。

3dp28_3

USBコネクタの+5V端子を絶縁。

 

これで3Dプリンタ2号機は一旦完成とします(多分まだ何かやりますが)。

3dp28_4

どどーんはじめました。~その3~

今回のマルチコプターでS.BUSを初めて使ったので信号をArduinoで読み出してみました。
S.BUSとは何かという詳しい説明はコチラ→https://ja.wikipedia.org/wiki/S.BUS
要はラジコン受信機から昔ながらのサーボ信号を出すのではなくシリアル通信にする事で全チャンネルを1本の信号線で制御するという物です。

飛行機の場合はサーボの位置が分散しているので結局それぞれに配線する必要があり、あまりメリットを感じませんでした。しかしマルチコプターでは受信機の信号は全てフライトコントローラ基板に接続するのでこれが一本で済むのは大きなメリットになります。

S.BUS信号はシリアル通信ですが、UARTでよく使う仕様とは微妙に違うところがあり面倒になっています。例えば次のところ・・・

  • ボーレートが100Kbps。
    なぜか115.2Kbpsではなく100Kbpsです。妙なボーレートですがArduinoではSerialBegin()のとき100000と指定する事で対応できます。
  • 信号極性が逆転。
    Arduinoに入れる信号はインバータで反転してやる必要があります(もしかするとArduino側に反転機能があるのかもしれませんが見つけられませんでした)。

あと受信後のデータが11bit区切りなので並べ替えがややこしいです。

S.BUSプロトコルに詳細はこちらを参考にしました。→https://os.mbed.com/users/Digixx/notebook/futaba-s-bus-controlled-by-mbed/http://anarchy.hatenablog.com/entry/2014/12/07/181853

そして最低限の部分をスケッチに書きます。

int count;
long interval;
void setup() {
 Serial.begin(115200); // Terminal
 Serial1.begin(100000,SERIAL_8E2); // S-BUS
 count=0;
}

void loop() {
 int data[26];
 int val[19];
 int i;
 if (Serial1.available() > 0) {
 data[count]=Serial1.read();
 interval=millis();
 count++;
 }
 if ((interval+4 < millis()) && (0 < count) ) {
 count=0;

 val[0] =((data[1] & 0xff)<<0) + ((data[2] & 0x07)<<8);
 val[1] =((data[2] & 0xf8)>>3) + ((data[3] & 0x3f)<<5);
 val[2] =((data[3] & 0xc0)>>6) + ((data[4] & 0xff)<<2) + ((data[5] & 0x01)<<10);
 val[3] =((data[5] & 0xfe)>>1) + ((data[6] & 0x0f)<<7);
 val[4] =((data[6] & 0x0f)>>4) + ((data[7] & 0x7f)<<4);
 val[5] =((data[7] & 0x80)>>7) + ((data[8] & 0xff)<<1) + ((data[9] & 0x03) <<9);
 val[6] =((data[9] & 0x7c)>>2) + ((data[10] & 0x1f)<<6);
 val[7] =((data[10] & 0xe0)>>5) + ((data[11] & 0xff)<<3);

 val[8] =((data[12] & 0xff)<<0) + ((data[13] & 0x07)<<8);
 val[9] =((data[13] & 0xf8)>>3) + ((data[14] & 0x3f)<<5);
 val[10]=((data[14] & 0xc0)>>6) + ((data[15] & 0xff)<<2) + ((data[16] & 0x01)<<10);
 val[11]=((data[16] & 0xfe)>>1) + ((data[17] & 0x0f)<<7);
 val[12]=((data[17] & 0x0f)>>4) + ((data[18] & 0x7f)<<4);
 val[13]=((data[18] & 0x80)>>7) + ((data[19] & 0xff)<<1) + ((data[20] & 0x03) <<9);
 val[14]=((data[20] & 0x7c)>>2) + ((data[21] & 0x1f)<<6);
 val[15]=((data[21] & 0xe0)>>5) + ((data[22] & 0xff)<<3);
 val[16] = (data[23] & 0x1) ? 0x7ff : 0 ;
 val[17] = (data[23] & 0x2) ? 0x7ff : 0 ;
 val[18] = (data[23] & 0x8) ? 0x7ff : 0 ; // Failsafe

 for (i=0 ; i<19; i++ ) {
 Serial.print(val[i],DEC);
 Serial.print(F(" "));
 }
 Serial.print(F("\n"));
 }
}

S.BUSから取り込んだデータをUSB経由でシリアルモニタに表示したいので、シリアルポートが複数あるArduino MEGA2560で動かしてみます。

S.BUSモニタ

Arduino MEGA2560でS.BUSをモニター。
ブレッドボード上のICは信号極性反転のための74HC00。

 

こんな感じでデータが出てきました。
送信機が6CHなので7CH以降が正しいかどうかは確かめられていません。また19番目のデータはFailsafeが働いたときに1になるはずですが、これも確かめていません。

S.BUS monitor

モニター中。

各データが11bitt幅なので0~2047が表せるはずで、どうやらニュートラルが1024の様です。
ところでCleanflightにも受信データを表示する機能があります。しかし今回のモニターとCleanflightの値が一致しません。そこで何ポイントか対応を取ってみました。

 SBUSモニタ Cleanflight
       102         943
       697        1315
      1024        1520 ←ニュートラル
      1435        1776
      1681        1930

グラフにすると・・・

SBUS-CleanFlight

SBUSとCleanFlightの読値対応

恐らくCleanflightの表示値は昔ながらのPWMサーボ信号のパルス幅に換算した値をμS単位で表示しているのだと思います。例えばニュートラルはS.BUSの生データは1024ですがPWMだと1520μSといった感じ。
ということでS.BUSの生の値にざっと0.625掛けて879.5を足すとほぼCleanFlightの値になる様です。