SD/MMC карта памяти и микроконтроллер AVR (часть 1) Базовые операции.

Работа SD/MMC карты с микроконтроллером AVR

Как-то давно хотел себе сделать логгер температуры, возникла необходимость использовать внешнюю EEPROM память. Прикинув, что в наличие имеется 512кб память с i2c интерфейсом, сделал на ней экспериментальный логгер. Но когда возникла необходимость скинуть данные на компьютер для последующей обработки, то вылезли трудности с написанием софтины, которая бы считывала данные с EEPROM и писала бы их в текстовый файл.

Софтину я написал, только работала она как-то корявенько и медленно, для меня сойдет, а вот для массового производства корявости недопустимы. Захотелось писать данные на карту памяти, которую можно потом вставить в карт-ридер и через проводник перекинуть на компьютер, где их уже можно обрабатывать чем удобно. Для этого нужно уметь собственно писать данные на карту памяти, и знать файловую систему FAT, чтобы карточка распозналась компьютером. С этого вступления хочу начать небольшой цикл из 3-х статей, в котором я напишу про то, как работать с SD/MMC картой памяти и файловой системой FAT.
Карточку SD я выбрал из-за того, что внутри ее есть встроенный контроллер и что с ней можно работать в SPI 0 режиме (положительный синхроимпульс, защёлкивание по переднему фронту, сдвиг по заднему фронту), с которым довольно просто совладать. Посмотрим на распиновку(цоколевку) SD карты:
распиновка SD карты

Видно, что карточка имеет 9 контактов, предназначение их следующее.
распиновка SD карты
При работе с микроконтроллерами режима SPI за глаз хватает по скорости, потому использовать родной режим работы карты памяти будет нецелесообразно. Нам понадобятся пины DI, DO, CLK, CS для передачи данных и VSS, VDD для питания. Теперь немного про питание, SD карта требует от 2,7В до 3,6В, и тока до 100мА. Также если планируется горячее подключения, нужно предусмотреть просадку питающего напряжения при подсоединении карты. Иначе питание может просесть до такого уровня, когда BOD детектор сработает и ресетнет микроконтроллер. Этого можно избежать, налепив по питания конденсаторов и индуктивность. Учитывая все это, была слеплена стендовая платка для работы с SD картой:
фото макетки для SD карты
Схема платки показана ниже:

Для питания карты памяти предусмотрен стабилизатор на 3,3В - LP2980-3.3. Его обвязка из конденсаторов C1,C3 – 100мкф, танталовые; C2,C4 – 0,1мкф, керамика; L1 – индуктивность на 22мкГн. Для сопряжения TTL уровней сигналов предусмотрены резистивные делители R2-R4 по 5,6кОм; R5-R7 по 10кОм. Светодиод D1 – сигнальный, для него ограничивающий резистор R1 – 470 Ом. Также на разъеме оказались выводы WP и INS, отслеживая состояния которых можно понять, защищена ли карта от записи механической защелкой, и присутствует ли карта в разъеме соответственно. Далее дело за подключением, все сигналы с карты подключил к PortB микроконтроллера. Нежелание использовать аппаратный SPI микроконтроллера буду аргументировать плохой переносимостью кода на разные модели микроконтроллеров. Для работы с SD картой сразу буду использовать ATmega32 (при работе с FAT нам понадобится около 20кб флеша). Хотя можно использовать хоть Atmega8, благо код для этого переделывать не нужно. Схема подключения к микроконтроллеру показана ниже:

Тактовый генератор – встроенный RC на 8Мгц, хотя можно использовать любой, но с 8Мгц работает шустро. Конденсаторы C5,C7 – по 100мкФ, электролиты, С4,С6 – 0,1мкф, керамика. Так как мы будем передавать большие объемы данных (стандартный блок – 512 байт), то выводить их будем по UART на компьютер в программу Terminal 1.9. Про сопряжение UART микроконтроллера с компьютером я писал уже неоднократно вот здесь, здесь и даже здесь.
фото стенда для SD карты
Теперь у нас есть все железо для экспериментов с картой памяти. Но прежде чем перейти к программной части, упомянем, что карта типа MMC также может работать в SPI режиме. Для ее управления также стоит использовать выводы DI, DO, CLK, CS. Схемотехнические рассуждения для MMC такие же, как и для SD карты. Распиновка MMC карты показана ниже:
распиновка MMC карты
Перейдем к программной части. Рассмотрим, как инициализировать карту, и писать/читать из нее. Для перехода в режим SPI нужно дождаться, пока питающее напряжения на карте достигнет 3В (несколько миллисекунд, после включения) и подать более 74 импульса на выводе CLK, при высоком уровне на CS и DI выводах.

