|
|
  |
Работа с SD-картой, LPC1778 |
|
|
|
Jul 24 2014, 10:25
|
Местный
  
Группа: Участник
Сообщений: 234
Регистрация: 7-11-13
Пользователь №: 79 085

|
Начал изучать алгоритм чтения-записи данных на карту SD, для этого перевёл соответствующий раздел из LPC178x/7x User manual Rev. 2.1 — 6 March 2013. Пдфка прикреплена к сообщению. Нет уверенности, что перевод безошибочный, поэтому хотелось бы иметь критику со стороны, т.е. просьба к здешним читателям-писателям почитать мой перевод и указать на принципиальные ошибки, если таковые имеются. Существует ли какое-то упорядоченное и подробное описание команд работы с SD-картой? Желательно на русском языке. А ещё интересно посмотреть демонстрационный пример работы с картой памяти объёмом больше 4 ГГб. добавил более позднюю версию перевода, в предыдущей забыл две таблицы вставить
Сообщение отредактировал ДЕЙЛ - Jul 24 2014, 20:57
|
|
|
|
|
Jul 25 2014, 10:59
|
Местный
  
Группа: Участник
Сообщений: 234
Регистрация: 7-11-13
Пользователь №: 79 085

|
Цитата(andrewlekar @ Jul 25 2014, 11:39)  Вполне приличный перевод, на мой взгляд. Может вы так весь User Manual переведёте? Всётки есть сомнения насчёт возможных ошибок в переводе, поэтому и выложил для критики.Точный перевод потребует 2-3 итерации для согласованости написанного. На весь мануал энтузиазма пока не хватает.
|
|
|
|
|
Jul 28 2014, 10:44
|
Местный
  
Группа: Участник
Сообщений: 234
Регистрация: 7-11-13
Пользователь №: 79 085

|
Читаю описание команд и пока непонятна разница между командами CMD и ACMD. К примеру, CMD10 означает, что в поле индекса команды записывается число 10 или 0xA, а в чём отличие команды ACMD10? http://habrahabr.ru/post/213803/ Цитата Важное пояснение по поводу ACMD: пространство их индексов пересекается с индексами CMD команд, поэтому, чтобы контроллер воспринял команду именно, как Application-Specific, ей должна предшествовать CMD55! Т.е. команда ACMD10 равносильна последовательной передаче CMD55 с пустым аргументом и команды CMD10? Если так, то нужно ли ждать окончания ответа на команду CMD55 или сразу отсылать CMD10?
Сообщение отредактировал ДЕЙЛ - Jul 28 2014, 10:54
|
|
|
|
|
Jul 29 2014, 18:53
|
Местный
  
Группа: Участник
Сообщений: 234
Регистрация: 7-11-13
Пользователь №: 79 085

|
Опять имеются непонятки. При отправке команды CMD0 в карту возвращается ответ с установленным битом In Idle State, т.е. говорит, что карта в нерабочем состоянии. Но карточка рабочая - телефон её видит. Этот ответ с установленным нулевым битом допустим? В одном из описаний процесса инициализации после команды CMD0 ожидается ответ 0x00, а у меня почему-то всегда 0x01. Что тут не так может быть? Для пробы отправлял заведомо левую команду - бит 2 устанавливался, т.е. карта сказала, что команда неправильная. Тут всё нормально, но и бит 0 тоже всё равно в единицу установлен. Карта 8 гигов. Надо полагать, что SDHC. Частота тактирования 300 кГц. UP1. Отправил CMD8 c аргументом 0x1AA, т.е. указал карте питание хоста 2.7-3.5В, ответ пришёл вроде нормальный, т.е. с 0x1АА в хвосте, но бит 0 в ответе всё равно остался установленным.
Сообщение отредактировал ДЕЙЛ - Jul 29 2014, 19:21
Эскизы прикрепленных изображений
|
|
|
|
|
Jul 29 2014, 19:34
|
Гуру
     
Группа: Свой
Сообщений: 2 724
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702

