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



 

Урок 33

Часть 1

 

SPI. Карта SD. FAT

 

Сегодня мы продолжим нашу любимую тему по интерфейсу SPI. Закончили мы с данной шиной уроком по подключению друг к другу контроллеров Atmega8a и ATTtiny2313. А сегодня мы по данному интерфейсу попробуем подключить к микроконтроллеру по данной шине карту памяти SD (Secure Digital).

Данная карта может подключаться также по интерфейсу SDIO, но так как такой интерфейс не поддерживается аппаратно нашим контроллером, то в рамках данного занятия мы его касаться не будем. Нам интересен именно тип подключения по шине SPI, так как у нас уже есть неплохие накопленные знания по данной теме, а также аппаратная поддержка в контроллере, который мы программируем.

Тем не менее мы посмотрим распиновку ножек карты по обоим типам

 

Image00

 

Ну, так как нас интересует второй тип, с ним и будем разбираться.

А разбираться тут особо не в чем. Все эти аббревиатуры нам известны. Здесь все стандартные ножки интерфейса SPI и ничего тут лишнего нет.

Теперь вообще про карту. Данная карта нам позволяет хранить данные, тип памяти у неё FLASH, который по сравнению с памятью типа EEPROM также является энергонезависимым, то есть при отключении питания данные никуда не пропадают, а остаются храниться. Также данная память имеет отличия, мы с ними познакомимся в процессе программирования. Одно из главных отличий то, что мы уже как в память EEPROM в данную память не можем записать один байт. Теоретически то конечно можем, но только запишутся туда либо только единички из нашего байта либо только нули в зависимости от типа FLASH — NOR или NAND. То есть прежде чем писать байт, нужно его стереть, а в силу организации данной памяти, стирать мы можем только блоками, вот и писать следовательно также только блоками. Но зато есть величайшее отличие от EEPROM — это цена. Она в разы дешевле, даже порой на порядки за одну хранящуюся единицу информации (за мегабайт, за гигабайт). Поэтому у памяти FLASH как правило всегда гораздо больший объём информации.

Существуют 4 типа SD, но это мы изучим немного позднее.

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

 

Image01

 

Здесь всё просто. На самом деле не совсем так. Нужны ещё резисторы

 

Image02

 

Данные резисторы нужны для того, чтобы обеспечить соответствующие уровни, так как карта питается от 3,3 вольт. Вообще по технической документации от 2,7 до 3,6 вольт.

Также в протеусе не указано, а на самом деле мы будем питать нашу карту от отдельного питания, поставив микросхему, преобразующую 5 вольт в 3,3 вольт.

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

Также у нас подключен дисплей, как и на прошлом занятии по расширению функционала библиотеки дисплея.

Вот так у нас всё выглядит в практической схеме

 

Image09

 

 

Вот так вот выглядит модуль с держателем

 

Image10

 

Найти такой модуль можно везде, стоит он копейки. Тот модуль, который конектится по SDIO, стоит дороже. Мы видим также, что на модуле уже установлена микросхема для понижения напряжения до 3,3 вольта. А подключаем питание мы только на контакт 5 вольт, а на 3,3 не подключаем ничего

 

Image12

 

Также на модуле установлены все делители для уровней, то есть данный модуль рассчитан именно на подключение к 5-вольтовым устройствам.

А флеш-карту для тестов я откопал на 32 мегабайта, именно мегабайта а не гигабайта

 

Image11

 

 

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

Код был весь взят также с прошлого занятия вместе с библиотекой дисплея, так как функцию, которую мы создали на прошлом уроке, мы будем очень активно использовать, только был конечно создан проект новый и назват соответственно MYSD_SPI.

Удалим ненужные строки, в main() у нас останется только во это

 

int main(void)

{

  unsigned int i;

  port_ini();

  LCD_ini(); //инициализируем дисплей

  clearlcd();//очистим дисплей

  setpos(0,0);

  str_lcd(«String 1»);

  setpos(2,1);

  str_lcd(«String 2»);

  setpos(4,2);

  str_lcd(«String 3»);

  setpos(6,3);

  str_lcd(«String 4»);

  _delay_ms(2000);

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

  while(1)

  {

  }

}

 

 

Так как мы посимвольно не будем выводить текст, то можно будет в переменной обойтись типом char

 

unsigned char i;

 

Теперь ещё один нюанс.

Чтобы нам работать с SD-картой в протеусе, нам мало добавить сам держатель с картой, необходимо также в его свойствах прикрепить файл образа флеш-карты.

Создать его не сложно. Одним из способов является создание с помощью программы WinImage.

Мы в ней стандартно создаём новый файл с помощью пункта меню File — > New. Выбираем в диалоге самый последний пункт и жмём «OK»

 