После нужно выставить на CS нулевой уровень, далее карта входит в режим SPI, теперь для успешной работы следует подать команды сброса и инициализации CMD0, CMD1 прежде, чем мы сможем писать/читать данные из карты. Команд для карты довольно много, часть из них приведена в таблице ниже:
таблица команд SD карты
Команд много, но основанная масса работы производится командами CMD0, CMD1 (сброс и инициализация) CMD17 (чтение), CMD24 (запись). Весь перечень команд и как с ними работать, можно просмотреть в родной спецификации SD карты на английском.
Рассмотрим формат команды для SD карты.
формат команды команд SD карты
Сперва идет индекс команды. Индекс команды в десятичном виде определяется как 64+имя команды. Далее следует 4 байта аргументов (данные, адрес), после следует 7-ми битная контрольная сумма. После успешной отправки команды следует послать байтовую паузу из 8*N тактовых импульсов (N - целое), после чего карта ответит. Ответ может быть типа R1,R2,R3. В нашем случае, ответы будут только типа R1. Поэтому рассмотрим только его.
ответ R1 SD карты
Старший бит R1 всегда равен 0. Назначения остальных битов хорошо видно с рисунка.
Рассмотрим процесс инициализации карты памяти командами CMD0,CMD1. Сперва, при высоком уровне на выводах CS и DI подаем 80 тактовых импульсов на вывод CLK. Далее на все время работы с картой сажаем CS на землю, подаем команду CMD0, контрольная сумма для которой равнa 0x95 (контрольная сумма в нашем случае нужна только для команды CMD0, в остальных случаях она не проверяется, поэтому все время будем использовать 0х95 как контрольную сумму). Далее, после байтовой паузы, карточка должна ответить 0х01, что означает, что она вошла в SPI режим и готова принимать команды. Теперь подаем команды CMD1, и после паузы ожидаем от карточки ответа 0х00, которые говорит о том, что карта готова к обмену данными.

