Imax9
НОВОСТИ   ПУБЛИКАЦИИ   FILES   ИНФОРМАЦИЯ

STM32F407 Урок 04. Работаем с SD картой в режиме SDIO.

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

Советую в CubeMX создать новый проект, у меня при добавлении к старому, почему-то упорно неправильно показывался общий объем карты, пока не создал новый, бился несколько дней над глюком. Как всегда не забываем включить Debug mode, подключить кварцы, выставим частоту на максимум, подключим к I2C1 наш дисплей, не забываем про DMA в режим передачи и NVIC. Кто забыл - ссылка на прошлый урок в абзаце выше.

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

Не забываем про DMA на прием и передачу, настройки по умолчанию :

Прерывания, куда же без них :

И ягодка на торте - в Middleware FATFS с поддержкой SD карт, при желании, в настройках можете включить поддержку длинных имен и увеличить максимальный размер сектора до 4096 :

Еще один важный момент, определим контакт по которому FatFS будет определять что карта вставлена, на схеме я такого не нашел, поэтому определим для него PA0 подтянутый к земле - карта всегда вставлена :

Этот-же пин определим в меню Platform Settings, иначе при генерации проекта выпадет предупреждение.

Вроде все готово, увеличиваем кучу и стэк в 2 раза, пересылаем в Atollic и начнем уже программировать. Копируем библиотеку ic1306 и заголовочный файл в наш проект, советую обновить библиотеку, я добавил туда печать мелким шрифтом и возможность переворота экрана при инициализации. Прописываем следующие строки :

/* USER CODE BEGIN Includes */
#include <ic1306.h>
/* USER CODE END Includes */

В бесконечном цикле введем задержку, чтоб попусту не лопатил :

while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_Delay(500);
}
/* USER CODE END 3 */
}

До бесконечного чикла проинициализируем дисплей и очистим его и поприветствуем для начала :

/* USER CODE BEGIN 2 */
display_init (50,0x22,0);
display_clear(0,7);
display_SmallPrint(0,0,"Hello");

/* USER CODE END 2 */

После приветствия смонтируем нашу карту :

display_SmallPrint(0,0,"Hello");
FATFS SDFatFs;
char USER_Path[4];
if(f_mount(&SDFatFs,(TCHAR const*)USER_Path,1)!=FR_OK)
{display_SmallPrint(0,7,"Error mount"); }
else
{display_SmallPrint(0,7,"OK mount");
FATFS_UnLinkDriver(USER_Path);
}

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

char USER_Path[4];
FATFS* fs;
char str[32] = {0,};
FRESULT res;
DWORD fre_clust, fre_sect, tot_sect;

В случае успешного монтирования добавим вывод информации о карте:

{display_SmallPrint(0,7,"OK mount");
res = f_getfree("", &fre_clust, &fs);
tot_sect = (fs->n_fatent - 2) * fs->csize;
fre_sect= fre_clust * fs->csize;
sprintf(str, "Fclst %lu", fre_clust);
display_SmallPrint(0,0,str);
sprintf(str, "Faten %lu", fs->n_fatent);
display_SmallPrint(0,1,str);
sprintf(str, "Size %d", fs->csize);
display_SmallPrint(0,2,str);
sprintf(str,"t_sec %lu",tot_sect);
display_SmallPrint(0,3,str);
sprintf(str,"f_sec %lu",fre_sect);
display_SmallPrint(0,4,str);
sprintf(str,"%lu KB tot",fre_sect/2);
display_SmallPrint(0,5,str);
sprintf(str,"%lu KB avail",tot_sect/2);
display_SmallPrint(0,6,str);

Здесь по строкам :

  1. Fclst - количество свободных кластеров
  2. Faten - общее количество кластеров
  3. Size - число секторов в кластере
  4. t_sec - общее число секторов
  5. f_sec - число свободных секторов
  6. xxxx KB tot - объем карты
  7. xxxx KB avail - размер свободного места

Если мы подключим логический анализатор (у меня клон SL) к выведенным на гребенки пинам и выберем в Pulse View протокол sd, то можем наблюдать такую картинку :

Как видно - сначала подается команда сброса GO_IDLE_STATE , затем проверяется вольтаж SEND_IF_COND, и уже расширенной командой узнаем CardStatus, как я понимаю, мы наблюдаем определение типа карт, далее декодер sd ругается, как найду причину - дополню. Неплохое описание программы PulseView вы можете найти на странице сайта eax.me.

Запишем на карту текстовый файл с именем "1.txt" желательно больше 44 символов и без перевода строки. Добавим еще описание переменных :

DWORD fre_clust, fre_sect, tot_sect;
FIL MyFile;
uint32_t bytesread;

После вывода информации добавим следующий код :

display_SmallPrint(0,6,str);
if(f_open(&MyFile, "1.txt", FA_READ) != FR_OK)
{display_SmallPrint(0,7,"Error file open");}
else {f_lseek(&MyFile,2);
res = f_read(&MyFile, str, 21, (void *)&bytesread);
if((bytesread == 0) || (res != FR_OK))
{display_SmallPrint(0,7,"Error read");}
else display_SmallPrint(0,7,str);
HAL_Delay(5000);
res = f_read(&MyFile, str, 21, (void *)&bytesread);
if((bytesread == 0) || (res != FR_OK))
{display_SmallPrint(0,7,"Error read");}
else display_SmallPrint(0,7,str);
f_close(&MyFile);
HAL_Delay(5000);
}

В нижней строке дисплея вы увидите сначала 21 символ начиная со второго и через 5сек следующий 21 символ, как видно из кода, не обязательно делать каждый раз f_lseek , если вы последовательно читаете порциями большой файл. Подробнее изучить команды FatFS можно на сайте разработчика или на русском языке. Теперь попробуем записать файл с нашими данными, определим следующие переменные :

uint32_t bytesread;
const char wtext[] = "STM32F407 write file";
uint32_t byteswritten;

Добавим следующий код для записи файла :

HAL_Delay(5000);
}
if((res=f_open(&MyFile, "STM32wri.txt", FA_CREATE_ALWAYS | FA_WRITE)) != FR_OK)
{sprintf(str, "Error open wr %d", res);
display_SmallPrint(0,7,str);}
else
{res = f_write(&MyFile, wtext, sizeof(wtext), (void *)&byteswritten);
if((byteswritten == 0) || (res != FR_OK)) display_SmallPrint(0,7,"Error write");
else display_SmallPrint(0,7,"OK write");
f_close(&MyFile); }
HAL_Delay(5000);

Для вывода каталога карты добавим описание следующих переменных :

uint32_t byteswritten;
FILINFO fileInfo;
DIR dir;

И сам код для чтения каталога :

HAL_Delay(5000);
res = f_opendir(&dir, "/");
if (res == FR_OK)
{
for(uint8_t i=0;i<8;i++)
{
res = f_readdir(&dir, &fileInfo);
if (res==FR_OK && fileInfo.fname[0])
{if(fileInfo.fattrib&AM_DIR) {display_SmallPrint(0,i,"DIR:"); i++;}
if(strlen(fileInfo.fname)) display_SmallPrint(0,i,(uint8_t*)fileInfo.fname);
}
else break;
}
f_closedir(&dir);
}

Если у вас карта с фотика, можете выдать список фотографий изменив команду f_opendir(&dir, "/DCIM");

На сегодня все, в следующем уроке поработаем с установленной на плате spi FLASH W25Q16. Если будут пожелания - поработаем с SD картой в режиме SPI.

Адрес для контактов : imax9@narod.ru

Если вам понравились мои работы и вы желаете поддержать сайт - сделайте дотацию.

При копировании статьи – обязательна ссылка на авторство и источник. Без разрешения автора копирование запрещено.

© Максим Ильин 2020г.

Яндекс.Метрика