【L-RTK】LunchBox内にμSDカードロガー作った<mbed SDFileSystemで手間取った>

スマホRTKモニターは出来たけど、全UBXデータをバイナリーでログも、モニターと一緒に処理するのは、BT受信とスマホでは厳しいだろうということで、LuchBox内のNucleoF446REのSPIにSDカードを接続して、ログすることにしました。
現在は、μSDカードですが、後日、FlashAirのSDカードスロットに変更して
MovingBaseのUBXのフルデータも無線で吸い取れるようにします。

●SDカードログ
以前からセンサデータをSDカードにログすることをトライしてきました。
ロードバイクのパワーメーターの場合数msec周期で休みなく10chのデータが
飛び込んでくるので、マイコンのSDカードプログラムでは、バッファオーバーフローしてしまって、使えなかったのですが、F9Pは、トータルスループットが200msecとセンサとしては非常に遅いデバイスなので、SDカードで余裕でログできました。
だいたいの時間は、BTのスマホモニターデータ送信で5msec+SDへ172バイト書き込み5msec~10msec程度で全部仕事ができてしまいました。
本当に忙しいのは、F9Pから460800bpsで172バイトを送信されてくる瞬間だけで、
あとの190数msecは、暇をもてあそぶという感じです。

●mbedのSDFilesystemライブラリーが動かない
ここ1年半で、mbed OSが大きく変更されて、マルチスレッドになりました。
昔作った、SDファイル用プログラムが全然動かなくなってしまいました。
そこで、KenjiArai様がパッチをあてて公開されている、SDFilesystem.hと
サンプルプログラムで何とか動作させることができました。
mbed内のKenjiArai様のSDカードのNOTEです。
 https://os.mbed.com/users/kenjiArai/notebook/sd-card-control-new/#

ここでは、SD CARD CONTROLという、カード用のUTILITYプログラムを公開されてますがここで使われているSDFilesysytemライブラリーでないと現在のmbedOSではSDカード接続できません。
最新のOS5で使いこなすためにはmbedのFORUMで学習しないとできそうもないので、OS5のSDカード読み込みは、PellionDeveiceを始める機会からやります。


●SDカードプログラム
まずは基礎的に動作させる確認用プログラムを作りました。
SDFileSystem.hは、こちらのページからダウンロードします。
https://os.mbed.com/users/kenjiArai/code/SD_Card_Control/
control用のライブラリーは使わないので、SDFileSystem.hだけで動作します。
常に最新のバージョンにしてアップデートしたほうがいいです。
間違えやすいのは、SPIの結線です。
はまるのは、結線が長すぎてノイズだらけになってしまう場合あるのでSPIは注意です。

// example writing to SD card, sford
//0a_SDFileSystem_HelloWorld_F446reOK_upOK#include “mbed.h”
#include “SDFileSystem.h”
Serial pc(USBTX,USBRX);
//SDFileSystem sd(PB_5, PB_4, PB_3, PA_4,”sd”); // L432KC SPI3 the pinout on the mbed Cool Components workshop board
//SDFileSystem sd(PA_7, PA_6, PA_5, PB_6,”sd”); // FF446 SPSi1 the pinout on the mbed Cool Components workshop board
Timer t;
int n;
int main() {
pc.baud(115200);
SDFileSystem sd(PA_7, PA_6, PA_5, PB_6,”sd”); // FF446 SPSi1 the pinout on the mbed Cool Components workshop board
wait(1);
int i;
pc.printf(“Hello World!00\n”);

mkdir(“/sd/mydir”, 0777);
wait(0.1);
FILE *fp = fopen(“/sd/sdtestNum.txt”, “w”);
wait(1);
if(fp == NULL) {
error(“Could not open file for write\n”);
}
t.start();
while(1){
n++;
for (i=0;i<172;i++){
fprintf(fp, “%d,”,n);
//wait(0.05);
//pc.printf(“i=%d\n\r”,i);
}
fprintf(fp,”%d\n\r”,t.read_ms());
//fclose(fp);
//printf(“Goodbye World!i=%d time=%d\n”,i,t.read_ms());
}
}

●SDカードスロットで性能が違う
中華SDカードスロットを2種類使ってみたのですが、ICがのっている高級なほうが
安定性が良かったです。
SDカードスロットとDIP基板は、なかなか当たりはずれがあるので、
秋月の実績のあるもののほうが安心です。中華スロットは怖いです。

●本番プログラムへ組み込み作業
メモ1:初期設定で、F9Pから時刻データiTowを読んで、ファイル名を時刻にするのですが、F9PからまともにiTowがでてくるまで、待ってからでないと時刻が出てこないので、待ちループをいれて、iTowを得てからファイルOPENしました。

メモ2:MovingBaseモードのUBXデータは、NAV-PVTとNAV-RELPOSNEDだけですが、デリミターが一切ないバイナリデータなのでヘッダをみつけて、判定するのに4バイト比較しないとPVTのヘッダがつかまりません。一度ヘッダを捕まえれば、あとは、172バイトごとにカウントしていけば、ぴったり受信できます。

