PSoCでSDカードにGPSログを保存する


psoc_gps_sd_01.gif
今回はGPSからRS-232C経由で取得できる緯度経度のログデータをSDカードに保存してみる。
GPSユニットは「PSoCとGPSモジュールで経緯度を表示する」で用いたのと同じものを使った。
前回の「PSoCでSDカードに書き込む」でSDカードをPSoCから(実用的に)使うのは無理と感じたが、"なんとかなるかもしれない"という淡い希望を抱き作業した。結論は...やはりダメだった。GPSログをSDカードに保存はできるが、信頼性がなさすぎてとても実用にはできない。

psoc_gps_sd_02.gif
前回作成した「PSoCでSDカードに書き込む」のプロジェクトをPSoC Designerで開く。そして「View」メニューの「Device Editor」を選択して画面を切り替える。


psoc_gps_sd_03.gif
さらに「Config」メニューの「Selection」を選択してモジュール選択画面に切り替える。

psoc_gps_sd_04.gif
ここでGPSからのデータを受信するためのモジュールを追加する。「Digital Comm」にある「RX8」を右クリックして現れるメニューから「Select」を選択する。

psoc_gps_sd_05.gif
追加された「RX8_1」というアイコンを右クリックして現れるメニューから「Rename」を選択して名前を「RX8」に変更する。

psoc_gps_sd_06.gif
名前の変更までできたら、「Config」メニューの「Interconnect」を選択して配線設定画面に切り替える。

psoc_gps_sd_07.gif
そして「RX8」のアイコンを右クリックして現れるメニューから「Place」を選択して配置する。

psoc_gps_sd_08.gif
前回行ったプロジェクトの設定で「VC1」が「6」、「VC2」が「8」になっているが、さらに...
「VC3 Source」を「VC2」に、
「VC3 Divider」を「13」にする。そして「RX8」の設定欄で
「Clock」を「VC3」に、
「Input」を「Row_0_Input_0」に、
「ClockSync」を「Sync to SysClk」に、
「RxCmdBuffer」を「Disable」に、
「RxBufferSize」を「128 Bytes」にする。これでGPSからの信号を4800bpsで受信できるようになる。

psoc_gps_sd_09.gif
とは言うもののどのポートから受信するかの設定がまだなので、「RX8」の入力が「Port_0_0」からになるように配線する。

psoc_gps_sd_10.gif
配線が終わったら「View」メニューの「Application Editor」を選択してソースコード編集画面に切り替える。

psoc_gps_sd_11.gif
ここで「main.c」の中に処理を書く。
今回はGPSから受信するデータのうち「$GPRMC」と「$GPGGA」データをSDカードに保存し、ほかのデータは無視している。GPSから届くデータを全て書き込めるほど高速にSDカードへ書き込めないためだ。受信割り込み処理でバッファーを複数確保して切り替えながらSDカードへ保存するなどの方法も試したが速度的に間に合わなかった。


//----------------------------------------------------------------------------
// C main line
//----------------------------------------------------------------------------

#include <m8c.h> // part specific constants and macros
#include "PSoCAPI.h" // PSoC API definitions for all User Modules

#include "stdlib.h"

//#define _DEBUG

// Can not retreave last data of CSV
BOOL GetCSVData(char* pszCSV,int nIndex,char** ppszStart,char** ppszEnd)
{
int i;
int nFind;

if(nIndex < 0)
return FALSE;

*ppszStart = pszCSV;
*ppszEnd = pszCSV;
nFind = 0;
i = -1;
while(1)
{
i++;
if(pszCSV[i] != ',')
continue;

nFind++;

if(nFind == nIndex)
*ppszStart = &(pszCSV[i+1]);
if(nFind == nIndex + 1)
{
*ppszEnd = &(pszCSV[i-1]);
return TRUE;
}
}

return FALSE;
}


BOOL IsFileExist(char* pszFileName)
{
char fp;

fp = SDCard_fopen(pszFileName,"r");
if(fp > SDCard_MAXFILES) // != SDCard_MAXFILES
return TRUE;
// if(fp == SDCard_MAXFILES || SDCard_ferror(fp) & 0x02) //check error flag of "File not found."
if(fp == SDCard_MAXFILES)
{
SDCard_fclose(fp);
return FALSE;
}
if(SDCard_GetFileSize(fp) == 0) //File is empty.
{
SDCard_fclose(fp);
return FALSE;
}
SDCard_fclose(fp);

return TRUE;
}

BOOL OpenSDCardFile(char* pfp,char* pszFileName)
{
int i;

for(i = 0; i < 2; i++)
{
BYTE ret;

*pfp = SDCard_fopen(pszFileName,"a");
#ifdef _DEBUG
LCD_Position(2,0);
LCD_PrCString("fp:");
LCD_PrHexByte(*pfp);
#endif
if(*pfp < SDCard_MAXFILES) // != SDCard_MAXFILES
return TRUE;

ret = SDCard_ferror(*pfp);
SDCard_fclose(*pfp);

#ifdef _DEBUG
LCD_Position(1,4);
LCD_PrCString("error ");
LCD_Position(1,10);
LCD_PrHexByte(ret);
#endif
}

return FALSE;
}