Обмен данными между картой памяти и микроконтроллером будет производиться стандартными блоками по 512 байт. Адресация карты побайтная, начиная с нуля, но считывать данные можно только блоками. Адресом блока служит первый его байт. То есть 0-й блок имеет адрес 0х0000, 1-й блок - 0х0200, 2-й блок – 0х400 и т.д. (справедливо для размера блока 512 байт). В SDHC картах адресация поблочная, адресом блока служит его номер. Операция чтения блока производится в следующем порядке. Подается команда CMD17, байтовая пауза, если принимается ответ 0х00, то после еще одной байтовой паузы принимается блок данных, структура которого показана ниже.
блок данных SD карты
Некое подобие временной диаграммы операции чтения можно посмотреть на рисунке ниже
диаграма чтения блока данных с SD карты
Как видно, блок начинается с байта 0хFE (для команд CMD17/18, CMD24), далее идет 512 байт информации и 2 байта контрольной суммы (которая по умолчанию не используется). Операция записи производиться похоже, команда CMD24, пауза, ответ карты 0х00, и блок данных (так как контрольная сумма не проверяется, то ее поле можно заполнить случайно ). Далее следует ответ карты про прием блока данных.
ответ на блока данных SD карты
После чего busy состояние, когда карта записывает полученные данные. Временная диаграмма операции записи приведена ниже.
диаграма записи блока на SD карту
Для подтверждения вышесказанного хочу привести пример работы с картой. Запишем в блок под номером 1 (адрес 0х0200) какие-то циклически повторяющиеся данные, например чередующиеся цифры от 0 до 9, а потом считаем этот же блок и посмотрим, записались ли наши данные. Для этого была написана небольшая программка :

  1. #include <avr/io.h> //Cтандартная библиотека ввода/вывода
  2. #include <string.h> //Библиотека для работы с строками
  3.  
  4. #define DI 0
  5. #define DO 1
  6. #define CLK 2
  7. #define CS 3
  8. #define INS 4
  9. #define WP 5
  10.  
  11. char buffer [512]={}; //Буфер данных для записи/чтения
  12.  
  13. //Программа инициализации UART
  14. void uart_init(void)
  15. {
  16. UBRRH = 0x00; //256000 битрейт, 1 стоп бит, без проверки четности
  17. UBRRL = 0x01;
  18. UCSRA = 0x00;
  19. UCSRB = (1<<RXEN)|(1<<TXEN); //Прием и передача разрешена
  20. UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
  21. }
  22.  
  23. //Программа передачи байта по UART
  24. void uart_transmit(unsigned char data)
  25. {
  26. while ( !( UCSRA & (1<<UDRE)) );
  27. UDR = data;
  28. }
  29.  
  30. //Программа приема байта по UART
  31. unsigned char uart_receive (void)
  32. {
  33. while ( !(UCSRA & (1<<RXC)) );
  34. return UDR;
  35. }
  36.  
  37. //Программа передачи строки по UART
  38. void uart_transmit_message(char* msg)
  39. { unsigned char i;
  40. i=0; //Начальное значение переменной
  41.  
  42. //Цикл до перебора всех элементов строки
  43. while ((i<256)&(msg[i]!=0x00) )
  44. {
  45. //Отправка поэлементно символов строки
  46. uart_transmit(msg[i]);
  47. i++; //Увеличиваем номер элемента строки
  48. }
  49. }
  50.  
  51. //Программа передачи байта карте SD|MMC
  52. void spi_transmit (unsigned char data)
  53. {
  54. unsigned char i;
  55. for (i=0;i<8;i++) //Цикл перебора битов отправляемого байта
  56. {
  57. if ((data&0x80)==0x00) //Если все данные переданы
  58. PORTB&=~_BV(DI); //Выставить бит данных
  59. else
  60. PORTB|=_BV(DI);
  61. data=data<<1;
  62. PORTB|=_BV(CLK); //Импульс
  63. asm("nop"); //Пауза в 1 такт
  64. PORTB&=~_BV(CLK);
  65. }
  66. }
  67.  
  68. //Программа приема байт от карты SD|MMC
  69. unsigned char spi_receive (void)
  70.  
  71. {
  72. //Декларация переменных
  73. unsigned char i, res=0;
  74. for(i=0;i<8;i++)
  75. {
  76. PORTB|=_BV(CLK); //Фронт импульса
  77. res=res<<1;
  78. if ((PINB&_BV(DO))!=0x00)
  79. res=res|0x01; //Считать бит данных
  80. PORTB&=~_BV(CLK); //Спад испульса
  81. asm("nop");
  82. }
  83. return res;
  84. }
  85.  
  86. unsigned char sd_cmd(char b0, char b1, char b2, char b3, char b4, char b5)
  87. //Отправка команды карте SD|MMC
  88. { unsigned char res;
  89. long int count;
  90. spi_transmit (b0); //Передать индекс команды
  91.  
  92. spi_transmit (b1); //Передать аргумент
  93. spi_transmit (b2);
  94. spi_transmit (b3);
  95. spi_transmit (b4);
  96.  
  97. spi_transmit (b5); //Передать CRC
  98. count=0;
  99. do { //Подождпть R1 ответа
  100. res=spi_receive();
  101. count=count+1;
  102. } while ( ((res&0x80)!=0x00)&&(count<0xffff) );
  103. return res;
  104. }
  105.  
  106. unsigned char sd_card_init(void)
  107. { unsigned char i,temp;
  108. long int count;
  109.  
  110. if ((PINB&_BV(INS))!=0x00) return 1; //Проверка карты в слоту
  111.  
  112. for (i=0;i<10;i++) //80 импульсов
  113. spi_transmit (0xff);
  114. PORTB&=~_BV(CS); //CS опустить
  115.  
  116. temp=sd_cmd (0x40,0x00,0x00,0x00,0x00,0x95); //CMD0
  117. if (temp!=0x01) return 3; //Выйти, если ответ не 0х01
  118. spi_transmit (0xff);
  119.  
  120. count=0;
  121. do{
  122. temp=sd_cmd (0x41,0x00,0x00,0x00,0x00,0x95); //CMD1
  123. spi_transmit (0xff);
  124. count=count+1;
  125. } while ( (temp!=0x00)&&(count<0xffff) ); //Ждем 0x01 ответа R1
  126.  
  127. if (count>=0xffff) return 4;
  128. return 0;
  129. }
  130.  
  131. unsigned char read_block (char* buff, unsigned char a1, unsigned char a2, unsigned char a3, unsigned char a4)
  132. { unsigned char temp;
  133. long int count;
  134.  
  135. if ((PINB&_BV(INS))!=0x00) return 1; //Проверка карты в слоту
  136.  
  137. temp=sd_cmd (0x51,a1,a2,a3,a4,0x95); //CMD17
  138. if (temp!=0x00) return 5; //Выйти, если ответ не 0x00
  139. spi_transmit (0xff);
  140. count=0;
  141. do{ //Ждем начала пакета данных
  142. temp=spi_receive();
  143. count=count+1;
  144. } while ( (temp!=0xfe)&&(count<0xffff) );
  145.  
  146. if (count>=0xffff) return 5;
  147.  
  148. for (count=0;count<512;count=count+1) //Сохраняем данные
  149. buff[count]=spi_receive();
  150. spi_receive(); //Сохраняем CRC
  151. spi_receive();
  152. return 0;
  153. }
  154.  
  155. unsigned char write_block (char* buff, unsigned char a1, unsigned char a2, unsigned char a3, unsigned char a4)
  156. { unsigned char temp;
  157. long int count;
  158.  
  159. if ((PINB&_BV(INS))!=0x00) return 1; //Проверка карты в слоту
  160. if ((PINB&_BV(WP))!=0x00) return 2; //Проверка write protect
  161.  
  162. temp=sd_cmd(0x58,a1,a2,a3,a4,0x95); //CMD24
  163. if (temp!=0x00) return 6; //Выйти, если ответ не 0x00
  164. spi_transmit (0xff);
  165.  
  166. spi_transmit (0xfe); //Начало пакета данных
  167. for (count=0;count<512;count=count+1) //Отослать данные
  168. spi_transmit(buff[count]);
  169. spi_transmit (0xff); //Отослать CRC
  170. spi_transmit (0xff);
  171. temp=spi_receive();
  172. if ((temp&0x05)!=0x05) return 6; //Выйти, если данные не приняты
  173.  
  174. count=0;
  175. do { //Ждем окончания busy состояния
  176. temp=spi_receive();
  177. count=count+1;
  178. }while ( (temp!=0xff)&&(count<0xffff) );
  179. if (count>=0xffff) return 6;
  180. return 0;
  181. }
  182.  
  183. int main(void)
  184. { unsigned char temp;
  185. int i;
  186.  
  187. PORTB=_BV(CS)|_BV(DO)|_BV(DI)|_BV(WP)|_BV(INS); //Инициализация портов
  188. DDRB=_BV(CS)|_BV(DI)|_BV(CLK);
  189.  
  190. uart_init(); //Инициализация UART
  191.  
  192. temp=sd_card_init(); //Инициализация карты
  193. if (temp==0x00)
  194. {
  195. uart_transmit_message("sd_card_init: initialization succes\r\n");
  196. for (i=0;i<512;i=i+1)
  197. buffer[i]=0x30+(i%10); //Заполнить буфер 12345...
  198.  
  199. temp=write_block(buffer,0x00,0x00,0x02,0x00);//Записать буфер
  200. if(temp==0x00) uart_transmit_message("write_block: block writte succes\r\n");
  201. else if (temp==1) uart_transmit_message("write_block: fail, no card in the slot\r\n");
  202. else if (temp==2) uart_transmit_message("write_block: fail, card write protected\r\n");
  203. else uart_transmit_message("read_block: CMD24 fail\r\n");
  204. temp=read_block(buffer,0x00,0x00,0x02,0x00); //Считать буфер
  205. if(temp==0x00) {
  206. uart_transmit_message("read_block: data block read succes:\r\n");
  207. for (i=0;i<512;i=i+1) //Выслать буфер по UART
  208. uart_transmit(buffer[i]);
  209. }
  210. else if (temp==0x01) uart_transmit_message("read_block: fail, no card in the slot\r\n");
  211. else uart_transmit_message("read_block: CMD17 fail\r\n");
  212. }
  213. else if (temp==0x01) uart_transmit_message("sd_card_init: fail, no card in the slot\r\n");
  214. else if (temp==0x03) uart_transmit_message("sd_card_init: CMD0 fail\r\n");
  215. else uart_transmit_message("sd_card_init: CMD1 fail\r\n");
  216.  
  217. while (1);
  218.  
  219. return 1;
  220. }

