我想从Arduino Mega 2560手动初始化SD卡并读取其内容。
我已经阅读了很多手册,解释了如何正确执行操作以及Arduino SD库代码,但是我无法使其正常工作。
uint8_t spi_byte(uint8_t byte) {
SPDR = byte;
asm volatile("nop");
while(!(SPSR & B10000000));
uint8_t response = SPDR;
return response;
}
uint8_t sd_cmd(uint8_t cmd, uint32_t args) {
if(cmd != 0x40) while(spi_byte(0xFF) != 0xFF);
spi_byte(cmd);
int8_t c;
for(c = 3; c >= 0; --c) spi_byte(args >> (c << 3));
uint8_t crc;
if(cmd == 0x40) crc = 0x95;
else if(cmd == 0x48) crc = 0x87;
else crc = 0xFF;
spi_byte(crc);
uint8_t response;
for(c = 16; ((response = spi_byte(0xFF)) & 0x80) && c; --c);
/*if((cmd < 0x51) || (cmd > 0x59))*/ spi_byte(0xFF); //S
return response;
}
void sd_init() {
DDRB &= B11110000;
PORTB |= B0001; //set CS pull-up resistor (just-in-case)
DDRB |= B0001; //set CS to output
PORTB |= B1000; //set MISO pull-up resistor (just-in-case)
SPCR = B01010010; //no interrupt, MSB first, master, mode 0, fosc/64 (250 kHz)
SPSR &= ~1; //clear SPI double speed
DDRB |= B0110; //set SCK and MOSI to output
delayMicroseconds(200000);
uint8_t c;
cli();
for(c = 0; c < 10; ++c) spi_byte(0xFF); //synchronize clock
clb(PORTB, 0); //set CS low
uint8_t response;
uint16_t timeout = 1024;
while((response=sd_cmd(0x40, 0)) != 0x1) { //CMD0: reset card
if((!response) || (response == 0xFF)) error(3); //we don't even have a card
if(!--timeout) error(7); //timed out
}
if(sd_cmd(0x48, 0x1AA) != 1) error(1); //CMD8: make sure we are using SD v2
for(c = 0; c < 4; ++c) spi_byte(0xFF);
do {
sd_cmd(0x77, 0); //CMD55: introduce application-specific command
response = sd_cmd(0x69, 0x40000000); //ACMD41: initialize card
if(!--timeout) error(8); //timed out
} while(response != 0);
sd_cmd(0x7A, 0); //CMD58: read OCR
response = spi_byte(0xFF);
if((response & B11000000) != B11000000) error(2); //make sure we are using SDHC
for(c = 0; c < 3; ++c) spi_byte(0xFF);
stb(PORTB, 0); //set CS high
SPCR = B01010000; //fosc/4 (4 MHz)
SPSR |= 1; //set SPI double speed (8 MHz)
for(c = 0; c < 10; ++c) spi_byte(0xFF); //synchronize clock
sei();
return;
}
void sd_read(uint8_t* buffer, uint32_t block, uint8_t start2, uint8_t size2) {
/*start2 and size2 are in 2 byte units, size2 = 0 means whole block (512 B)*/
cli();
block <<= 9; //S//D
clb(PORTB, 0); //set CS low
uint8_t response;
if((response=sd_cmd(0x51, block))) { //CMD17: read single block
Serial.begin(9600); //D
Serial.println(response, HEX); //D
error(10);
}
while(spi_byte(0xFF) != 0xFE) ; //TODO: timeout error 9
uint8_t b = 0; uint8_t end = 0;
do {
if((b >= start2) && (!end)) {
*(buffer++) = spi_byte(0xFF);
*(buffer++) = spi_byte(0xFF);
--size2;
if(!size2) end = 1;
}
else {
spi_byte(0xFF);
spi_byte(0xFF);
}
++b;
} while(b); //repeat 256 times
spi_byte(0xFF); spi_byte(0xFF); //two more bytes to close
stb(PORTB, 0); //set CS high
spi_byte(0xFF);
sei();
return;
}
有时候它可以完美地工作,有时它只是在初始化时锁定,最后现在我正在尝试读取SD卡内容,并且它永远显示0x55AA。我怀疑这是硬件问题,但我想排除我的代码可能出错的可能性。另外,我不知道为什么我必须将读取地址乘以512。作为SDHC卡,我希望地址以块为单位,对吗?