AVR Урок 33. SPI. Карта SD. FAT. Часть 3

 

 

 

 

Урок 33

Часть 3

 

SPI. Карта SD. FAT

 

 

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

Поэтому создадим функцию для записи блока с карты SD выше функции main(). Почему сразу записи, да потому, что читать нам ещё нечего, так как сначала надо что-то записать, чтобы потом прочитать и убедиться, что это именно то, что мы записали

 

unsigned char SD_Write_Block (char* bf, unsigned char dt1, unsigned char dt2, unsigned char dt3, unsigned char dt4)

{

}

 

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

Создадим в функции две переменных

unsigned char SD_Write_Block (char* bf, unsigned char dt1, unsigned char dt2, unsigned char dt3, unsigned char dt4)

{

  unsigned char result;

  long int cnt;

 

Теперь команда. Посмотрим техническую документацию и найдём команду для записи блока

 

Image19

 

Индекс команды у нас 24 или по-шестнадцатеричному — 0x18, первый бит, как мы знаем 0, второй всегда 1, поэтому будет 0x58.

Основным аргументом будет адрес данных. Поэтому напишем вызов функции передачи команды

 

long int cnt;

result=SD_cmd(0x58,dt1,dt2,dt3,dt4,0x95); //CMD24 даташит стр 51 и 97-98

 

Так как все параметры у нас во входе функции, то мы их пока не увидим, увидим, когда будем нашу функцию записи вызывать.

Выйдем, если что-то не то, если всё то, то вычистим мусор из регистра сдвига карты

 

result=SD_cmd(0x58,dt1,dt2,dt3,dt4,0x95); //CMD24 даташит стр 51 и 97-98

if (result!=0x00) return 6; //Выйти, если результат не 0x00

SPI_SendByte (0xFF);

 

Вообще мы будем пробовать писать данные по адресу 0x400, так как если мы вдруг будем позже пробовать 32-битную файловую систему, то в первые байти мы писать не можем, так как там служебная информация файловой системы FAT32. В 0x300 мы писать не можем также, потому что блоки у нас по 512 байт и мы просто с такого адреса писать не можем, это не адрес блока.

Передадим начало буфера

 

SPI_SendByte (0xFF);

SPI_SendByte (0xFE); //Начало буфера

 

Начало буфера — это своего рода метка, она входит в пакет передачи данных, состоящий из метки начала и собственно самих данных

 

Image20

 

Именно такая метка (0b11111110) должна быть для CMD 24, CMD17 и CMD18

 

Image21

 

Ну, и теперь непосредственно передаём данные из буфера и в конце контрольную сумму и любой байт

 

SPI_SendByte (0xFE); //Начало буфера

for (cnt=0;cnt<512;cnt++) SPI_SendByte(bf[cnt]); //Данные

SPI_SendByte (0xFF); //Котрольная сумма

SPI_SendByte (0xFF);

 

Контрольная сумма любая, поэтому по этому поводу не заморачиваемся.

Теперь примем результат команды из шины и произведём первичную проверку

 

SPI_SendByte (0xFF);

result=SPI_ReceiveByte();

if ((result&0x05)!=0x05) return 6; //Выйти, если результат не 0x05 (Даташит стр 111)

 

Аналогично, как и в предыдущей функции, создадим цикл и дождёмся свободного состояния карты, и, если всё нормально, то возвращаем 0

 

  if ((result&0x05)!=0x05) return 6; //Выйти, если результат не 0x05 (Даташит стр 111)

  cnt=0;

  do { //Ждем окончания состояния BUSY

    result=SPI_ReceiveByte();

    cnt++;

  } while ( (result!=0xFF)&&(cnt<0xFFFF) );

  if (cnt>=0xFFFF) return 6;

  return 0;

}

 

Вызовем нашу функцию в main() и отобразим результат на дисплее в следующей строке

 

str_lcd(str);

result=SD_Write_Block(buffer,0x00,0x00,0x04,0x00);//Запишем блок из буфера

sprintf(str,"%d",result);

setpos(0,1);

str_lcd(str);

 

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

Далше идёт у нас адрес, просто разбитый по 8 бит. А полностью получается 0x00000400, то есть именно тот адрес в который мы и будем пытаться писать блок.

Проверим сначала в протеусе

 

Image22

 

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

 

Image23

 

Мы видим, что вся наша информация записана в правильное место.

Теперь поиграем с чтением. Создадим функцию опять же над функцией main() и сразу напишем в неё локальные переменные

 

unsigned char SD_Read_Block (char* bf, unsigned char dt1, unsigned char dt2, unsigned char dt3, unsigned char dt4)

{

  unsigned char result;

  long int cnt;

}

 

Дальше всё скопируем с предыдущей функции записи и будем потихоньку вносить изменения

