Title:Let's try the function on GR-KURUMI, SD Card (SPI) Vol.
Displayed Name:@chobichan
Concept / Overview |
---|
GR-KURUMI can handle SD Card (SPI) easily. Let's try! |
Handling SD Card with microcontroller
GR-KURUMI can handle SD Card easily.
Thanks to this nifty function, GR-KURUMI can keep a log data of sensor by itself without connection to the network.
Let’s log data on temperature and humidity.
Showing the code. A part of the code is omitted since it’s the same as HDC1000 sample.
※Using a SD card library, please keep in mind followings.
1.The file name is not corresponding to long form, the file with long name is dealt with 8+3 form in a compulsory manner.
2.Small letters in file name or directory name is dealt with capital letters. Need to take care on comparison in proceeding program.
3.To reach the file in sub-directory, please access with “FULL PATH”.
4.As generaconpal information about SD Card format, SDFomatter is recommended instead of Windows.
https://www.sdcard.org/jp/downloads/formatter_4/
/*GR-KURUMI Sketch Template Version: V1.12*/ #include#include //for RTC #include //for SD card #include //I2Cを使う為に宣言 #define SD_SS A2 //sd card slave select #define SD_CD A3 //sd card detect この辺り省略 void setup() { Serial.begin( 9600 ); Wire.begin(); //for display and temp sensor HDC1000writeConfig(0x8000); //reset delay(10); HDC1000writeConfig(0x1000); //config set resolution 14bit 0b0000 0000 00000000 rtc_init(); //RTC initialize RTC_TIMETYPE rtc_t = { 16,1,12,0,0,0 }; rtc_set_time( &rtc_t ); //date and time set SUBCUD.subcud = 0xB8; //calibration pinMode( SD_CD, INPUT ); //SD cardが入っているとLOW、無ければHIGHとなる Serial.print("wait for SD card inserted."); while( digitalRead( SD_CD ) == HIGH ) //SDカードが刺さるまでやっている { Serial.print("."); delay( 100UL ); } Serial.println("SD card detected."); if( !SD.begin( SD_SS ) ) //SSに使用する端子番号を指定している { Serial.println("SD initialization failed!"); while( 1 ) ; } Serial.println("SD initialization cleared."); while( 1 ) { while( 1 ) //wait for 10second period. { rtc_get_time( &rtc_t ); if( !(rtc_t.second % 10) ) break; //interval time = 10s } unsigned short tempUS,humiUS; HDC1000readTemperature( &tempUS, &humiUS ); //温度、湿度データを取得 float tempF = HDC1000temperature2Degree( tempUS ) + 0.05f; //変換値を摂氏に換算 float humiF = HDC1000humidity2Percent( humiUS ) + 0.05f; //変換値をパーセントに換算 char buf[32]; String log = ""; log += rtc_t.year + 2000; log += "/"; log += rtc_t.mon; log += "/"; log += rtc_t.day; log += " "; log += rtc_t.hour; log += ":"; log += rtc_t.min; log += ":"; log += rtc_t.second; log += ","; sprintf( buf, "%2.1f", tempF ); log += buf; log += "c,"; sprintf( buf, "%2.1f", humiF ); log += buf; log += "%"; char fn[] = "temper.csv"; File logFile; logFile = SD.open( fn, FILE_WRITE ); /*ファイル書き込み*/ logFile.println( log ); logFile.close(); Serial.println( log ); delay( 10 * 1000UL ); } } void loop() { } The rest is omitted.
The contents of "Temper.csv" file is as follows.
2016/1/12 0:0:10,26.2c,45.5%
2016/1/12 0:0:20,24.8c,42.9%
2016/1/12 0:0:30,24.4c,40.4%
2016/1/12 0:0:40,24.1c,38.9%
2016/1/12 0:0:50,23.9c,37.9%
2016/1/12 0:1:0,23.9c,37.9%
2016/1/12 0:1:10,23.7c,37.8%
2016/1/12 0:1:20,23.6c,37.4%
2016/1/12 0:1:30,23.6c,37.2%
2016/1/12 0:1:40,23.6c,37.0%
Added mode is active in the case of opening the file for overwriting.
Remove the file in the case of deleting the previous contents and newly writing.
Reading out from SD Card
Reading the contents having written into SD Card earlier. Please refer to the code below.
?/*GR-KURUMI Sketch Template Version: V1.12*/ #include#include //for SD card #define SD_SS A2 //sd card slave select #define SD_CD A3 //sd card detect void setup() { Serial.begin( 9600 ); pinMode( SD_CD, INPUT ); //SD cardが入っているとLOW、無ければHIGHとなる Serial.print("wait for SD card inserted."); while( digitalRead( SD_CD ) == HIGH ) //SDカードが刺さるまでやっている { Serial.print("."); delay( 100UL ); } Serial.println("SD card detected."); if( !SD.begin( SD_SS ) ) //SSに使用する端子番号を指定している { Serial.println("SD initialization failed!"); while( 1 ) ; } Serial.println("SD initialization cleared."); char fn[] = "temper.csv"; File logFile; logFile = SD.open( fn, FILE_READ ); /*ファイル読み込み*/ while( logFile.available() ) { unsigned char c = logFile.read(); Serial.write( (const unsigned char*)&c,1 ); } logFile.close(); } void loop() { }
Writing speed for SD Card
You may have been wondering how fast you can write SD Card.
Measured the time for writing a SD card with 1Mbyte-text. It took 10483ms, approximately 10s.
Hence, the speed is 100K byte per second. ※The efficiency should be good since the writing is executed after the data is buffered at 512byte.
If writing is executed per 1byte, the speed will be slower.
Showing the code used for the experiment.
/*GR-KURUMI Sketch Template Version: V1.12*/ #include#include //for SD card #define SD_SS A2 //sd card slave select #define SD_CD A3 //sd card detect void setup() { Serial.begin( 9600 ); pinMode( SD_CD, INPUT ); //SD cardが入っているとLOW、無ければHIGHとなる Serial.print("wait for SD card inserted."); while( digitalRead( SD_CD ) == HIGH ) //SDカードが刺さるまでやっている { Serial.print("."); delay( 100UL ); } Serial.println("SD card detected."); if( !SD.begin( SD_SS ) ) //SSに使用する端子番号を指定している { Serial.println("SD initialization failed!"); while( 1 ) ; } Serial.println("SD initialization cleared."); char fileBuf[512]; char testString[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\r\n"; //26 + 26 + 10 + 2 #define STRING_SIZE (sizeof(testString) - 1) char *ptr = fileBuf; for( int i = 0; i < sizeof(fileBuf) / STRING_SIZE; i++ ) { memcpy( ptr, testString, STRING_SIZE ); ptr += STRING_SIZE; } char fn[] = "abcd.txt"; if( SD.exists(fn) ) SD.remove(fn); File txtFile; txtFile = SD.open( fn, FILE_WRITE ); /*ファイル書き込み*/ #define LOOP_LIMIT (int)(1024UL * 1024UL / sizeof(fileBuf)) unsigned long previousTime = millis(); for( int i = 0; i < LOOP_LIMIT; i++ ) { txtFile.write( (unsigned char*)fileBuf, sizeof(fileBuf) ); } txtFile.flush(); unsigned long nextTime = millis(); txtFile.close(); Serial.print("SD card write time:"); Serial.println( nextTime - previousTime, DEC ); } void loop() { }
Reading speed for SD Card
Also you may have been wondering how fast you can read SD Card.
Measured the time for reading SD Card with 1Mbyte-text.
As result, it took 3870ms.
The speed is 271Kbyte per second.
※ Get ready 512byte buffer. Reading is executed per block unit.
Showing the code used for experiment.
?/*GR-KURUMI Sketch Template Version: V1.12*/ #include#include //for SD card #define SD_SS A2 //sd card slave select #define SD_CD A3 //sd card detect void setup() { Serial.begin( 9600 ); pinMode( SD_CD, INPUT ); //SD cardが入っているとLOW、無ければHIGHとなる Serial.print("wait for SD card inserted."); while( digitalRead( SD_CD ) == HIGH ) //SDカードが刺さるまでやっている { Serial.print("."); delay( 100UL ); } Serial.println("SD card detected."); if( !SD.begin( SD_SS ) ) //SSに使用する端子番号を指定している { Serial.println("SD initialization failed!"); while( 1 ) ; } Serial.println("SD initialization cleared."); char fn[] = "abcd.txt"; File txtFile; txtFile = SD.open( fn, FILE_READ ); unsigned long fileSize = txtFile.size(); unsigned long sz = fileSize; char buf[512]; unsigned long previousTime = millis(); while( sz > 0 ) { unsigned long readSz = (sz > sizeof(buf)) ? sizeof(buf) : sz; txtFile.read( buf, readSz ); sz -= readSz; } unsigned long nextTime = millis(); txtFile.close(); Serial.print("SD card read time:"); Serial.print( nextTime - previousTime, DEC ); Serial.print( " file size =" ); Serial.println( fileSize, DEC ); } void loop() { }
Reproduction of the music file in SD Card
Found that reading SD Card was going well above, let’s try to play music data stored in SD Card.
Recommended to use MP3 form for the music data, to use dedication decoder IC: VS1063A to play MP3 data.
http://akizukidenshi.com/catalog/g/gI-06585/
The interface for decoder IC is SPI.
SD Card also use SPI, being afraind that a conflict happens between two.
GR-KURUMI is preparing library for using SPI.
SPI condition for decoder IC is under 5MHz on SCK.
Out of the four SPI modes, the one which fix the topology of SCK and data is mode 0.
Again, I'm afraind that the decoder IC has a conflict with SD Card on this change. The SPI has four kinds of mode while these should be collectively controlled. Program check to see the name of all files in SD Card, including in sub-directory, read the data file based on the extension of “.MP3” as mp3 file, send the data in line with decode IC.
Complete to play all mp3 files, it’ll be the end.
Confirm the operation without fail to start playing the music under this program.
Showing the code.
/* ------------------------------------------------------------------------ */ /* SDカード内の音楽ファイルをMP3デコーダーICに転送して再生 */ /* designed by hamayan */ /* Copyright(C) hamayan */ /* since 2004 - 2016 */ /* ------------------------------------------------------------------------ */ #include#include #include //for SD card #include //for vs1063a extern "C" { #include "string.h" } #if !defined( _MULTITASK_H_ ) #define dly_tsk(tim) delay(tim) #define rot_rdq() #endif /*_MULTITASK_H_ */ void searchMp3( File dir, const char *path ); void playMp3( const char *fn ); static void VS1011e_Wait_DREQ( void ); void vs1011eInit( void ); void VS1011e_SCI_Write( unsigned char adr, unsigned short data ); unsigned short VS1011e_SCI_Read( unsigned char adr ); void VS1011e_SDI_Write( const char *data, unsigned long size ); void setVolum( unsigned short vol ); bool isDREQ( void ); #define SD_SS A3 //sd card slave select #define SD_CD A2 //sd card detect /*DREQ:D3(p16),XRESET:D5(p15),XCS:D6(p10),XDCS:D9(p13) */ #define VS_DRQ (P1.BIT.bit6 == 1) #define VS_RST_IS_0 P1.BIT.bit5 = 0 #define VS_RST_IS_1 P1.BIT.bit5 = 1 #define VS_XDCS_IS_0 P1.BIT.bit3 = 0 #define VS_XDCS_IS_1 P1.BIT.bit3 = 1 #define VS_XCS_IS_0 P1.BIT.bit0 = 0 #define VS_XCS_IS_1 P1.BIT.bit0 = 1 #define VS_SCI_OPE_WRITE 0x02 #define VS_SCI_OPE_READ 0x03 enum VS_REGISTERS { VS_MODE, VS_STATUS, VS_BASS, VS_CLOCKF, VS_DECODE_TIME, VS_AUDATA, VS_WRAM, VS_WRAMADDR, VS_HDAT0, VS_HDAT1, VS_AIADDR, VS_VOL, VS_AICTRL0, VS_AICTRL1, VS_AICTRL2, VS_AICTRL3 }; const unsigned short loud_table[] = {0x0000,0x1010,0x2020,0x3030,0x4040,0x5050,0x6060,0x7070,0x8080,0x9090,0xa0a0,0xb0b0,0xc0c0,0xd0d0,0xe0e0,0xf0f0}; extern const unsigned long mp3_dat_size; extern const unsigned char mp3_file[]; void setup() { Serial.begin( 9600 ); SPI.begin(); SPI.setClockDivider(SPI_CLOCK_DIV8); //2mhz //SPI.setClockDivider(SPI_CLOCK_DIV4); //4mhz SPI.setDataMode(SPI_MODE0); Serial.println("initialize vs1011e..."); vs1011eInit(); VS1011e_SDI_Write( (const char *)mp3_file, (unsigned long)mp3_dat_size ); //setVolum( 0x2020 ); pinMode( SD_CD, INPUT ); //SD cardが入っているとLOW、無ければHIGHとなる Serial.println("wait for SD card inserted."); while( digitalRead( SD_CD ) == HIGH ) //SDカードが刺さるまでやっている { Serial.print("."); delay( 100UL ); } Serial.println("SD card detected."); if( !SD.begin( SD_SS ) ) //SSに使用する端子番号を指定している { Serial.println("SD initialization failed!"); while( 1 ) ; } Serial.println("SD initialization cleared."); File root = SD.open( "/" ); //open root directory searchMp3( root, "" ); } void loop() { } void searchMp3( File dir, const char *path ) { while( 1 ) { File fil = dir.openNextFile(); if( fil == false ) return; const char *fn = fil.name(); //Serial.println( fn ); if( fil.isDirectory() == true ) { char cpyPath[256]; strcpy( cpyPath, path ); strcat( cpyPath, "/" ); strcat( cpyPath, fil.name() ); searchMp3( fil, cpyPath ); } if( strcmp(".MP3", strchr( fn, '.' )) == 0 ) { char cpyFn[256]; strcpy( cpyFn, path ); strcat( cpyFn, "/" ); strcat( cpyFn, fn ); playMp3( cpyFn ); } } } void playMp3( const char *fn ) { File mp3File = SD.open( fn, FILE_READ ); if( mp3File == false ) { Serial.print( fn ); Serial.println( ":open error." ); return; } unsigned long fileSize = mp3File.size(); Serial.print("file name:"); Serial.print(fn); Serial.print(" file size="); Serial.println( fileSize, DEC ); char buf[2048]; unsigned long previousTime = millis(); #if 1 while( fileSize > 0 ) { unsigned long readSz = (fileSize > sizeof(buf)) ? sizeof(buf) : fileSize; mp3File.read( buf, readSz ); fileSize -= readSz; VS1011e_SDI_Write( (const char *)buf, readSz ); } #else delay( 1 * 1000UL ); #endif unsigned long nextTime = millis(); mp3File.close(); Serial.print("mp3 play time:"); Serial.println( nextTime - previousTime, DEC ); } /****************************************************************************/ /* vs1011e初期化 */ /****************************************************************************/ void vs1011eInit( void ) { int i; char dummy; unsigned short loud; /*PORTの設定*/ PM1.BIT.bit6 = 1; //dreq input mode PIM1.BIT.bit6 = 1; //ttl input PM1.BIT.bit5 = 0; //xreset output mode POM1.BIT.bit5 = 0; //cmos PM1.BIT.bit3 = 0; //xdcs output mode POM1.BIT.bit3 = 0; //cmos PM1.BIT.bit0 = 0; //xcs output mode POM1.BIT.bit0 = 0; //cmos /*XRESET*/ VS_RST_IS_0; dly_tsk(10); /*XRESETの解除*/ VS_RST_IS_1; /*ソフトウエアリセット*/ VS1011e_SCI_Write( VS_MODE, 0x0804 ); VS1011e_SCI_Write( VS_MODE, 0x0800 ); /*モード設定完了*/ VS1011e_SCI_Write( VS_CLOCKF, 0xa000 + 1072 ); /*クロック設定 x4 0x8000:x3.5*/ VS1011e_SCI_Write( VS_VOL, 0x2020 ); /*音量設定 夜、寝ている時にいい感じ*/ //VS1011e_SCI_Write( VS_VOL, 0x1010 ); /*音量設定*/ loud = VS1011e_SCI_Read( VS_VOL ); dly_tsk(100); /*バッファを0で埋める*/ for( i = 0, dummy = 0; i < 2048; i++ ) VS1011e_SDI_Write( &dummy, 1 ); } /****************************************************************************/ /* VS1011eのDREQがネゲートされるのを待つ */ /****************************************************************************/ static void VS1011e_Wait_DREQ( void ) { while( VS_DRQ == false ) rot_rdq(); } /****************************************************************************/ /* SCIの書き込み */ /****************************************************************************/ void VS1011e_SCI_Write( unsigned char adr, unsigned short data ) { /*DREQのチェック*/ if( VS_DRQ == false ) VS1011e_Wait_DREQ(); /*XCSのアサート*/ VS_XCS_IS_0; /*オペレーションコードの書き込み*/ SPI.transfer(VS_SCI_OPE_WRITE); /*アドレスの書き込み*/ SPI.transfer(adr); /*データの書き込み*/ SPI.transfer(data >> 8); SPI.transfer(data >> 0); /*XCSのネゲート*/ VS_XCS_IS_1; } /****************************************************************************/ /* SCIの読み込み */ /****************************************************************************/ unsigned short VS1011e_SCI_Read( unsigned char adr ) { int i; unsigned char ope; unsigned short data = 0; /*DREQのチェック*/ if( VS_DRQ == false ) VS1011e_Wait_DREQ(); /*XCSのアサート*/ VS_XCS_IS_0; /*オペレーションコードの書き込み*/ SPI.transfer(VS_SCI_OPE_READ); /*アドレスの書き込み*/ SPI.transfer(adr); /*データの読み込み*/ data = SPI.transfer(0xff) << 8; data |= SPI.transfer(0xff) << 0; /*XCSのネゲート*/ VS_XCS_IS_1; return data; } /****************************************************************************/ /* SDIの読み込み */ /****************************************************************************/ void VS1011e_SDI_Write( const char *data, unsigned long size ) { /*XDCSのアサート*/ VS_XDCS_IS_0; for( ;size > 0; size-- ) { /*書き込めるまで待ちを入れる*/ while( size > 32 && VS_DRQ == false ) rot_rdq(); //while( size > 32 && digitalRead(dreq) == LOW ) rot_rdq(); /*データの書き込み*/ SPI.transfer(*data++); } /*XDCSのネゲート*/ VS_XDCS_IS_1; } /****************************************************************************/ /* volume control */ /****************************************************************************/ void setVolum( unsigned short vol ) { VS1011e_SCI_Write( VS_VOL, vol ); /*音量設定*/ } /****************************************************************************/ /* what is state of dreq pin ? */ /****************************************************************************/ bool isDREQ( void ) { return VS_DRQ; }
General hard engineer... occasionally writing for technical magazine.