I'm trying to raw write blocks to an SDHC card in SPI mode. I'm not actually using an Arduino but a breadboard Atmega328p @ 8 MHz with a 3.3V supply (that way I don't need to level convert for the SD)
I wrote the SD code based on scattered specs and code examples on the internet. None of which are very complete. I am able to initialize the card and can read blocks to my hearts content. But when I try to write a sector from data stored in EEPROM, I get the expected 0x05 response but the data isn't actually written. I read back the sector and it is unchanged.
Relevant sections of code:
#define SET_CS() PORTB |= _BV(DDB2)
#define CLEAR_CS() PORTB &= ~_BV(DDB2)
uint8_t SD_response(uint8_t resp){
scheduler_stop();
uint16_t count = 0xFFF;
uint8_t result;
while(count) {
result = spi_rx_byte();
if (result == resp)break;
count--;
}
// scheduler_start();
if(!count){return 1;}
return 0;
}
#define SD_READ 0x11
#define SD_WRITE 0x18
uint8_t SD_block_command(uint8_t cmd, uint32_t block){
uint8_t cnt = 0;
again:
cnt++;
CLEAR_CS();
//0x51
SD_cmd[0] = 0x40 | cmd;
SD_cmd[1] = (block & 0xFF000000) >> 24;
SD_cmd[2] = (block & 0x00FF0000) >> 16;
SD_cmd[3] = (block & 0x0000FF00) >> 8;
SD_cmd[4] = block & 0xFF;
SD_cmd[5] = 0xFF;
spi_send(SD_cmd, 6);
if (SD_response(0x00) == 1) {
printk(PSTR("SD block timeout\n"));
spi_init();
SD_init();
if(cnt < 16)goto again;
return 1;
}
if(cmd == SD_READ){
if (SD_response(0xFE) == 1){
printk(PSTR("SD data error\n"));
return 1;
}
} else {
spi_send_byte(0xFE);
}
return 0;
}
void SD_write_block(uint32_t block){
scheduler_stop();
if(SD_block_command(SD_WRITE, block)){
scheduler_start();
return;
}
spi_tx_eeprom(512);
spi_send_byte(0xFF);
spi_send_byte(0xFF);
printk(PSTR("resp=%d\n"), spi_rx_byte());
while(!spi_rx_byte());
SET_CS();
spi_rx_byte();
CLEAR_CS();
while(!spi_rx_byte());
SET_CS();
scheduler_start();
}
void spi_tx_eeprom(int length){
int i = 0;
for(i=0;i < length;i++){
spi_send_byte(eeprom_read_byte(i));
}
}
void spi_send_byte(uint8_t b){
SPDR = b;
while (!(SPSR & _BV(SPIF)));
}
uint8_t spi_rx_byte(){
SPDR = 0xFF;
while (!( SPSR & _BV(SPIF)));
return SPDR;
}
Hopefully I didn't make a mistake copying that. My code is spread between multiple files and I pasted it together (hence the weird place for the #define s)
Thanks!