Код программы прост, название функций говорит само за себя. Вначале инициализируем UART, посредством которого будем связываться с компьютером на скорости 256кбод/с, с одним стоп битом, без проверки четности (если такая скорость покажется большой по ряду причин, то ее легко подредактировать в строке 16). Функция void uart_init(void) инициализирует UART; void uart_transmit(unsigned char х) – пересылает байт х по UART; unsigned char uart_receive(void) – принимает байт; void uart_transmit_message(char * msg) – пересылает строку, на которую ссылается msg по UART. Подключение карты к микроконтроллера определяется директивами define в начале программы. Рассмотрим функции работы c картой SD/MMC. Функции void spi_transmit(unsigned char x), unsigned char spi_receive(void) отвечают за пересылку байт по SPI; unsigned char sd_cmd(unsigned char b0, unsigned char b1, unsigned char b2, unsigned char b3, unsigned char b4, unsigned char b5) – отвечает за пересылку команды карте памяти.

b0 – индекс команды, b1-b4 – аргумент команды, b5 – контрольная сумма, функция возвращает ответ R1 от карточки. Пользовательские функции: unsigned char sd_card_init(void) служит для инициализации карты командами CMD0, CMD1, при успешном выполнении возвращает результат 0х00. Функции unsigned char read_block (char* buff, unsigned char a1, unsigned char a2, unsigned char a3, unsigned char a4) и unsigned char write_block (char* buff, unsigned char a1, unsigned char a2, unsigned char a3, unsigned char a4) служат для чтения/записи блока, на который указывает buff, по адресу a1-a4, в случае выполнения возвращают 0х00. Во всех пользовательских функция предусмотрена проверка наличия карты в слоте и режима Write Protect, который устанавливается механическим ползунком на самой карте памяти.
режим WP SD карты
При внутрисхемном программировании следует вынимать карту из слота, иначе программатор не сможет залить прошивку в микроконтроллер (сигналы WP, INS при вставленной карте садят на землю выводы нужные для внутрисхемного программирования). Выполнение приведенной выше программы приведет к тому, что целостность файловой системы (существовавшей до этого на карточке) будет нарушена, так что перед экспериментами не забудьте скопировать с карточки всю важную информацию.
Вот что я увидел в Terminal 1.9 при запуске программы:
принтскрин terminal'а при работе с SD картой
Решил перепроверить с помощью утилиты WinHex содержание первого блока карты памяти:
принтскрин winhex'а при работе с SD картой
Результаты совпадают. Запись чтение удалось. Теперь смело можно писать/читать данные на карту. Про то, как писать данные в файлы и про файловую систему FAT я напишу чуть позже.