Команда будет у нас уже CMD17

 

Image24

 

 

Соответственно, CMD17 у нас превращается в 0x51, остальные параметры аналогичные

 

long int cnt;

result=SD_cmd (0x51,dt1,dt2,dt3,dt4,0x95); //CMD17 даташит стр 50 и 96

if (result!=0x00) return 5; //Выйти, если результат не 0x00

 

Затем также передача 0xFF с целью выждать время и заодно прочистить регистр SPI у карты

 

if (result!=0x00) return 5; //Выйти, если результат не 0x00

SPI_SendByte (0xFF);

 

Посмотрим, как читаются данные с карты

 

Image25

 

Мы видим, что никаких меток у нас нет, поэтому сразу принимаем ответ и проводим первичную его проверк

 

SPI_SendByte (0xFF);

cnt=0;

do{ //Ждем начала блока

  result=SPI_ReceiveByte();

  cnt++;

} while ( (result!=0xFE)&&(cnt<0xFFFF) );

if (cnt>=0xFFFF) return 5;

 

А вот теперь уже читаем данные

 

if (cnt>=0xFFFF) return 5;

for (cnt=0;cnt<512;cnt++) bf[cnt]=SPI_ReceiveByte(); //получаем байты блока из шины в буфер

 

Затем мы обязаны принять контрольную сумму, поэтому примем её символически, никак не проверяя результат, даже не видя его, и возвращаем 0

 

  for (cnt=0;cnt<512;cnt++) bf[cnt]=SPI_ReceiveByte(); //получаем байты блока из шины в буфер

  SPI_ReceiveByte(); //Получаем контрольную сумму

  SPI_ReceiveByte();

  return 0;

}

 

Теперь вызовем нашу функцию в main() и отобразим результат в третьей строке дисплея

 

str_lcd(str);

result=SD_Read_Block(buffer,0x00,0x00,0x04,0x00); //Считаем блок в буфер

sprintf(str,"%d",result);

setpos(0,2);

str_lcd(str);

 

Попробуем собрать код и запустить его в протеусе

 

Image26

 

Всё у нас считалось.

Теперь проверим в живой схеме, прошив перед этим контроллер

 

Image27

 

Только мы не видим, что именно у нас считалось. Если мы отобразим наш буфер, в который мы считали, то толку от этого не будет, так как там уже есть этот текст. Поэтому мы должны назначить буфер для чтения, так как наш буфер с текстом нам уже не подойдёт, ибо в нём уже есть текст и мы просто не проверим работу функции. Поэтому создадим ещё один буфер, а предыдущий закомментируем, так как у нас не хватит на два буфера оперативной памяти и компилятор даст ошибку и не будет собирать код

 

//char buffer[512] ="The…"; //Буфер данных для записи/чтения

char buffer2[512] ={}; //Буфер данных для чтения

 

И также закомментируем код вызова и отображения результата функции записи в main(), а также исправим имя буфера в вызове функции чтения, затем добавим задержку, раскомментируем функцию вывода буфера на экран дисплея, исправив там также имя буфера

 

// result=SD_Write_Block(buffer,0x00,0x00,0x04,0x00);//Запишем блок из буфера

// sprintf(str,"%d",result);

// setpos(0,1);

// str_lcd(str);

result=SD_Read_Block(buffer2,0x00,0x00,0x04,0x00); //Считаем блок в буфер

sprintf(str,"%d",result);

setpos(0,2);

str_lcd(str);

_delay_ms(1000);

for (i=0;i<=22;i++) {str80_lcd(buffer2+i*20);_delay_ms(1000);}

while(1)

 

Сначала соберём код и проверим в протеусе

 

Image28

 

Затем прошьём контроллер и посмотрим результат вживую

 

Image29

 

Как видим, всё у нас работает.

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

 

Предыдущая часть Программирование МК AVR Следующая часть

 

Исходный код

 

Техническая документация на Secure Digital

 

Программатор, модуль SD и дисплей можно приобрести здесь:

Программатор (продавец надёжный) USBASP USBISP 2.0

Модуль карты SD SPI

Дисплей LCD 20×4

 

 

Смотреть ВИДЕОУРОК (нажмите на картинку)

 

AVR SPI. Карта SD. FAT

2 комментария на “AVR Урок 33. SPI. Карта SD. FAT. Часть 3
  1. михаил:

    Спасибо огромное за Ваши статьи. Неделю пытался проинициализировать SD карту аппаратным SPI, а тут в течение 3х часов (с перерывами) и все заработало! Удачи!

  2. михаил:

    Уважаемый admin! Нет ли у Вас в планах разжевать для широких масс тему USB MS class именно с mega8 + SD карта? В разделе stm32 есть, а здесь пока нет.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*