メモ3:ログの停止機能がついてないので、電源遮断でログが停止するのですが
fclose()をいれなくても自動FLUSHが働いていて常ログされてました。

 

メモ4:デバッグでデータがSDにきちんと書き込まれているか確認するのにバイナリーエディタとTeraTermを使って、最後は、電卓でバイト数を確認しました。
急に電源オフすると、SDカードのバッファに残ったデータは、SDに書き込まれないで捨てられることがわかりました。大体3センテンスくらいは捨てられます。

●F446REのSDカードログとBTモニター送信機能プログラムソース
mbedオンラインコンパイラです。
あちこちにdebug用pc.printfが埋まってますが、必要ないので消して使います。

//0a_BT_RELPOSNED_Calc_rev05_SD_LunchBox

#include “mbed.h”
#include “SDFileSystem.h”
Serial pc(USBTX,USBRX);
Serial F9P(PC_6,PC_7);;//F9P uart1 TX,RX-F446RE Serial6 TX,RX 5.62MHz
Serial BT(PA_9,PA_10);//Xbee TX,RX F446RE Serail TX,RX 5.62MHz
//SDFileSystem sd(PA_7, PA_6, PA_5, PB_6,”sd”); // F446 SPSi1 the pinout on the mbed Cool Components workshop board
Timer t;
DigitalOut myled(LED1);
int flag=1;
int Fflag=1;//SD record Flag 1=GO 0=NOGO
int t0,t1;
int datanum=1000;// sampling data suu
char flname[]={};
int rcvFlag=0;
int Floatflag=1;
//==================UBX_DEC parameters==========================
long relN;
long relE;
long relD;
long Length;
long Long;
long Lati;
long Seah;
long Acc2d;
char numSV;//satellite number
long iTow;
int iTows;
long su;
int sNo;//pvt start
int rNo;//relposned start
int i=0;
int j=0;
char sen[]={};
unsigned char c;
unsigned char bData[]={0xB5,0x62,0x1,0x7,0x5C,0x0,0x60,0xDA,0x2D,0xB,0xE4,0x7,0x2,0x4,0x4,0x5,0x24,0x37,0x1,0x0,0x0,0x0,0x28,0xBD,0xDD,0x17,0x3,0x83,0xEA,0x15,0x35,0x7,0x30,0x52,0x6E,0x95,0xEB,0x15,0xE6,0xF2,0xD,0x0,0x0,0x65,0xD,0x0,0x88,0x0,0x0,0x0,0x86,0x0,0x0,0x0,0x9,0x0,0x0,0x0,0xFA,0xFF,0xFF,0xFF,0x8,0x0,0x0,0x0,0xB,0x0,0x0,0x0,0xF2,0x4A,0x18,0x0,0xDA,0x0,0x0,0x0,0x80,0xA8,0x12,0x1,0x7B,0x0,0x0,0x0,0xBA,0x65,0x43,0x2C,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x35,0x5D,0xB5,0x62,0x1,0x3C,0x40,0x0,0x1,0x0,0x0,0x0,0x60,0xDA,0x2D,0xB,0xE8,0xFF,0xFF,0xFF,0x3F,0x0,0x0,0x0,0xA,0x0,0x0,0x0,0x44,0x0,0x0,0x0,0x5A,0x37,0xAA,0x0,0x0,0x0,0x0,0x0,0xA8,0x0,0x24,0x34,0x64,0x0,0x0,0x0,0x64,0x0,0x0,0x0,0x64,0x0,0x0,0x0,0x64,0x0,0x0,0x0,0x6A,0x4A,0x1,0x0,0x0,0x0,0x0,0x0,0x37,0x1,0x0,0x0,0x1A,0xCD};
//================================================================================================================
long B2L(char b4 , char b3 , char b2 , char b1 ) {
//pc.printf(“B2L IN=%s,%x,%x,%x,%x,b4&0x80=%d\n\r”,sen,b4,b3,b2,b1,b4 &0x80);
//pc.printf(“B2L IN=b4&0x80=%d\n\r”,b4 & 0x80);if ((b4 & 0x80) && 0x80){//最上位ビットたっていればマイナス
su = -(256-(int)b1)+(255-(int)b2)*256+(255-(int)b3)*65536+(255-(int)b4)*256*256*256;
//pc.printf(“B2L-:sen=%s,%d,%d,%d,%d,%d\n\r”,sen,b4,b3,b2,b1,su);
}
else {
su=(int)b1+(int)b2*256+(int)b3* 65536+(int)b4*256*256*256;
//pc.printf(“B2L+:sen=%s,%d,%d,%d,%d,%d,%d\n\r”,sen,b4,b3,b2,b1,su);
}return su;
}
//================================================================================================================
void ubx_dec(){
//for (i=0;i<172;i++){
//if (bData[0]==0xB5){
sNo=0;//Default 0 PVT startNo
rNo=100;
//pc.printf(“st:%d\n\r”,t.read_ms());
//}
//}

//pc.printf(“Long_sNo+33,32,31,30=%d,%d,%d,%d\n\r”,bData[sNo+33],bData[sNo+32],bData[sNo+31],bData[sNo+30]);
//sen[0]=’L’;sen[1]=’o’;

Long=B2L(bData[sNo+33],bData[sNo+32],bData[sNo+31],bData[sNo+30]);//上位ー>下位
//pc.printf(“Lati_sNo+37,36,35,34=%d,%d,%d,%d\n\r”,bData[sNo+37],bData[sNo+36],bData[sNo+35],bData[sNo+34]);
//sen[0]=’L’;sen[1]=’a’;
Lati=B2L(bData[sNo+37],bData[sNo+36],bData[sNo+35],bData[sNo+34]);
//pc.printf(“Seah_sNo+45,44,43,42=%d,%d,%d,%d\n\r”,bData[sNo+45],bData[sNo+44],bData[sNo+43],bData[sNo+42]);
//sen[0]=’S’;sen[1]=’h’;
Seah=B2L(bData[sNo+45],bData[sNo+44],bData[sNo+43],bData[sNo+42]);
//pc.printf(“Acc2d_sNo+49,48,47,46=%d,%d,%d,%d\n\r”,bData[sNo+49],bData[sNo+48],bData[sNo+47],bData[sNo+46]);
//sen[0]=’A’;sen[1]=’c’;
Acc2d=B2L(bData[sNo+49],bData[sNo+48],bData[sNo+47],bData[sNo+46]);
//pc.printf(“relN_rNo+17,16,15,14=%d,%d,%d,%d\n\r”,bData[rNo+17],bData[rNo+16],bData[rNo+15],bData[rNo+14]);
//sen[0]=’r’;sen[1]=’N’;
relN=B2L(bData[rNo+17],bData[rNo+16],bData[rNo+15],bData[rNo+14]);
//pc.printf(“relE_rNo+21,20,19,18=%d,%d,%d,%d\n\r”,bData[rNo+21],bData[rNo+20],bData[rNo+19],bData[rNo+18]);
//sen[0]=’r’;sen[1]=’E’;
relE=B2L(bData[rNo+21],bData[rNo+20],bData[rNo+19],bData[rNo+18]);
//pc.printf(“Length_rNo+29,28,27,26=%d,%d,%d,%d\n\r”,bData[rNo+29],bData[rNo+28],bData[rNo+27],bData[rNo+26]);
//sen[0]=’L’;sen[1]=’e’;
relD=B2L(bData[rNo+25],bData[rNo+24],bData[rNo+23],bData[rNo+22]);
Length=B2L(bData[rNo+29],bData[rNo+28],bData[rNo+27],bData[rNo+26]);
numSV=bData[sNo+29];
iTow=B2L(bData[sNo+9],bData[sNo+8],bData[sNo+7],bData[sNo+6]);
iTows=(iTow/1000)%86400;
//pc.printf(“Long=%d,Lati=%d,Seah=%d,Acc2d=%d\n\r”,Long,Lati,Seah,Acc2d);

//pc.printf(“et:%d,\n\r”,t.read_ms());

}
//====================================f9P rcv=======================================
void F9Prcv(){
if(F9P.getc()==0xb5){
bData[0]=0xb5;
bData[1]=F9P.getc();//0x01
bData[2]=F9P.getc();//0x62
bData[3]=F9P.getc();//0x07
if (bData[3]==0x07){
for(i=4;i<172;i++){ //header had recieved
bData[i]=F9P.getc();// F9P data recieving
}
//rcvFlag=1;
}

}
}