Image03

 

Для теста в протеусе нам вполне хватит размера 4 мегабайта, поэтому поменяем в следующем диалоге поле с номером секторов, а также выберем формат FAT12/16, потому что с 32-битной файловой системой немного другая специфика работы, и также нажмём «OK»

 

Image07

 

Вообще мы конечно можем оставить и FAT32, так как мы с файловой системой пока не работает, но в дальнейших частях занятия будет работа с файловой системой и мы будем именно работать с 12/16.

Затем мы сохраняем наш созданный файл с помощью пункта меню File -> Save As. И сохраняем мы его в ту папку, где у нас находится сохранённый проект протеуса. Назовём файл и нажмём «Сохранить»

 

Image05

 

Также затем нужно будет убедиться, что данный файл у нас получился не с аттрибутом «только для чтения» и после этого мы уже сможем его подключить  в протеусе. Надо будет вручную вписать имя файла, так как протеус требует какой-то свой формат и наш файл будет просто не виден

 

Image08

 

Путь нам никакой не нужен, так как файл у нас находится в папке с проектом. Жмём «ОК».

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

Добавим макроподстановки для ножек порта

 

#include «main.h»

#define MOSI 3

#define MISO 4

#define SCK 5

#define SS 2

 

Добавим код для инициализации ножек в функцию инициализации портов

 

void port_ini(void)

{

  PORTD=0x00;

  DDRD=0xFF;

  PORTB|=(1<<SS)|(1<<MISO)|(1<<MOSI);

  DDRB|=(1<<SS)|(1<<MOSI)|(1<<SCK);

}

 

Мы оставляем на вход ножку MISO, так как по умолчанию все биты в регистре равны нулю, и мы его просто не трогает. Также мы включаем сразу высокий уровень в MOSI и SS, а к MISO подтягиваем резистор.

Напишем функцию передачи байта по шине SPI

 

void SPI_SendByte (unsigned char byte)

{

}

 

Добавим переменную для цикла и сам цикл

 

void SPI_SendByte (unsigned char byte)

{

  unsigned char i;

  for (i=0;i<8;i++) //движемся по битам байта

  {

  }

}

 

Я думаю, понятно почем мы считаем до 8, так как битов мы передаём именно 8.

Ну и начнём их передавать потихоньку.

Проверим сначала самый левый бит, выделив его из всего байта маскированием, и, если он у нас равен 1, то выставим 1 и на шине MOSI, а если 0 — то не трогаем шину

 

for (i=0;i<8;i++) //движемся по битам байта

{

  if ((byte&0x80)==0x00)//проверяем левый бит

  PORTB&=~(1<<MOSI); //если 0, то выставляем 0 на шине

  else PORTB|=(1<<MOSI); //если 1, то выставляем 1

 

Затем мы сдвинем наш байт влево на 1, чтобы старшим (левым) битом у нас стал следующий бит

 

else PORTB|=(1<<MOSI); //если 1, то выставляем 1

byte<<=1; //сдвигаем влево, в сторону старшего для проверки следующего бита

 

Дрыгнем ножкой SCK, чтобы сформировать импульс тактирования

 

    byte<<=1; //сдвигаем влево, в сторону старшего для проверки следующего бита

    PORTB|=(1<<SCK); //фронт на ножке SCK

    asm(«nop»); //1 такт подождём

    PORTB&=~(1<<SCK); //спад на ножке SCK

  }

}

 

Я думаю, для одной части урока мы уже сделали достаточно, а код для приёма байта по шине мы будем писать уже в следующей части урока.

 

 

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

 

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

 

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

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

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

Дисплей LCD 20×4

 

 

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

 

AVR SPI. Карта SD. FAT

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

    Вы писали: «Также на модуле установлены все делители для уровней, то есть данный модуль рассчитан именно на подключение к 5-вольтовым устройствам»

    На моём модуле эти резисторы являются просто подтяжкой на 3.3В

  2. Игорь:

    Здравствуйте. Правильно ли я понимаю, что в результате конкретно этой последовательности:
    PORTB|=(1<<SS)|(1<<MISO)|(1<<MOSI);
    DDRB|=(1<<SS)|(1<<MOSI)|(1<<SCK);
    мы сначала подтягиваем резисторы трех ног(SS, MISO, MOSI), а потом меняя направление работы портов(SS, MOSI, SCK) на "выход" оставляем только MISO входом с подтянутым внутренним резистором?
    Можно было бы сначала указать направление "выход" трем портам SS, MOSI, SCK, а потом только для MISO дать команду для подтягивания резистором, так как он(как и все порты) после сброса МК по умолчанию в состоянии "вход"?

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

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

*