Перейти к содержанию
    

Работа с SD-картой

Начал изучать алгоритм чтения-записи данных на карту SD, для этого перевёл соответствующий раздел из LPC178x/7x User manual Rev. 2.1 — 6 March 2013. Пдфка прикреплена к сообщению. Нет уверенности, что перевод безошибочный, поэтому хотелось бы иметь критику со стороны, т.е. просьба к здешним читателям-писателям почитать мой перевод и указать на принципиальные ошибки, если таковые имеются.

 

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

 

добавил более позднюю версию перевода, в предыдущей забыл две таблицы вставить

________SD_______.pdf

Изменено пользователем ДЕЙЛ

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вполне приличный перевод, на мой взгляд. Может вы так весь User Manual переведёте?

Всётки есть сомнения насчёт возможных ошибок в переводе, поэтому и выложил для критики.Точный перевод потребует 2-3 итерации для согласованости написанного. На весь мануал энтузиазма пока не хватает.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Здесь был вопрос, но проблема была в настройках осциллографа, уж чуть было мозги не закипели :05:

Изменено пользователем ДЕЙЛ

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Читаю описание команд и пока непонятна разница между командами CMD и ACMD. К примеру, CMD10 означает, что в поле индекса команды записывается число 10 или 0xA, а в чём отличие команды ACMD10?

 

http://habrahabr.ru/post/213803/

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

 

Т.е. команда ACMD10 равносильна последовательной передаче CMD55 с пустым аргументом и команды CMD10? Если так, то нужно ли ждать окончания ответа на команду CMD55 или сразу отсылать CMD10?

Изменено пользователем ДЕЙЛ

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

UP1. Отправил CMD8 c аргументом 0x1AA, т.е. указал карте питание хоста 2.7-3.5В, ответ пришёл вроде нормальный, т.е. с 0x1АА в хвосте, но бит 0 в ответе всё равно остался установленным.

post-79085-1406660012_thumb.jpg

Изменено пользователем ДЕЙЛ

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ответы нужно искать на Figure 7-2: SPI Mode Initialization Flow документа Physical Layer Simplified Specification Version 3.01 - там CMD1 нет.

Если память мне не изменяет то CMD1 актуальна для MMC.

Я инициализирую карточки так (правда, uSD, т.е. >=ver2.00):

//-----------------------------------------------------------------------------
//	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. Надеюсь, что кто-то из местных наблюдал у себя такую картину. Интересно было бы узнать, на что нужно обратить внимание.

post-79085-1407087126_thumb.jpg

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Попробовал записать в один из 16 регистров FIFO - записываю в один, меняется содержимое сразу во всех. У каждого регистра свой отдельный адрес. Как токое может быть? На скрине режим пошаговой отладки в железе.

post-79085-1407266909_thumb.jpg

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...