//=======================================================================================================
int main() {
pc.baud(115200);
F9P.baud(460800);
BT.baud(115200);
wait(0.5);
pc.printf(“SDFILESYSTEM def\n\r”);
//+++++++++++++++ Filename Timestump reading+++++++++++++++++++++++
while(Floatflag){
F9Prcv();
ubx_dec();
if(iTows>10000){Floatflag=0;}
}

sprintf(flname,”/sd/%d.ubx”,iTow);
pc.printf(“flaname=%s,iTow=%d\n\r”,flname,iTow);
wait(1);
SDFileSystem sd(PA_7, PA_6, PA_5, PB_6,”sd”); // F446 SPSi1 the pinout on the mbed Cool Components workshop board
wait(1);
FILE *fp = fopen(flname, “w”);
wait(1);
if(fp == NULL) {
error(“Could not open file for write\n”);
}
//***************************************************
t.start();
j=0;
while(flag){
F9Prcv();
//wait(0.1);
//===============PVT,RELPOSNED CalResult BT send===========
ubx_dec();
BT.printf(“%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,\n”,j,Long,Lati,Seah,relN,relE,relD,Length,Acc2d,numSV,iTows,t0);
j++;
rcvFlag=0;

//*******************SD WRITING**********************************
for (i=0;i<172;i++){
fputc(bData[i],fp);
}
pc.printf(“j=%d,time=%d\n\r”,j,t.read_ms());
//if(j>10){
// flag=0;
// pc.printf(“End j=%D\n\r”,j);
//}
}//while
fclose(fp);
pc.printf(“data_finished total=%d\n\r”,t.read_ms());

}

 

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です