采样 50M 1M;采样时间足够长,采样频率1M 避免信息遗漏
引脚 cs pa2 mosi pa3 sck pa5 miso pa6 vcc ->5v gnd ->gnd
ARDUINO SD库与移植(原本是打算移值tw ch32v103的sd库的,但没有对比,只能选择arduino ;
对 #define USE_SPI_LIB ;USE_SPI_LIB进行注释 ,不使用原代码 ,再进行修改(原为使用硬件 与软件 spi代码
对 sd2card.h cpp 进行修改 修改send recv 函数,替换
注释 #include "arduino.h"
及其它一些细节
注释 //#error Architecture or board not supported.
1.问题 io口导致的 ;逻辑分析仪查看输出 对比arduino 输出
模拟spi输出 波形(逻辑分析仪查看) 产生额外的干扰波纹,导致无法初始化成功;
混乱的输出与digitalWrite(xx,1);
输出引脚
pinMode(2,output); //cs
setPinFun(2,0);
digitalWrite(2,1);
pinMode(3,output); //mosi
setPinFun(3,0);
digitalWrite(3,1);
pinMode(5,output); //sck
setPinFun(5,0);
digitalWrite(5,1);
pinMode(6,input); //miso
dpmu_set_io_pull(pinToFun[6],DPMU_IO_PULL_UP);
移值arduino SD2时 修改 sd2card.cpp sd2card.h ;(可以使用官方的 asr_softspi库 进行修改 ,模拟为1 ,1 ;sck 之后添加 延时 delay100us;
对主要函数 spiRec spiSend 进行修改 (速度与调整delay) 或用sleep1;(*delay5us 可以 sleep1(100)不行
void sleep1(uint8_t t)
{
while(t>0)
t--;
}
//------------------------------------------------------------------------------
/** Soft SPI receive */
uint8_t spiRec(void) {
uint8_t data = 0;
// no interrupts during byte receive - about 8 us
// cli();
//eclic_global_interrupt_disable();
//eclic_global_interrupt_disable();
// output pin high - like sending 0XFF
digitalWrite(SPI_MOSI_PIN, HIGH);
//sleep1(speed);
for (uint8_t i = 0; i < 8; i++) {
digitalWrite(SPI_SCK_PIN, HIGH);
// adjust so SCK is nice
nop;
nop;
//sleep1(speed);
data <<= 1;
if (digitalRead(SPI_MISO_PIN)) {
data |= 1;
}
digitalWrite(SPI_SCK_PIN, LOW);
delay100us();
}
// enable interrupts
//sei();
// eclic_global_interrupt_enable();
return data;
}
//------------------------------------------------------------------------------
/** Soft SPI send */
void spiSend(uint8_t data) {
// no interrupts during byte send - about 8 us
// cli();
for (uint8_t i = 0; i < 8; i++) {
digitalWrite(SPI_SCK_PIN, LOW);
//sleep1(speed);
delay100us();
digitalWrite(SPI_MOSI_PIN, data & 0X80);
delay100us();
data <<= 1;
digitalWrite(SPI_SCK_PIN, HIGH);
//sleep1(speed);
delay100us();
}
// hold SCK high for a few ns
nop;
nop;
nop;
nop;
digitalWrite(SPI_SCK_PIN, LOW);
delay100us();
delay100us();
// enable interrupts
//sei();
//eclic_global_interrupt_enable();
}
------------------------------------------------------------------------------------------------------------------------------
复制arduino sd库目录下的
到 asrpro myLib 下
1.修改 office 下地的 source_file.prj 添加如下语句
source-file: ../myLib/Sd2Card.cpp (原名SdCard
source-file: ../myLib/SdFile.cpp
source-file: ../myLib/SdVolume.cpp
2 asr.cpp 测试代码 如下
3.修改 sdCard.cpp
#include "asr.h"
extern "C"{ void * __dso_handle = 0 ;}
#include "setup.h"
//#include "SD2Card.h"
#include "SD2.h"
uint32_t snid;
void ASR_CODE();
Sd2Card card;
SdVolume volume;
SdFile root;
//{speak:小蝶-清新女声,vol:10,speed:10,platform:haohaodada}
//{playid:10001,voice:欢迎使用语音助手,用天问五幺唤醒我。}
//{playid:10002,voice:我退下了,用天问五幺唤醒我}
/*描述该功能...
*/
void ASR_CODE(){
//本函数是语音识别成功钩子程序
//运行时间越短越好,复杂控制启动新线程运行
//唤醒时间设置必须在ASR_CODE中才有效
set_state_enter_wakeup(10000);
//用switch分支选择,根据不同的识别成功的ID执行相应动作,点击switch左上齿轮
//可以增加分支项
switch (snid) {
case 1:
digitalWrite(4,0);
break;
case 2:
digitalWrite(4,1);
break;
}
//除了switch分支选择,也可用如果判断识别ID的值来执行动作
if((snid) == 3){
digitalWrite(4,0);
}
if((snid) == 4){
digitalWrite(4,1);
}
//采用如果判断模块,可更方便复制
}
int chipSelect = 2;
void hardware_init(){
//需要操作系统启动后初始化的内容
//音量范围1-7
vol_set(1);
Serial.begin(9600);
delay(200);
Serial.print("\nInitializing SD card...");
// we'll use the initialization code from the utility libraries
// since we're just testing if the card is working!
if (!card.init(SPI_HALF_SPEED, chipSelect)) {
Serial.println("initialization failed. Things to check:");
Serial.println("* is a card inserted?");
Serial.println("* is your wiring correct?");
Serial.println("* did you change the chipSelect pin to match your shield or module?");
while (1);
} else {
Serial.println("Wiring is correct and a card is present.");
}
// print the type of card
Serial.println();
Serial.print("Card type: ");
switch (card.type()) {
case SD_CARD_TYPE_SD1:
Serial.println("SD1");
break;
case SD_CARD_TYPE_SD2:
Serial.println("SD2");
break;
case SD_CARD_TYPE_SDHC:
Serial.println("SDHC");
break;
default:
Serial.println("Unknown");
}
// Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32
if (!volume.init(card)) {
Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card");
while (1);
}
Serial.print("Clusters: ");
Serial.println(volume.clusterCount());
Serial.print("Blocks x Cluster: ");
Serial.println(volume.blocksPerCluster());
Serial.print("Total Blocks: ");
Serial.println(volume.blocksPerCluster() * volume.clusterCount());
Serial.println();
// print the type and size of the first FAT-type volume
uint32_t volumesize;
Serial.print("Volume type is: FAT");
Serial.println(volume.fatType(), DEC);
volumesize = volume.blocksPerCluster(); // clusters are collections of blocks
volumesize *= volume.clusterCount(); // we'll have a lot of clusters
volumesize /= 2; // SD card blocks are always 512 bytes (2 blocks are 1KB)
Serial.print("Volume size (Kb): ");
Serial.println(volumesize);
Serial.print("Volume size (Mb): ");
volumesize /= 1024;
Serial.println(volumesize);
Serial.print("Volume size (Gb): ");
Serial.println((float)volumesize / 1024.0);
Serial.println("\nFiles found on the card (name, date and size in bytes): ");
root.openRoot(volume);
// list all files in the card with date and size
root.ls(LS_R | LS_DATE | LS_SIZE);
vTaskDelete(NULL);
}
void setup()
{
//需要操作系统启动前初始化的内容
//播报音下拉菜单可以选择,合成音量是指TTS生成文件的音量
//欢迎词指开机提示音,可以为空
//退出语音是指休眠时提示音,可以为空
//休眠后用唤醒词唤醒后才能执行命令,唤醒词最多5个。回复语可以空。ID范围为0-9999
//{ID:0,keyword:"唤醒词",ASR:"天问五幺",ASRTO:"我在"}
//{ID:1,keyword:"命令词",ASR:"打开灯光",ASRTO:"好的,马上打开灯光"}
//{ID:2,keyword:"命令词",ASR:"关闭灯光",ASRTO:"好的,马上关闭灯光"}
//{ID:3,keyword:"命令词",ASR:"灯光打开",ASRTO:"好的,马上打开灯光"}
//{ID:4,keyword:"命令词",ASR:"灯光关闭",ASRTO:"好的,马上关闭灯光"}
pinMode(2,output); //cs
setPinFun(2,0);
digitalWrite(2,1);
pinMode(3,output); //mosi
setPinFun(3,0);
digitalWrite(3,1);
pinMode(5,output); //sck
setPinFun(5,0);
digitalWrite(5,1);
pinMode(6,input); //miso
dpmu_set_io_pull(pinToFun[6],DPMU_IO_PULL_UP);
}
//Sd2Card.cpp
#include "Sd2Card.h"
//#define chipSelectPin_ 4 // 4 5 6 7
#ifndef __SD2Card
#define __SD2Card
// #define SPI_MOSI_PIN 3
// #define SPI_SCK_PIN 5
// #define SPI_MISO_PIN 6
//------------------------------------------------------------------------------
// functions for hardware SPI
/** Send a byte to the card */
// static void spiSend(uint8_t b) {
// #ifndef USE_SPI_LIB
// SPDR = b;
// while (!(SPSR & (1 << SPIF)))
// ;
// #else
// SDCARD_SPI.transfer(b);
// #endif
// }
// /** Receive a byte from the card */
// static uint8_t spiRec(void) {
// #ifndef USE_SPI_LIB
// spiSend(0XFF);
// return SPDR;
// #else
// return SDCARD_SPI.transfer(0xFF);
// #endif
// }
// #else
//
void usleep(uint8_t t)
{
while(t>0)
t--;
}
//----------------------SOFTWARE_SPI--------------------------------------------------------
/** nop to tune soft SPI timing */
#define nop asm volatile ("nop\n\t")
//------------------------------------------------------------------------------
/** Soft SPI receive */
void sleep1(uint8_t t)
{
while(t>0)
t--;
}
//------------------------------------------------------------------------------
/** Soft SPI receive */
uint8_t spiRec(void) {
uint8_t data = 0;
// no interrupts during byte receive - about 8 us
// cli();
//eclic_global_interrupt_disable();
//eclic_global_interrupt_disable();
// output pin high - like sending 0XFF
digitalWrite(SPI_MOSI_PIN, HIGH);
//sleep1(speed);
for (uint8_t i = 0; i < 8; i++) {
digitalWrite(SPI_SCK_PIN, HIGH);
// adjust so SCK is nice
nop;
nop;
//sleep1(speed);
data <<= 1;
if (digitalRead(SPI_MISO_PIN)) {
data |= 1;
}
digitalWrite(SPI_SCK_PIN, LOW);
delay100us();
}
// enable interrupts
//sei();
// eclic_global_interrupt_enable();
return data;
}
//------------------------------------------------------------------------------
/** Soft SPI send */
void spiSend(uint8_t data) {
// no interrupts during byte send - about 8 us
// cli();
for (uint8_t i = 0; i < 8; i++) {
digitalWrite(SPI_SCK_PIN, LOW);
//sleep1(speed);
delay100us();
digitalWrite(SPI_MOSI_PIN, data & 0X80);
delay100us();
data <<= 1;
digitalWrite(SPI_SCK_PIN, HIGH);
//sleep1(speed);
delay100us();
}
// hold SCK high for a few ns
nop;
nop;
nop;
nop;
digitalWrite(SPI_SCK_PIN, LOW);
delay100us();
delay100us();
// enable interrupts
//sei();
//eclic_global_interrupt_enable();
}
//------------------------------------------------------------------------------
// send command and return error code. Return zero for OK
uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) {
// end read if in partialBlockRead mode
readEnd();
// select card
chipSelectLow();
// wait up to 300 ms if busy
waitNotBusy(300);
// send command
spiSend(cmd | 0x40);
// send argument
for (int8_t s = 24; s >= 0; s -= 8) {
spiSend(arg >> s);
}
// send CRC
uint8_t crc = 0XFF;
if (cmd == CMD0) {
crc = 0X95; // correct crc for CMD0 with arg 0
}
if (cmd == CMD8) {
crc = 0X87; // correct crc for CMD8 with arg 0X1AA
}
spiSend(crc);
// wait for response
for (uint8_t i = 0; ((status_ = spiRec()) & 0X80) && i != 0XFF; i++)
;
return status_;
}
//------------------------------------------------------------------------------
/**
Determine the size of an SD flash memory card.
\return The number of 512 byte data blocks in the card
or zero if an error occurs.
*/
uint32_t Sd2Card::cardSize(void) {
csd_t csd;
if (!readCSD(&csd)) {
return 0;
}
if (csd.v1.csd_ver == 0) {
uint8_t read_bl_len = csd.v1.read_bl_len;
uint16_t c_size = (csd.v1.c_size_high << 10)
| (csd.v1.c_size_mid << 2) | csd.v1.c_size_low;
uint8_t c_size_mult = (csd.v1.c_size_mult_high << 1)
| csd.v1.c_size_mult_low;
return (uint32_t)(c_size + 1) << (c_size_mult + read_bl_len - 7);
} else if (csd.v2.csd_ver == 1) {
uint32_t c_size = ((uint32_t)csd.v2.c_size_high << 16)
| (csd.v2.c_size_mid << 8) | csd.v2.c_size_low;
return (c_size + 1) << 10;
} else {
error(SD_CARD_ERROR_BAD_CSD);
return 0;
}
}
//------------------------------------------------------------------------------
static uint8_t chip_select_asserted = 0;
void Sd2Card::chipSelectHigh(void) {
digitalWrite(chipSelectPin_, HIGH);
// #ifdef USE_SPI_LIB
// if (chip_select_asserted) {
// chip_select_asserted = 0;
// SDCARD_SPI.endTransaction();
// }
// #endif
}
//------------------------------------------------------------------------------
void Sd2Card::chipSelectLow(void) {
// #ifdef USE_SPI_LIB
// if (!chip_select_asserted) {
// chip_select_asserted = 1;
// SDCARD_SPI.beginTransaction(settings);
// }
// #endif
digitalWrite(chipSelectPin_, LOW);
}
//------------------------------------------------------------------------------
/** Erase a range of blocks.
\param[in] firstBlock The address of the first block in the range.
\param[in] lastBlock The address of the last block in the range.
\note This function requests the SD card to do a flash erase for a
range of blocks. The data on the card after an erase operation is
either 0 or 1, depends on the card vendor. The card must support
single block erase.
\return The value one, true, is returned for success and
the value zero, false, is returned for failure.
*/
uint8_t Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) {
if (!eraseSingleBlockEnable()) {
error(SD_CARD_ERROR_ERASE_SINGLE_BLOCK);
goto fail;
}
if (type_ != SD_CARD_TYPE_SDHC) {
firstBlock <<= 9;
lastBlock <<= 9;
}
if (cardCommand(CMD32, firstBlock)
|| cardCommand(CMD33, lastBlock)
|| cardCommand(CMD38, 0)) {
error(SD_CARD_ERROR_ERASE);
goto fail;
}
if (!waitNotBusy(SD_ERASE_TIMEOUT)) {
error(SD_CARD_ERROR_ERASE_TIMEOUT);
goto fail;
}
chipSelectHigh();
return true;
fail:
chipSelectHigh();
return false;
}
//------------------------------------------------------------------------------
/** Determine if card supports single block erase.
\return The value one, true, is returned if single block erase is supported.
The value zero, false, is returned if single block erase is not supported.
*/
uint8_t Sd2Card::eraseSingleBlockEnable(void) {
csd_t csd;
return readCSD(&csd) ? csd.v1.erase_blk_en : 0;
}
//------------------------------------------------------------------------------
/**
Initialize an SD flash memory card.
\param[in] sckRateID SPI clock rate selector. See setSckRate().
\param[in] chipSelectPin SD chip select pin number.
\return The value one, true, is returned for success and
the value zero, false, is returned for failure. The reason for failure
can be determined by calling errorCode() and errorData().
*/
uint8_t Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) {
errorCode_ = inBlock_ = partialBlockRead_ = type_ = 0;
chipSelectPin_ = chipSelectPin;
// 16-bit init start time allows over a minute
uint32_t arg;
// set pin modes
// pinMode(chipSelectPin_, OUTPUT);
// pinMode(SPI_MISO_PIN, INPUT);
// pinMode(SPI_MOSI_PIN, OUTPUT);
// pinMode(SPI_SCK_PIN, OUTPUT);
digitalWrite(chipSelectPin_, HIGH);
// #ifndef USE_SPI_LIB
//*********
for (uint8_t i = 0; i < 10; i++) {
spiSend(0XFF);
}
unsigned int t0 = millis();
chipSelectLow();
// command to go idle in SPI mode
while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) {
unsigned int d = millis() - t0;
if (d > SD_INIT_TIMEOUT) {
error(SD_CARD_ERROR_CMD0);
goto fail;
}
}
// check SD version
if ((cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND)) {
type(SD_CARD_TYPE_SD1);
} else {
// only need last byte of r7 response
for (uint8_t i = 0; i < 4; i++) {
status_ = spiRec();
}
if (status_ != 0XAA) {
error(SD_CARD_ERROR_CMD8);
goto fail;
}
type(SD_CARD_TYPE_SD2);
}
// initialize card and send host supports SDHC if SD2
arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0;
while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) {
// check for timeout
unsigned int d = millis() - t0;
if (d > SD_INIT_TIMEOUT) {
error(SD_CARD_ERROR_ACMD41);
goto fail;
}
}
// if SD2 read OCR register to check for SDHC card
if (type() == SD_CARD_TYPE_SD2) {
if (cardCommand(CMD58, 0)) {
error(SD_CARD_ERROR_CMD58);
goto fail;
}
if ((spiRec() & 0XC0) == 0XC0) {
type(SD_CARD_TYPE_SDHC);
}
// discard rest of ocr - contains allowed voltage range
for (uint8_t i = 0; i < 3; i++) {
spiRec();
}
}
chipSelectHigh();
// #ifndef SOFTWARE_SPI
//return setSckRate(sckRateID);
// #else // SOFTWARE_SPI
return true;
// #endif // SOFTWARE_SPI
fail:
chipSelectHigh();
return false;
}
// errorCode_ = inBlock_ = partialBlockRead_ = type_ = 0;
// chipSelectPin_ = chipSelectPin;
// // 16-bit init start time allows over a minute
// unsigned int t0 = millis();
// uint32_t arg;
// // set pin modes
// pinMode(chipSelectPin_, OUTPUT);
// digitalWrite(chipSelectPin_, HIGH);
// // #ifndef USE_SPI_LIB
// pinMode(SPI_MISO_PIN, INPUT);
// pinMode(SPI_MOSI_PIN, OUTPUT);
// pinMode(SPI_SCK_PIN, OUTPUT);
// // #endif
// // #ifndef SOFTWARE_SPI
// // #ifndef USE_SPI_LIB
// // // SS must be in output mode even it is not chip select
// // pinMode(SS_PIN, OUTPUT);
// // digitalWrite(SS_PIN, HIGH); // disable any SPI device using hardware SS pin
// // // Enable SPI, Master, clock rate f_osc/128
// // SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0);
// // // clear double speed
// // SPSR &= ~(1 << SPI2X);
// // #else // USE_SPI_LIB
// // SDCARD_SPI.begin();
// // settings = SPISettings(250000, MSBFIRST, SPI_MODE0);
// // #endif // USE_SPI_LIB
// // #endif // SOFTWARE_SPI
// // // must supply min of 74 clock cycles with CS high.
// // #ifdef USE_SPI_LIB
// // SDCARD_SPI.beginTransaction(settings);
// // #endif
// for (uint8_t i = 0; i < 10; i++) {
// spiSend(0XFF);
// }
// // #ifdef USE_SPI_LIB
// // SDCARD_SPI.endTransaction();
// // #endif
// chipSelectLow();
// // command to go idle in SPI mode
// while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) {
// unsigned int d = millis() - t0;
// if (d > SD_INIT_TIMEOUT) {
// error(SD_CARD_ERROR_CMD0);
// goto fail;
// }
// }
// // check SD version
// if ((cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND)) {
// type(SD_CARD_TYPE_SD1);
// } else {
// // only need last byte of r7 response
// for (uint8_t i = 0; i < 4; i++) {
// status_ = spiRec();
// }
// if (status_ != 0XAA) {
// error(SD_CARD_ERROR_CMD8);
// goto fail;
// }
// type(SD_CARD_TYPE_SD2);
// }
// // initialize card and send host supports SDHC if SD2
// arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0;
// while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) {
// // check for timeout
// unsigned int d = millis() - t0;
// if (d > SD_INIT_TIMEOUT) {
// error(SD_CARD_ERROR_ACMD41);
// goto fail;
// }
// }
// // if SD2 read OCR register to check for SDHC card
// if (type() == SD_CARD_TYPE_SD2) {
// if (cardCommand(CMD58, 0)) {
// error(SD_CARD_ERROR_CMD58);
// goto fail;
// }
// if ((spiRec() & 0XC0) == 0XC0) {
// type(SD_CARD_TYPE_SDHC);
// }
// // discard rest of ocr - contains allowed voltage range
// for (uint8_t i = 0; i < 3; i++) {
// spiRec();
// }
// }
// chipSelectHigh();
// #ifndef SOFTWARE_SPI
// return setSckRate(sckRateID);
// #else // SOFTWARE_SPI
// return true;
// #endif // SOFTWARE_SPI
// fail:
// chipSelectHigh();
// return false;
// }
//------------------------------------------------------------------------------
/**
Enable or disable partial block reads.
Enabling partial block reads improves performance by allowing a block
to be read over the SPI bus as several sub-blocks. Errors may occur
if the time between reads is too long since the SD card may timeout.
The SPI SS line will be held low until the entire block is read or
readEnd() is called.
Use this for applications like the Adafruit Wave Shield.
\param[in] value The value TRUE (non-zero) or FALSE (zero).)
*/
void Sd2Card::partialBlockRead(uint8_t value) {
readEnd();
partialBlockRead_ = value;
}
//------------------------------------------------------------------------------
/**
Read a 512 byte block from an SD card device.
\param[in] block Logical block to be read.
\param[out] dst Pointer to the location that will receive the data.
\return The value one, true, is returned for success and
the value zero, false, is returned for failure.
*/
uint8_t Sd2Card::readBlock(uint32_t block, uint8_t* dst) {
return readData(block, 0, 512, dst);
}
//------------------------------------------------------------------------------
/**
Read part of a 512 byte block from an SD card.
\param[in] block Logical block to be read.
\param[in] offset Number of bytes to skip at start of block
\param[out] dst Pointer to the location that will receive the data.
\param[in] count Number of bytes to read
\return The value one, true, is returned for success and
the value zero, false, is returned for failure.
*/
uint8_t Sd2Card::readData(uint32_t block,
uint16_t offset, uint16_t count, uint8_t* dst) {
if (count == 0) {
return true;
}
if ((count + offset) > 512) {
goto fail;
}
if (!inBlock_ || block != block_ || offset < offset_) {
block_ = block;
// use address if not SDHC card
if (type() != SD_CARD_TYPE_SDHC) {
block <<= 9;
}
if (cardCommand(CMD17, block)) {
error(SD_CARD_ERROR_CMD17);
goto fail;
}
if (!waitStartBlock()) {
goto fail;
}
offset_ = 0;
inBlock_ = 1;
}
#ifdef OPTIMIZE_HARDWARE_SPI
// start first spi transfer
SPDR = 0XFF;
// skip data before offset
for (; offset_ < offset; offset_++) {
while (!(SPSR & (1 << SPIF)))
;
SPDR = 0XFF;
}
// transfer data
n = count - 1;
for (uint16_t i = 0; i < n; i++) {
while (!(SPSR & (1 << SPIF)))
;
dst[i] = SPDR;
SPDR = 0XFF;
}
// wait for last byte
while (!(SPSR & (1 << SPIF)))
;
dst[n] = SPDR;
#else // OPTIMIZE_HARDWARE_SPI
// skip data before offset
for (; offset_ < offset; offset_++) {
spiRec();
}
// transfer data
for (uint16_t i = 0; i < count; i++) {
dst[i] = spiRec();
}
#endif // OPTIMIZE_HARDWARE_SPI
offset_ += count;
if (!partialBlockRead_ || offset_ >= 512) {
// read rest of data, checksum and set chip select high
readEnd();
}
return true;
fail:
chipSelectHigh();
return false;
}
//------------------------------------------------------------------------------
/** Skip remaining data in a block when in partial block read mode. */
void Sd2Card::readEnd(void) {
if (inBlock_) {
// skip data and crc
#ifdef OPTIMIZE_HARDWARE_SPI
// optimize skip for hardware
SPDR = 0XFF;
while (offset_++ < 513) {
while (!(SPSR & (1 << SPIF)))
;
SPDR = 0XFF;
}
// wait for last crc byte
while (!(SPSR & (1 << SPIF)))
;
#else // OPTIMIZE_HARDWARE_SPI
while (offset_++ < 514) {
spiRec();
}
#endif // OPTIMIZE_HARDWARE_SPI
chipSelectHigh();
inBlock_ = 0;
}
}
//------------------------------------------------------------------------------
/** read CID or CSR register */
uint8_t Sd2Card::readRegister(uint8_t cmd, void* buf) {
uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
if (cardCommand(cmd, 0)) {
error(SD_CARD_ERROR_READ_REG);
goto fail;
}
if (!waitStartBlock()) {
goto fail;
}
// transfer data
for (uint16_t i = 0; i < 16; i++) {
dst[i] = spiRec();
}
spiRec(); // get first crc byte
spiRec(); // get second crc byte
chipSelectHigh();
return true;
fail:
chipSelectHigh();
return false;
}
//------------------------------------------------------------------------------
/**
Set the SPI clock rate.
\param[in] sckRateID A value in the range [0, 6].
The SPI clock will be set to F_CPU/pow(2, 1 + sckRateID). The maximum
SPI rate is F_CPU/2 for \a sckRateID = 0 and the minimum rate is F_CPU/128
for \a scsRateID = 6.
\return The value one, true, is returned for success and the value zero,
false, is returned for an invalid value of \a sckRateID.
*/
uint8_t Sd2Card::setSckRate(uint8_t sckRateID) {
if (sckRateID > 6) {
error(SD_CARD_ERROR_SCK_RATE);
return false;
}
// #ifndef USE_SPI_LIB
// // see avr processor datasheet for SPI register bit definitions
// if ((sckRateID & 1) || sckRateID == 6) {
// SPSR &= ~(1 << SPI2X);
// } else {
// SPSR |= (1 << SPI2X);
// }
// SPCR &= ~((1 << SPR1) | (1 << SPR0));
// SPCR |= (sckRateID & 4 ? (1 << SPR1) : 0)
// | (sckRateID & 2 ? (1 << SPR0) : 0);
// #else // USE_SPI_LIB
// switch (sckRateID) {
// case 0: settings = SPISettings(25000000, MSBFIRST, SPI_MODE0); break;
// case 1: settings = SPISettings(4000000, MSBFIRST, SPI_MODE0); break;
// case 2: settings = SPISettings(2000000, MSBFIRST, SPI_MODE0); break;
// case 3: settings = SPISettings(1000000, MSBFIRST, SPI_MODE0); break;
// case 4: settings = SPISettings(500000, MSBFIRST, SPI_MODE0); break;
// case 5: settings = SPISettings(250000, MSBFIRST, SPI_MODE0); break;
// default: settings = SPISettings(125000, MSBFIRST, SPI_MODE0);
// }
// #endif // USE_SPI_LIB
return true;
}
#ifdef USE_SPI_LIB
//------------------------------------------------------------------------------
// set the SPI clock frequency
uint8_t Sd2Card::setSpiClock(uint32_t clock) {
// settings = SPISettings(clock, MSBFIRST, SPI_MODE0);
return true;
}
#endif
//------------------------------------------------------------------------------
// wait for card to go not busy
uint8_t Sd2Card::waitNotBusy(unsigned int timeoutMillis) {
unsigned int t0 = millis();
unsigned int d;
do {
if (spiRec() == 0XFF) {
return true;
}
d = millis() - t0;
} while (d < timeoutMillis);
return false;
}
//------------------------------------------------------------------------------
/** Wait for start block token */
uint8_t Sd2Card::waitStartBlock(void) {
unsigned int t0 = millis();
while ((status_ = spiRec()) == 0XFF) {
unsigned int d = millis() - t0;
if (d > SD_READ_TIMEOUT) {
error(SD_CARD_ERROR_READ_TIMEOUT);
goto fail;
}
}
if (status_ != DATA_START_BLOCK) {
error(SD_CARD_ERROR_READ);
goto fail;
}
return true;
fail:
chipSelectHigh();
return false;
}
//------------------------------------------------------------------------------
/**
Writes a 512 byte block to an SD card.
\param[in] blockNumber Logical block to be written.
\param[in] src Pointer to the location of the data to be written.
\param[in] blocking If the write should be blocking.
\return The value one, true, is returned for success and
the value zero, false, is returned for failure.
*/
uint8_t Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src, uint8_t blocking) {
#if SD_PROTECT_BLOCK_ZERO
// don't allow write to first block
if (blockNumber == 0) {
error(SD_CARD_ERROR_WRITE_BLOCK_ZERO);
goto fail;
}
#endif // SD_PROTECT_BLOCK_ZERO
// use address if not SDHC card
if (type() != SD_CARD_TYPE_SDHC) {
blockNumber <<= 9;
}
if (cardCommand(CMD24, blockNumber)) {
error(SD_CARD_ERROR_CMD24);
goto fail;
}
if (!writeData(DATA_START_BLOCK, src)) {
goto fail;
}
if (blocking) {
// wait for flash programming to complete
if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
error(SD_CARD_ERROR_WRITE_TIMEOUT);
goto fail;
}
// response is r2 so get and check two bytes for nonzero
if (cardCommand(CMD13, 0) || spiRec()) {
error(SD_CARD_ERROR_WRITE_PROGRAMMING);
goto fail;
}
}
chipSelectHigh();
return true;
fail:
chipSelectHigh();
return false;
}
//------------------------------------------------------------------------------
/** Write one data block in a multiple block write sequence */
uint8_t Sd2Card::writeData(const uint8_t* src) {
// wait for previous write to finish
if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
error(SD_CARD_ERROR_WRITE_MULTIPLE);
chipSelectHigh();
return false;
}
return writeData(WRITE_MULTIPLE_TOKEN, src);
}
//------------------------------------------------------------------------------
// send one block of data for write block or write multiple blocks
uint8_t Sd2Card::writeData(uint8_t token, const uint8_t* src) {
#ifdef OPTIMIZE_HARDWARE_SPI
// send data - optimized loop
SPDR = token;
// send two byte per iteration
for (uint16_t i = 0; i < 512; i += 2) {
while (!(SPSR & (1 << SPIF)))
;
SPDR = src[i];
while (!(SPSR & (1 << SPIF)))
;
SPDR = src[i + 1];
}
// wait for last data byte
while (!(SPSR & (1 << SPIF)))
;
#else // OPTIMIZE_HARDWARE_SPI
spiSend(token);
for (uint16_t i = 0; i < 512; i++) {
spiSend(src[i]);
}
#endif // OPTIMIZE_HARDWARE_SPI
spiSend(0xff); // dummy crc
spiSend(0xff); // dummy crc
status_ = spiRec();
if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) {
error(SD_CARD_ERROR_WRITE);
chipSelectHigh();
return false;
}
return true;
}
//------------------------------------------------------------------------------
/** Start a write multiple blocks sequence.
\param[in] blockNumber Address of first block in sequence.
\param[in] eraseCount The number of blocks to be pre-erased.
\note This function is used with writeData() and writeStop()
for optimized multiple block writes.
\return The value one, true, is returned for success and
the value zero, false, is returned for failure.
*/
uint8_t Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) {
#if SD_PROTECT_BLOCK_ZERO
// don't allow write to first block
if (blockNumber == 0) {
error(SD_CARD_ERROR_WRITE_BLOCK_ZERO);
goto fail;
}
#endif // SD_PROTECT_BLOCK_ZERO
// send pre-erase count
if (cardAcmd(ACMD23, eraseCount)) {
error(SD_CARD_ERROR_ACMD23);
goto fail;
}
// use address if not SDHC card
if (type() != SD_CARD_TYPE_SDHC) {
blockNumber <<= 9;
}
if (cardCommand(CMD25, blockNumber)) {
error(SD_CARD_ERROR_CMD25);
goto fail;
}
return true;
fail:
chipSelectHigh();
return false;
}
//------------------------------------------------------------------------------
/** End a write multiple blocks sequence.
\return The value one, true, is returned for success and
the value zero, false, is returned for failure.
*/
uint8_t Sd2Card::writeStop(void) {
if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
goto fail;
}
spiSend(STOP_TRAN_TOKEN);
if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
goto fail;
}
chipSelectHigh();
return true;
fail:
error(SD_CARD_ERROR_STOP_TRAN);
chipSelectHigh();
return false;
}
//------------------------------------------------------------------------------
/** Check if the SD card is busy
\return The value one, true, is returned when is busy and
the value zero, false, is returned for when is NOT busy.
*/
uint8_t Sd2Card::isBusy(void) {
chipSelectLow();
char b = spiRec(); //****
chipSelectHigh();
return (b != 0XFF);
}
#endif
加快编译速度的方法
删除asr_pro_sdk\projects\offline_asr_sample\project_file\build\objs 下对应的 中间文件;
使用./build 一下