#include "sd.h" #include "spi.h" uint8_t SDHC; // глобальная переменная для определения типа карты //******************************************************************************************** //function посылка команды в SD // //Arguments команда и ее аргумент // //return 0xff - нет ответа // //******************************************************************************************** uint8_t SD_sendCommand(uint8_t cmd, uint32_t arg) { uint8_t response, wait=0, tmp; // для карт памяти SD выполнить коррекцию адреса, т.к. для них адресация побайтная if(SDHC == 0) if(cmd == READ_SINGLE_BLOCK || cmd == WRITE_SINGLE_BLOCK ) {arg = arg << 9;} //для SDHC коррекцию адреса блока выполнять не нужно(постраничная адресация) spi_cs_enable(); //передать код команды и ее аргумент spi_send(cmd | 0x40); spi_send(arg>>24); spi_send(arg>>16); spi_send(arg>>8); spi_send(arg); // передать CRC (учитываем только для двух команд) if(cmd == SEND_IF_COND) spi_send(0x87); else spi_send(0x95); // ожидаем ответ while((response = spi_read()) == 0xff) if(wait++ > 0xfe) break; // таймаут, не получили ответ на команду // проверка ответа если посылалась команда READ_OCR if(response == 0x00 && cmd == 58) { tmp = spi_read(); // прочитать один байт регистра OCR if(tmp & 0x40) SDHC = 1; // обнаружена карта SDHC else SDHC = 0; // обнаружена карта SD // прочитать три оставшихся байта регистра OCR spi_read(); spi_read(); spi_read(); } // spi_read(); spi_cs_disable(); return response; } //******************************************************************************************** //function инициализация карты памяти // //return 0 - карта инициализирована // //******************************************************************************************** uint8_t SD_init(void) { uint8_t i; uint8_t response; uint8_t SD_version = 2; // по умолчанию версия SD = 2 uint16_t retry = 0 ; spi_init(); // инициализировать модуль SPI for(i=0;i<10;i++) spi_send(0xff); // послать свыше 74 единиц // выполним программный сброс карты spi_cs_enable(); while(SD_sendCommand(GO_IDLE_STATE, 0)!=0x01) if(retry++>0x20) return 1; spi_cs_disable(); spi_send (0xff); spi_send (0xff); retry = 0; while(SD_sendCommand(SEND_IF_COND,0x000001AA)!=0x01) { if(retry++>0xfe) { SD_version = 1; break; } } retry = 0; do { response = SD_sendCommand(APP_CMD,0); response = SD_sendCommand(SD_SEND_OP_COND,0x40000000); retry++; if(retry>0xffe) return 1; }while(response != 0x00); // читаем регистр OCR, чтобы определить тип карты retry = 0; SDHC = 0; if (SD_version == 2) { while(SD_sendCommand(READ_OCR,0)!=0x00) if(retry++>0xfe) break; } return 0; } //******************************************************************************************** //function чтение регистра CSD карты // //Arguments указатель на буфер размером 16 байт // //return 0 - регистр прочитан успешно // //******************************************************************************************** uint8_t SD_ReadCSD(uint8_t *buff) { uint16_t i=0; // послать команду "чтение CSD" if(SD_sendCommand(READ_CSD, 0)) return 1; CS_ENABLE; // ожидание маркера данных while(spi_read() != 0xfe) if(i++ > 0xfffe) {CS_DISABLE; return 1;} // чтение 16 байт регистра CSD for(i=0; i<16; i++) buff[i] = spi_read(); spi_read(); spi_read(); spi_read(); CS_DISABLE; return 0; } //******************************************************************************************** //function чтение выбранного сектора SD // //Arguments номер сектора, указатель на буфер размером 512 байт // //return 0 - сектор прочитан успено // //******************************************************************************************** uint8_t SD_ReadSector(uint32_t BlockNumb, uint8_t *buff) { uint16_t i=0; // послать команду "чтение одного блока" с указанием его номера if(SD_sendCommand(READ_SINGLE_BLOCK, BlockNumb)) return 1; spi_cs_enable(); // ожидание маркера данных while(spi_read() != 0xfe) if(i++ > 0xfffe) {spi_cs_disable(); return 1;} // чтение 512 байт выбранного сектора for(i=0; i<512; i++) *buff++ = spi_read(); // for(i=0; i<512; i++) buff[i] = spi_read(); spi_read(); spi_read(); spi_read(); spi_cs_disable(); return 0; } //******************************************************************************************** //function запись выбранного сектора SD // //Arguments номер сектора, указательна данные для записи // //return 0 - сектор записан успешно // //******************************************************************************************** uint8_t SD_WriteSector(uint32_t BlockNumb, uint8_t *buff) { uint8_t response; uint16_t i,wait=0; // послать команду "запись одного блока" с указанием его номера if( SD_sendCommand(WRITE_SINGLE_BLOCK, BlockNumb)) return 1; spi_cs_enable(); spi_send(0xfe); // записать буфер сектора в карту for(i=0; i<512; i++) spi_send(*buff++); spi_send(0xff); // читаем 2 байта CRC без его проверки spi_send(0xff); response = spi_read(); if( (response & 0x1f) != 0x05) // если ошибка при приеме данных картой { spi_cs_disable(); return 1; } // ожидаем окончание записи блока данных картой while(!spi_read()) // пока карта занята, она выдает ноль if(wait++ > 0xfffe){spi_cs_disable(); return 1;} spi_cs_disable(); spi_send(0xff); spi_cs_enable(); while(!spi_read()) // пока карта занята, она выдает ноль if(wait++ > 0xfffe){spi_cs_disable(); return 1;} spi_cs_disable(); return 0; } //******************************************************************************************** //function чтение емкости карты в секторах (по 512 байт) из регистра CSD карты // //Arguments нет // //return 0 - не удалось прочитать // // не 0 - количество секторов карты // //******************************************************************************************** uint32_t SD_GetSectors(void) { uint32_t sectors; uint8_t buff[16]; // попытка прочитать регистр CSD if(SD_ReadCSD(buff)) return 0; // проверка версии формата регистра // if ((buff[0] >> 6) + 1 == 1) if((buff[0] & 0xC0) == 0) { /* CSD v1 */ sectors = (((buff[6]&0x3)<<10 | buff[7]<<2 | buff[8]>>6)+1) << (2+(((buff[9]&3) << 1) | buff[10]>>7)) << ((buff[5] & 0xf) - 9); /* ^ = (c_size+1) * 2**(c_size_mult+2) * 2**(read_bl_len-9) */ } else { /* CSD v2 */ /* this means the card is HC */ // hw->capabilities |= CAP_SDHC; sectors = buff[7]<<16 | buff[8]<<8 | buff[9]; /* in 512 kB */ sectors *= 1024; /* in 512 B sectors */ } return sectors; } //******************************************************************************************** //function чтение кратности стирания карты в байтах, из регистра CSD карты? // //Arguments нет // //return 0 - не удалось прочитать // // не 0 - размер, в байтах, кратно которому происходит стирание блоков памяти карты // //******************************************************************************************** uint8_t SD_GetEraseSectors(void) { uint32_t erase_sectors; uint8_t buff[16]; // попытка прочитать регистр CSD if(SD_ReadCSD(buff)) return 0; // проверка флага erase_blk_en // if erase_blk_en = 0, then only this many sectors // can be erased at once // это не было протестировано автором (Domen Puncer, Visionect, d.o.o.) if(((buff[10]>>6)&1) == 0) erase_sectors = ((buff[10]&0x3f)<<1 | buff[11]>>7) + 1; else erase_sectors = 1; return erase_sectors; }