|
Ответы нужно искать на Figure 7-2: SPI Mode Initialization Flow документа Physical Layer Simplified Specification Version 3.01 - там CMD1 нет. Если память мне не изменяет то CMD1 актуальна для MMC. Я инициализирую карточки так (правда, uSD, т.е. >=ver2.00): CODE //----------------------------------------------------------------------------- // BYTE sd_init(void) //----------------------------------------------------------------------------- BYTE sd_init(void) { volatile int i; BYTE response = 0xFF; DWORD data;
sCSD_V1 *csd_v1; sCSD_V2 *csd_v2;
sd_size_mb = 0;
// POWER OFF SD_PWR_bit = 1; delay_sd_tim(100); SD_PWR_bit = 0;
delay_sd_tim(200); SD_CS_bit = 1;
sd_set_mode(SD_MODE_INIT);
delay_sd_tim(10); for(i = 0; i < 74; i++) sd_send_byte(0xFF); delay_sd_tim(1);
SD_CS_bit = 0; sd_send_cmd(CMD0_GO_IDLE_STATE, 0, 0x95); response = sd_get_response(); SD_CS_bit = 1; sd_send_byte(0xFF);
#ifdef SD_DEBUG_INIT con_str("r_CMD0="); con_byte(response); con_str("\n\r"); con_start(); #endif
if(response == SD_RESP_IDLE) { i = 0;
#ifdef SD_DEBUG_INIT con_str("Send CMD8\n\r"); con_start(); #endif // SD_DEBUG_INIT
SD_CS_bit = 0; sd_send_cmd(CMD8_SEND_IF_COND, CARD_COND, 0x86); response = sd_get_response(); data = sd_get_dword(); SD_CS_bit = 1; sd_send_byte(0xFF);
#ifdef SD_DEBUG_INIT con_str("r_CMD8="); con_byte(response); con_str(" - "); con_dword(data); con_str("\n\r"); con_start(); #endif // SD_DEBUG_INIT
if(response == SD_RESP_IDLE) { sd_type = SD_TYPE_V2;
#ifdef SD_DEBUG_INIT con_str("SD ver2.00 or later.\n\r"); con_start(); #endif // SD_DEBUG_INIT
if(data != CARD_COND) return SD_INIT_ERROR;
#ifdef SD_DEBUG_INIT con_str("Valid voltage range\n\r"); con_str("Send ACMD41\n\r"); con_start(); #endif // SD_DEBUG_INIT
do { SD_CS_bit = 0; con_str("cmd55->"); con_start(); sd_send_cmd(CMD55_APP_CMD, 0, 0xFF); response = sd_get_response(); SD_CS_bit = 1; sd_send_byte(0xFF); if(response == SD_RESP_IDLE) { SD_CS_bit = 0; con_str("acmd41->"); con_start(); sd_send_cmd(CMD41_SEND_APP_OP_COND, SDIO_CARD_CCS | OCR_INDEX, 0xFF); response = sd_get_response(); SD_CS_bit = 1; sd_send_byte(0xFF); } else response = SD_RESP_IDLE;
while(con.tx_t != con.tx_b);
} while(response == SD_RESP_IDLE);
#ifdef SD_DEBUG_INIT con_str("Card ready\n\r"); con_str("Send CMD58\n\r"); con_start(); #endif // SD_DEBUG_INIT
SD_CS_bit = 0; sd_send_cmd(CMD58_READ_OCR, 0, 0xFF); response = sd_get_response(); data = sd_get_dword(); SD_CS_bit = 1; sd_send_byte(0xFF);
#ifdef SD_DEBUG_INIT con_str("r_CMD58="); con_byte(response); con_str(" - "); con_dword(data); con_str("\n\r"); con_start(); #endif // SD_DEBUG_INIT
if(data & SDIO_CARD_CCS) { #ifdef SD_DEBUG_INIT con_str("CCS = 1\n\r"); con_start(); #endif // SD_DEBUG_INIT sd_type = SD_TYPE_SDHC; } else { #ifdef SD_DEBUG_INIT con_str("CCS = 0\n\r"); con_start(); #endif // SD_DEBUG_INIT sd_type = SD_TYPE_NORMAL; } } else { sd_type = SD_TYPE_UNDEF; return SD_INIT_ERROR; }
while(response != SD_RESP_SUCCESS) { SD_CS_bit = 0; sd_send_cmd(CMD1_SEND_OP_COND, 0, 0xFF); response = sd_get_response(); SD_CS_bit = 1; sd_send_byte(0xFF); i++; if(i == 0x100000) { #ifdef SD_DEBUG_INIT con_str("r_CMD1="); con_byte(response); con_str(", i="); con_dword(i); con_str("\n\r"); con_start(); #endif return SD_TIMEOUT_ERROR; } } #ifdef SD_DEBUG_INIT con_str("r_CMD1="); con_byte(response); con_str(", i="); con_dword(i); con_str("\n\r"); con_start(); #endif } else { #ifdef SD_DEBUG_INIT con_str("INIT_ERROR\n\rr_CMD0="); con_byte(response); con_str("\n\r"); con_start(); #endif return SD_INIT_ERROR; }
// CMD9 Read CSD con_str("CMD9\n\r"); con_start();
SD_CS_bit = 0; sd_send_cmd(CMD9_SEND_CSD, 0, 0xFF); response = sd_get_response(); if(response == SD_RESP_SUCCESS) { response = sd_get_xx_response(SD_START_DATA_BLOCK_TOKEN); for(i = 0; i < 16; i++) sd_buf[15 - i] = sd_send_byte(0xFF); SD_CS_bit = 1; sd_send_byte(0xFF);
csd_v1 = (sCSD_V1 *)sd_buf; con_str("[CSD SOURCE: "); for(i = 0; i < 16; i++) con_byte(((BYTE *)sd_buf)[i]); con_str("]\n\r"); con_start();
if(csd_v1->csd_structure == 0) { sd_size_mb = ((csd_v1->c_size + 1) * (1 << csd_v1->read_bl_len) * (1 << (csd_v1->c_size_mult + 2))) >> 20; con_str("\n\n\rTotal Size: "); con_dec(sd_size_mb); con_str(" MB\n\n\r"); con_start(); } else if(csd_v1->csd_structure == 1) { csd_v2 = (sCSD_V2 *)sd_buf; sd_size_mb = (csd_v2->c_size + 1) >> 1; con_str("\n\n\rTotal Size: "); con_dec(sd_size_mb); con_str(" MB\n\n\r"); con_start(); } } else { SD_CS_bit = 1; sd_send_byte(0xFF); }
sd_set_mode(SD_MODE_DATA); sd_send_byte(0xff); sd_send_byte(0xff);
return sd_set_block_length(512); }
Устойчиво работают карты разных производителей, объемом 2Gb, 4GB, 8Gb, 16GB и 32GB.
|
|
|
|
|
Jul 29 2014, 20:02
|
Местный
  
Группа: Участник
Сообщений: 234
Регистрация: 7-11-13
Пользователь №: 79 085

|
Днём покопаюсь в коде, а пока читаю вот тут habrahabr.ru/post/213803/ Насколько правильно там всё описано? Я пока застрял на ожидании ответа на ACMD41 с установленными в аргументе битами 30 и 20(3.2 - 3.3В). Предполагаемого ответа в виде содержимого регистра OCR с установленной единицей в 31 бите пока не вижу. Только изменился бит 0 в ответе R1 на нулевой. UP1: Проблема в описании по ссылке - автор по памяти наверно писал и упустил один момент. Делал как тут http://we.easyelectronics.ru/AVR/mmcsd-i-a...tifikaciya.html и вроде дальше продвинулся, читаю дальше http://we.easyelectronics.ru/AVR/mmcsd-i-a...a-s-kartoy.html и вроде пока получилось считать регистр CSD.
Сообщение отредактировал ДЕЙЛ - Jul 29 2014, 20:44
|
|
|
|
|
Aug 3 2014, 17:33
|
Местный
  
Группа: Участник
Сообщений: 234
Регистрация: 7-11-13
Пользователь №: 79 085

|
Продолжаю ковыряться с SD-картой. С алгоритмом инициализации, чтения и записи самой карты в общих чертах разобрался. Теперь копаюсь с интерфейсом карты со стороны МК. В нём имеется буфер FIFO, с которым у меня появились непонятки. Насколько я понимаю, этот буфер проталкивает через себя 32битные слова от начала к хвосту по мере появления данных в начальной ячейке. Настроил срабатывание прерывания по каждому заполнению буфера, т.е. 16*4=64 байта. Тут всё нормально. Дальше в прерывании останавливаю SD_CLK, принятые данные копирую для передачи на ПК, сбрасываю флаг заполнения и опять включаю SD_CLK. Только почему-то получается такая ерунда, что во всех ячейках буфера одинаковые данные, причём такая картина и в режиме отладки, и в обычном режиме работы. Какая тут может быть причина? Можно было бы код приложить, но его от всего лишнего чистить нужно долго - там вся инициализация и команды чтения-записи выполняется с ПК через UART. Надеюсь, что кто-то из местных наблюдал у себя такую картину. Интересно было бы узнать, на что нужно обратить внимание.
Эскизы прикрепленных изображений
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|