Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Работа с SD-картой
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
ДЕЙЛ
Начал изучать алгоритм чтения-записи данных на карту SD, для этого перевёл соответствующий раздел из LPC178x/7x User manual Rev. 2.1 — 6 March 2013. Пдфка прикреплена к сообщению. Нет уверенности, что перевод безошибочный, поэтому хотелось бы иметь критику со стороны, т.е. просьба к здешним читателям-писателям почитать мой перевод и указать на принципиальные ошибки, если таковые имеются.

Существует ли какое-то упорядоченное и подробное описание команд работы с SD-картой? Желательно на русском языке. А ещё интересно посмотреть демонстрационный пример работы с картой памяти объёмом больше 4 ГГб.

добавил более позднюю версию перевода, в предыдущей забыл две таблицы вставить
andrewlekar
Вполне приличный перевод, на мой взгляд. Может вы так весь User Manual переведёте?
ДЕЙЛ
Цитата(andrewlekar @ Jul 25 2014, 11:39) *
Вполне приличный перевод, на мой взгляд. Может вы так весь User Manual переведёте?

Всётки есть сомнения насчёт возможных ошибок в переводе, поэтому и выложил для критики.Точный перевод потребует 2-3 итерации для согласованости написанного. На весь мануал энтузиазма пока не хватает.
ДЕЙЛ
Здесь был вопрос, но проблема была в настройках осциллографа, уж чуть было мозги не закипели 05.gif
ДЕЙЛ
Читаю описание команд и пока непонятна разница между командами CMD и ACMD. К примеру, CMD10 означает, что в поле индекса команды записывается число 10 или 0xA, а в чём отличие команды ACMD10?

http://habrahabr.ru/post/213803/
Цитата
Важное пояснение по поводу ACMD: пространство их индексов пересекается с индексами CMD команд, поэтому, чтобы контроллер воспринял команду именно, как Application-Specific, ей должна предшествовать CMD55!


Т.е. команда ACMD10 равносильна последовательной передаче CMD55 с пустым аргументом и команды CMD10? Если так, то нужно ли ждать окончания ответа на команду CMD55 или сразу отсылать CMD10?
adnega
На CMD55 нужно ждать ответа R1.
ДЕЙЛ
Опять имеются непонятки. При отправке команды CMD0 в карту возвращается ответ с установленным битом In Idle State, т.е. говорит, что карта в нерабочем состоянии. Но карточка рабочая - телефон её видит. Этот ответ с установленным нулевым битом допустим? В одном из описаний процесса инициализации после команды CMD0 ожидается ответ 0x00, а у меня почему-то всегда 0x01. Что тут не так может быть? Для пробы отправлял заведомо левую команду - бит 2 устанавливался, т.е. карта сказала, что команда неправильная. Тут всё нормально, но и бит 0 тоже всё равно в единицу установлен. Карта 8 гигов. Надо полагать, что SDHC. Частота тактирования 300 кГц.

UP1. Отправил CMD8 c аргументом 0x1AA, т.е. указал карте питание хоста 2.7-3.5В, ответ пришёл вроде нормальный, т.е. с 0x1АА в хвосте, но бит 0 в ответе всё равно остался установленным.
adnega
Ответы нужно искать на 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.
ДЕЙЛ
Днём покопаюсь в коде, а пока читаю вот тут 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.
ДЕЙЛ
Продолжаю ковыряться с SD-картой. С алгоритмом инициализации, чтения и записи самой карты в общих чертах разобрался. Теперь копаюсь с интерфейсом карты со стороны МК. В нём имеется буфер FIFO, с которым у меня появились непонятки. Насколько я понимаю, этот буфер проталкивает через себя 32битные слова от начала к хвосту по мере появления данных в начальной ячейке. Настроил срабатывание прерывания по каждому заполнению буфера, т.е. 16*4=64 байта. Тут всё нормально. Дальше в прерывании останавливаю SD_CLK, принятые данные копирую для передачи на ПК, сбрасываю флаг заполнения и опять включаю SD_CLK. Только почему-то получается такая ерунда, что во всех ячейках буфера одинаковые данные, причём такая картина и в режиме отладки, и в обычном режиме работы. Какая тут может быть причина? Можно было бы код приложить, но его от всего лишнего чистить нужно долго - там вся инициализация и команды чтения-записи выполняется с ПК через UART. Надеюсь, что кто-то из местных наблюдал у себя такую картину. Интересно было бы узнать, на что нужно обратить внимание.
ДЕЙЛ
Попробовал записать в один из 16 регистров FIFO - записываю в один, меняется содержимое сразу во всех. У каждого регистра свой отдельный адрес. Как токое может быть? На скрине режим пошаговой отладки в железе.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.