Cледующая статья цикла: "SD/MMC карта памяти и микроконтроллер AVR (часть 2) Система FAT, Petit FatFs."
Последняя стать цикла: "SD/MMC карта памяти и микроконтроллер AVR (часть 3) Система FAT, FatFs."

Код программы в формате проекта для AVR Studio 4.
Разводка печатной платы в формате .lay для программы Sprint Layout 5

Отличная статья,

Отличная статья, Респект!
Хотел спросить, вместо LP2980-3.3 можно поставить LP2981AIM5-3.3? и возможны ли допуски с индуктивностью и в каких диапазонах, а то у нас нет 22мкГн, есть 10 и 33 и какие можно использовать?
Спасибо!

Подойдет любой регулятор

Подойдет любой регулятор напряжения, который на выходе дает 3,3 Вольта. По поводу индуктивности 33мкГн будет не критично.

SDHC 16Gb

Уважаемый автор.
Я проштудировал всю родную спецификацию, ссылку на которую Вы дали (http://avrlab.com/upload_files/SD_card_Specification_Ver3.01_Final_10051...), но так и не понял, где Вы взяли ту последовательность действий инициализации SD карты, которую указываете:
"1. Сперва, при высоком уровне на выводах CS и DI подаем 80 тактовых импульсов на вывод CLK.
2. Далее на все время работы с картой сажаем CS на землю.
3. Подаем команду CMD0, контрольная сумма для которой равнa 0x95 (контрольная сумма в нашем случае нужна только для команды CMD0, в остальных случаях она не проверяется, поэтому все время будем использовать 0х95 как контрольную сумму).
4. Далее, после байтовой паузы, карточка должна ответить 0х01, что означает, что она вошла в SPI режим и готова принимать команды.
5. Теперь подаем команды CMD1, и после паузы ожидаем от карточки ответа 0х00, которые говорит о том, что карта готова к обмену данными."

Более того, в этом документе указано, что CMD1 зарезервировано и вместо нее рекомендуется использовать ACMD41, но не сразу после CMD0, а в такой последовательности CMD0 -> CMD8 -> ACMD41.

Причина моей критики заключается в том, что задача инициализации SD карты для меня сейчас является насущной, но что-то она пока не решается ни с помощью рекомендаций из английского оригинала, ни, к сожалению, с помощью Ваших.

Коммент увидел, завтра

Коммент увидел, завтра отвечу развернуто.

Эту последовательность команд

Эту последовательность команд уважаемый автор видимо взял не из указанного родного даташита на SD-карты, а из описания использования SD/MMS карт мистера ChaN'a (elm-chan.org/docs/mmc/mmc_e.html)

Здравствуйте! Почитал Вашу

Здравствуйте!
Почитал Вашу статью и пытаюсь повторить на ATmega16L (фиксированное питание 3.3 Вольта)
Взял карточку miro-SD с адаптером, но не знаю как подключить на основе Вашей статьи.

Подскажите пожалуйста! В секции Вашей программы

  1. 4.#define DI 0
  2. 5.#define DO 1
  3. 6.#define CLK 2
  4. 7.#define CS 3
  5. 8.#define INS 4
  6. 9.#define WP 5

скажите, что именно необходимо написать вместо следующих строк,т.к. такие выводы на карточке( INS и WP) я не нашёл
  1. 8.#define INS 4
  2. 9.#define WP 5

Заранее Вам всем спасибо за ответ!

Чтобы не переделывать код,

Чтобы не переделывать код, просто подаем на эти пины 0В и работаем с карточной дальше. Можно убрать эти дефайны, сэкономить 2 пина, но придется убрать все упоминание из mmc.c и подредактитовать функцию disk_timerproc.

Нет 512 байт памяти

Очень занимательно, а если в контроллере ВСЕГО 512 байт памяти?
Сам с таким столкнулся. Возможное решение. В железо еще не закатал..

  1. #define DATA_BLOCK_SIZE 64
  2. #define MMC_BLOCK_SIZE 512
  3.  
  4. char disk[N][MMC_BLOCK_SIZE];
  5. char buff[DATA_BLOCK_SIZE];
  6.  
  7. int read_data(char* buff, int offs_data)
  8. {
  9. int i,j;
  10. int buff_idx = 0;
  11. int in_block_idx = offs_data % MMC_BLOCK_SIZE;
  12. i = offs_data / MMC_BLOCK_SIZE;
  13. for(j=0, buff_idx=0; j<MMC_BLOCK_SIZE; j++)
  14. {
  15. if( in_block_idx <= j && (in_block_idx + DATA_BLOCK_SIZE) > j )
  16. {
  17. buff[buff_idx] = disk[i][j];
  18. buff_idx++;
  19. }
  20. else
  21. ; Читаем в пустую переменную, что бы не нарушить алгоритм выборки строго 512 байт
  22. }
  23. return 0;
  24. }
  25.  
  26. // Соответственно вызов
  27. int offs_data = MMC_BLOCK_SIZE + DATA_BLOCK_SIZE*3;
  28. read_data( buff, offs_data);

Народ, конструктивная критика приветствуется.

Логично, если нет целого

Логично, если нет целого куска памяти - нужно разбить на части :)