BOOL CreateFileName(char* pszRMCData,char* pszFileName)
{
//LOG file is not open, so make file name and open...
//file name is "ayymmdda.txt" to "zyymmdda.txt"

int j;
int k;
char* pszStart;
char* pszEnd;
BOOL ret;

//file name is made from date, and date data is only in RMC data.
if(!(pszRMCData[3] == 'R' && pszRMCData[4] == 'M' && pszRMCData[5] == 'C'))
return FALSE;

//Get date from RMC data.
ret = GetCSVData(pszRMCData,9,&pszStart,&pszEnd);
if(ret == FALSE || pszStart == pszEnd || pszEnd - pszStart < 5)
return FALSE;

pszFileName[1] = pszStart[4]; //year
pszFileName[2] = pszStart[5];
pszFileName[3] = pszStart[2]; //month
pszFileName[4] = pszStart[3];
pszFileName[5] = pszStart[0]; //day
pszFileName[6] = pszStart[1];

pszFileName[8] = '.';
pszFileName[9] = 't';
pszFileName[10] = 'x';
pszFileName[11] = 't';
pszFileName[12] = 0;


for(j = 0; j < 26; j++)
{
pszFileName[0] = 'a' + j;
for(k = 0; k < 26; k++)
{
pszFileName[7] = 'a' + k;

ret = IsFileExist(pszFileName);
if(ret == FALSE)
return TRUE;
}
}

return FALSE;
}


void main()
{
char fp; // File Pointer

// make Port16 to "strong" for LED
PRT1DM0 |= 0x40;
PRT1DM1 &= ~0x40;
PRT1DM2 &= ~0x40;

// make Port15 to "pull-down" for input sw
PRT1DM0 &= ~0x20;
PRT1DM1 &= ~0x20;
PRT1DM2 &= ~0x20;


#ifdef _DEBUG
LCD_Start();
#endif

SDCard_Start();
{
char cardInfo; // Card information

SDCard_Select(SDCard_ENABLE); // Select card
cardInfo = 0;
while ( ! cardInfo ) // Wait for card to communicate
{
cardInfo = SDCard_InitCard();
}
}

RX8_Start(RX8_PARITY_NONE);
RX8_DisableInt();
M8C_DisableGInt;

fp = SDCard_MAXFILES;
while(1)
{
int i;
int nLen;
char pszBuff[160];

i = 0;
while(1)
{
while ( !(RX8_bReadRxStatus() & (RX8_RX_COMPLETE | RX8_RX_NO_ERROR)))
{
}
pszBuff[i] = RX8_bReadRxData();
if(pszBuff[i] == '\n' && i > 0 && pszBuff[i-1] == '\r')
break;
i++;
if(i >= 158)
i = 0;
}
//pszBuff[i+1] = NULL;
nLen = i + 1;

if(!(pszBuff[0] == '$' && pszBuff[1] == 'G' && pszBuff[2] == 'P'))
continue;

for(i = 0; i <= nLen-3; i++) //pszBuff[nLen-2]=='\r' pszBuff[nLen-1]=='\n'
{
if(pszBuff[i] < 0x20 || pszBuff[i] >= 0x7f)
break;
}
if(i != nLen-2)
continue;

if(!((pszBuff[3] == 'G' && pszBuff[4] == 'G' && pszBuff[5] == 'A')
|| (pszBuff[3] == 'R' && pszBuff[4] == 'M' && pszBuff[5] == 'C')))
continue;

if(fp == SDCard_MAXFILES)
{
BOOL ret;
char pszFileName[13]; //File name is 8.3 format

ret = CreateFileName(pszBuff,pszFileName);
if(ret == FALSE)
{
fp = SDCard_MAXFILES;
continue;
}

#ifdef _DEBUG
LCD_Position(0,0);
LCD_PrString(pszFileName);
#endif

ret = OpenSDCardFile(&fp,pszFileName);
if(ret == FALSE)
{
fp = SDCard_MAXFILES;
continue;
}
#ifdef _DEBUG
LCD_Position(1,0);
LCD_PrCString(" ok ");
#endif
}

#ifdef _DEBUG
LCD_Position(1,0);
LCD_PrHexByte(fp);
#endif


{
BYTE bRet;
PRT1DR |= 0x40; //Busy LED On

bRet = SDCard_fputBuff(pszBuff, nLen, fp);
SDCard_fflush(fp);
if(SDCard_ferror(fp))//bRet == SDCard_EOF)//
{
//error!!
#ifdef _DEBUG
LCD_Position(3,0);
LCD_PrCString(" ");
LCD_Position(3,0);
LCD_PrCString("error ");
//LCD_PrHexByte(SDCard_ferror(fp));
LCD_PrHexByte(fp);
#endif

SDCard_fclose(fp);
fp = SDCard_MAXFILES;
}
PRT1DR &= ~0x40; //Busy LED Off
}

if((PRT1DR & 0x20)) //break sw is on
break;
}
SDCard_fclose(fp);
SDCard_Select(SDCard_DISABLE); // Deselect card
}





_DSC9257.JPG
これでPSocへ書き込んで動かしてみた。ポート00にGPSからの信号線(TX)を接続、ポート15にスイッチ、ポート16にLEDを接続した。

_DSC9258.JPG
今回利用したGPSモジュール。ストロベリーリナックスで6200円程度のもの。今日、新たに追加購入しようかと思い通販ページをチェックしたのだが...残念ながら売り切れていた。

psoc_gps_sd_14.gif
実際にSDカードへ書き込まれたログを見てみると...図のようにまれに文字化けが起きている。文字化けがあるとSDカードの内容が壊れたりするのでプログラム中で変な文字は書き込まないようにチェックを入れているのだが...ダメなようだ。

psoc_gps_sd_13.gif
そしてファイル内容が完全に変な状態になったり...

psoc_gps_sd_12.gif
このようにFATがほとんど壊れてしまったりもする。Windowsで認識できずにフォーマットするしかなくなることもある。
また、利用するSDカードがフォーマット直後でなくファイルがたくさん入っている状態(例えばデジカメで撮った画像が入ったままのSDカード)だと1回の書き込みに数十秒かかるため速度が間に合わず失敗する。

要するに全然使い物にならない。



カテゴリー「電子工作」 のエントリー