Gadget Renesas

Linking Ideas and Electronics

GR Atelier

Title:Let's try the function on GR-KURUMI, SD Card (SPI) Vol.

Displayed Name:@chobichan

Let's try the function on GR-KURUMI, SD Card (SPI) Vol.

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;
}

MVP information @chobichan

General hard engineer... occasionally writing for technical magazine.

Follow

share