Только не совсем понятно зачем массив disk[N][MMC_BLOCK_SIZE]. Или это только для демонстрации?

От себя добавлю, если интересует последовательно чтение/запись - то легко реализуется - SPI протокол можно стопнуть в любой момент. Т.е. считали небольшой блок данных, заморозили состояние SPI, обработали данные, снова считали блок и т.д.

Интересовал произвольный доступ

disk - это демонстрация. Пример алгоритма так сказать.
Инетересовал произвольный доступ кратный блокам DATA_BLOK_SIZE. Как я понимаю, нельзя непрочитав весь сектор, начать считывать из другого?
И еще вопрос к автору:
unsigned char a4 - в функциях write_block, read_block всегда равен 0. Так? Тоесть как бы нет смысла его передавать и следить за ним.

Угу, сектор нужно дочитывать

Угу, сектор нужно дочитывать до конца.

В данном примере a4 все время остается равной 0х00. Но размер блока в некоторых устройствах может быть например 128 байт. Т.е. насовсем я бы ее не убирал.

Глюк или косяк?

День добрый..попробовал поиграться с подключением SD к STM8...на CMD0 получаю нормальный ответ 0х01, на следущую за ней CMD1 - опять 0х01 вместо 0х00...из-за чего это может происходить?

Это происходит из-за того,

Это происходит из-за того, что карте нужно время на инициализацию. Попробуй периодически спамить ее коммандой CMD1 до того времени, как она вернет 0х00. У меня это сделано так:

  1. count=0;
  2. do{
  3. temp=sd_cmd (0x41,0x00,0x00,0x00,0x00,0x95); //CMD1
  4. spi_transmit (0xff);
  5. count=count+1;
  6. } while ( (temp!=0x00)&&(count<0xffff) ); //Ждем 0x01 ответа R1

так и делал

Собственно, как раз так и делал - ответ перманентно 0х01...сегодня попробую с другой карточкой - может эта просто глючит...

Запись в SD

Добрый день !!!
Подскажите пожалуйста, как сделать так чтобы данные записывались в продолжении имеющихся данных на карте (без указания адреса).

Нужно постоянно отслеживать

Нужно постоянно отслеживать текущий адрес блока. Т.е.

запись(блок,адрес блока);
адрес блока = адрес блока + размер блока;
запись(блок,адрес блока);
...

Я бы загнал адрес в глобальную переменную, в функции write_block увеличивал эту глобальную переменную на 512 (стандартный блок) при записи каждого блока. И соответственно избавился от переменных а1,а2,а3,а4 в функции write_block.

Если я не ошибаюсь, на

Если я не ошибаюсь, на карточку 1Gb можно записать ровно 2000 блоков по 512 байт. Да?

Это 1Мб... В 1Гб 2000000

Это 1Мб... В 1Гб 2000000 блоков по 512байт

SD/MMC карта памяти и микроконтроллер AVR

spi_transmit и spi_receive проще объединить в одну функцию (ведь аппаратный spi именно так и работает)

Можно, но мне привычней с

Можно, но мне привычней с разными функциями для приема/передачи работать.

Хорошая статья, все понятно

Хорошая статья, все понятно написано без лишних заморочек.
Есть вопрос: для повторения данной схемы подойдет любая SD карта, или есть какие-то особые требования (производитель, объем и т.д.)?

Подойдет SD карта, каких-то

Подойдет SD карта, каких-то предпочтений производителя и объема нету. С картами SDHC не тестил, но думаю что заработает.

Респектище тебе!!! Очень

Респектище тебе!!! Очень полезный мануал

Здравствуйте! у меня есть

Здравствуйте!
у меня есть вопрос по схеме
Я не нашел слота для SD карты и подсоединяю на прямую к контроллеру и не пойму выводы WP и IN5 от контроллера должны идти на линию GND?

Да. При установленной карте

Да.
При установленной карте памяти на INS 0В.
При разрешенной записи на выводе WP 0В.