Восстановление данных с монолитных SD и MicroSD карт. Распиновка Secure Digital (SD) card Microsd распиновка контактов
Всем доброго дня! Сегодня мы поговорим о подключении карты памяти SD к микроконтроллеру STM32.
Казалось бы, памяти полно у контроллеров STM32F10x, зачем там еще дополнительная, но это впечатление обманчиво) Вот, например, надо нам на дисплей вывести пару-тройку разных изображений – формат 320*240 – то есть 76800 пикселей, каждому из которых соответствует целых 2 байта. Вот и получаем около 150 кБ на одну картинку. А это немало по меркам микроконтроллера, и не факт, что две разные картинки удастся запихать в его Flash память. Или надо нам хранить большие объемы информации, данные с какого-нибудь датчика, к примеру. Да еще так, чтобы эти данные были доступны и после отключения питания. Вот тут то нам и пригодится внешняя память. И отличным решением будет SD карта памяти или MMC. К слову в этой статье мы будем проводить опыты над картой micro SD .
Для начала пара слов о самой карте памяти, точнее о ее распиновке. Выглядит все это дело следующим образом:
Итак, что тут у нас? Ну сразу видно, что выводов у нее целых восемь штук. Назначение выводов следующее (слева направо):
Колонка SPI Mode нам намекает на то, что взаимодействует с микроконтроллером при помощи интерфейса SPI. НО! Мы пойдем по другому пути 😉 Все дело в том, что STM32 имеют на своем борту готовый периферийный модуль для работы именно с картами памяти, и называется он SDIO.
Вообще взаимодействие с картами памяти заключается в передаче им определенных команд. Некоторые команды требует наличия аргумента, некоторые нет. Команды можно найти в официальной документации на конкретную карту. Так вот встроенный модуль SDIO дает возможность значительно упростить процесс передачи команд, да и вообще процесс работы с внешними картами памяти. Например, вот регистр SDIO_CMD – туда мы просто напросто записываем код команды, которую хотим передать карте. Или вот статусный регистр SDIO_STA – там целых 24 флага на каждый чих, то есть для большого количества событий.
Кстати STM радует еще и добротной документацией на все это дело. Вот, к примеру, подробное описание инициализации для карты памяти SD (аналогично все описано для других типов карт):
Ну, собственно, пора перейти к практическому примерчику. Поковыряем-ка Standard Peripheral Library.
В файле stm32f10x_sdio.h по традиции находим структуры для всевозможной настройки – то есть для выбора источника тактового сигнала, частоты контроллера SDIO, настройки количества передаваемых байт. Там все так щедро откомментировано, что даже не хочется отдельно это повторять)) Просто смотрите:
typedef struct { uint32_t SDIO_ClockEdge; /* Specifies the clock transition on which the bit capture is made. This parameter can be a value of @ref SDIO_Clock_Edge */ uint32_t SDIO_ClockBypass; /* Specifies whether the SDIO Clock divider bypass is enabled or disabled. This parameter can be a value of @ref SDIO_Clock_Bypass */ uint32_t SDIO_ClockPowerSave; /* Specifies whether SDIO Clock output is enabled or disabled when the bus is idle. This parameter can be a value of @ref SDIO_Clock_Power_Save */ uint32_t SDIO_BusWide; /* Specifies the SDIO bus width. This parameter can be a value of @ref SDIO_Bus_Wide */ uint32_t SDIO_HardwareFlowControl; /* Specifies whether the SDIO hardware flow control is enabled or disabled. This parameter can be a value of @ref SDIO_Hardware_Flow_Control */ uint8_t SDIO_ClockDiv; /* Specifies the clock frequency of the SDIO controller. This parameter can be a value between 0x00 and 0xFF. */ } SDIO_InitTypeDef; typedef struct { uint32_t SDIO_Argument; /* Specifies the SDIO command argument which is sent to a card as part of a command message. If a command contains an argument, it must be loaded into this register before writing the command to the command register */ uint32_t SDIO_CmdIndex; /* Specifies the SDIO command index. It must be lower than 0x40. */ uint32_t SDIO_Response; /* Specifies the SDIO response type. This parameter can be a value of @ref SDIO_Response_Type */ uint32_t SDIO_Wait; /* Specifies whether SDIO wait-for-interrupt request is enabled or disabled. This parameter can be a value of @ref SDIO_Wait_Interrupt_State */ uint32_t SDIO_CPSM; /* Specifies whether SDIO Command path state machine (CPSM) is enabled or disabled. This parameter can be a value of @ref SDIO_CPSM_State */ } SDIO_CmdInitTypeDef; typedef struct { uint32_t SDIO_DataTimeOut; /* Specifies the data timeout period in card bus clock periods. */ uint32_t SDIO_DataLength; /* Specifies the number of data bytes to be transferred. */ uint32_t SDIO_DataBlockSize; /* Specifies the data block size for block transfer. This parameter can be a value of @ref SDIO_Data_Block_Size */ uint32_t SDIO_TransferDir; /* Specifies the data transfer direction, whether the transfer is a read or write. This parameter can be a value of @ref SDIO_Transfer_Direction */ uint32_t SDIO_TransferMode; /* Specifies whether data transfer is in stream or block mode. This parameter can be a value of @ref SDIO_Transfer_Type */ uint32_t SDIO_DPSM; /* Specifies whether SDIO Data path state machine (DPSM) is enabled or disabled. This parameter can be a value of @ref SDIO_DPSM_State */ } SDIO_DataInitTypeDef; |
Отметим как в SPL реализована передача команд карте памяти. Для этих целей отведена отдельная структура SDIO_CmdInitTypeDef. В поле SDIO_CmdIndex вводим код команды, в поле SDIO_Argument – аргумент команды, также заполняем остальные поля. Осталось как то эти данные запихать в карту micro SD 😉 А для этого нам приготовили функцию:
SDIO_SendCommand (SDIO_CmdInitTypeDef *SDIO_CmdInitStruct)
В качестве аргумента передаем ей как раз таки созданную нами структуру. Для записи данных есть функция – SDIO_WriteData(uint32_t Data) . После вызова этой функции данные окажутся в специально предназначенном для этого регистре – SDIO_FIFO.
Вот так вот осуществляется работа с модулем SDIO в STM32F10x)
Теперь перейдем к практике наконец-то. Я снова буду работать с платой Mini STM32, поскольку добрые китайцы озадачились установкой на нее слота для карты памяти micro SD. Вот схема подключения разъема для карты к микроконтроллеру:
Для написания программы воспользуемся готовым примером для Keil’а – стащим оттуда два файла, в которых реализовано что-то вроде драйвера для работы с картами – это файлы sdcard.c и sdcard.h. Создаем новый проект, цепляем туда эти файлы, а кроме того, естественно, файлы CMSIS и SPL. Вот готовый проект, в который все уже добавлено – остается только написать код функции main())
В файле sdcard.c реализованы всевозможные функции для работы с картой памяти, нам теперь остается их только использовать 😉 Пишем код! Для примера запишем на micro SD 512 байт тестовых данных, а затем попробуем их считать:
// Цепляем нужные файлы #include "stm32f10x.h" #include "sdcard.h" /*******************************************************************/ // Массивы входных и выходных данных и переменная для хранения данных // о нашей карте uint8_t writeBuffer[ 512 ] ; uint8_t readBuffer[ 512 ] ; SD_CardInfo SDCardInfo; /*******************************************************************/ int main() { // Тестовые данные для записи for (uint16_t i = 0 ; i < 512 ; i++ ) { writeBuffer[ i] = i % 256 ; readBuffer[ i] = 0 ; } // Иницилизация карты SD_Init() ; // Получаем информацию о карте SD_GetCardInfo(& SDCardInfo) ; // Выбор карты и настройка режима работы SD_SelectDeselect((uint32_t ) (SDCardInfo.RCA << 16 ) ) ; SD_SetDeviceMode(SD_POLLING_MODE) ; // И вот наконец то запись и чтение SD_WriteBlock(0x00 , writeBuffer, 512 ) ; SD_ReadBlock(0x00 , readBuffer, 512 ) ; while (1 ) { } } /*******************************************************************/ |
Обратите внимание, что SD карта поддерживает запись блоками по 512 байт.
Если мы запустим программу под отладчиком, то увидим, что считанные данные соответствуют записанным =) Так что эксперимент можем считать удавшимся. На этом на сегодня заканчиваем, до скорых встреч!
Собрать адаптер Memory Stick своими руками не составляет особого труда при знании назначения функциональных выводов той или иной карты памяти. Обычно зовут распиновкой карты памяти или, например, микросхемы, чипа и т.п. Вообще технология проста. Вырезается макет карты памяти MMC (MultiMedia Card) из текстолита. На макете вырезаются 7 дорожек (MMC имеет 7 выводов). Затем, в соответствии с приведенной на рисунке ниже распиновкой, дорожки припаиваются к выводам карты памяти SD (имеет 9 выводов, из которых 2 не используются), microSD (имеет 8 выводов, из которых тоже не используются 2, но обратите внимание, что у карты памяти microSD нет вывода Vcc) или microM2 (распиновка microM2 в смежной теме Адаптер Memory Stick Micro M2). Вот и всё. Адаптер Memory Stick готов.
P.S. У нас в наличии имеются карты памяти MMC на 1 и 2 Гб. Стоимость, соответственно, 285 и 360 руб. Доставка включена в указанную цену.
Также можно дешево купить следующие типоразмеры карт памяти:
- Memory Stick и Memory Stick M2;
- Secure Digital (SD);
- Mini SD;
- Micro SD (TF);
- Compact Flash;
- XD;
- USB Flash Drives различных исполнений и емкости.
Например, такие:
да кстати я неочень селен в етих написях. немогби ты на том ресунке провисти дорожки от MicroCD До MMC буду очень признателен.
Вот так будет выглядеть адаптер miсroSD to MMC:
В устройствах на микроконтроллерах для хранения больших объемов данных используется внешняя память. Если требуется хранить единицы мегабайт, то подойдут микросхемы последовательной флэш памяти. Однако для больших объемов (десятки -сотни мегабайт) обычно применяются какие-нибудь карты памяти. В настоящий момент наибольшее распространение получили SD и microSD карты, о них я и хотел бы поговорить в серии материалов. В этой статье речь пойдет о подключении SD карт к микроконтроллеру, а в следующих мы будет разбираться как читать или записывать на них данные.
Распиновка SD и microSD карт
SD карты могут работать в двух режимах - SD и SPI . Назначение выводов карт и схема подключения зависит от используемого режима. У 8-и разрядных микроконтроллеров AVR нет аппаратной поддержки SD режима, поэтому карты с ними обычно используются в режиме SPI. В 32-х разрядных микроконтроллерах на ядре ARM, например AT91SAM3, интерфейс для работы с картами в SD режиме есть, поэтому там можно использовать любой режим работы.
Назначение контактов SD карты в SD режиме
Назначение контактов SD карты в SPI режиме
Назначение контактов microSD карты в SD режиме
Назначение контактов microSD карты в SPI режиме
Подключение SD и microSD карт к микроконтроллеру в SPI режиме
Напряжение питания SD карт составляет 2.7 - 3.3 В. Если используемый микроконтроллер запитывается таким же напряжением, то SD можно подключить к микроконтроллеру напрямую. Расово верная схема, составленная путем изучения спецификаций на SD карты и схем различных отладочных плат, показана на рисунке ниже. По такой схеме подключены карты на отладочных платах фирм Olimex и Atmel .
На схеме обозначены именно выводы SD карты, а не разъема.
L1 - феррит или дроссель, рассчитанный на ток >100 мА. Некоторые его ставят, некоторые обходятся без него. А вот чем действительно не стоит пренебрегать, так это полярным конденсатором C2. Потому что при подключении карты происходит бросок тока, напряжение питания "просаживается" и может происходить сброс микроконтроллера.
По поводу подтягивающих резисторов есть некоторая неоднозначность. Поскольку SD карты выпускаются несколькими производителями, на них существует несколько спецификаций. В одних документах четко указана необходимость подтягивающих резисторов (даже для неиспользуемых линий - 8, 9), в других документах этих указаний нет (или я не нашел).
Упрощенный вариант схемы (без подтягивающих резисторов) показан на рисунке ниже. Эта схема проверена на практике и используется в платах фирмы Microelectronika. Также она используется во многих любительских проектах, которые можно найти в сети.
Здесь сигнальные линии SD карты удерживаются в высоком состоянии микроконтроллером, а неиспользуемые линии (8, 9) никуда не подключены. По идее они должны быть подтянуты внутри SD карты. Далее я буду отталкиваться от этой схемы.
Если микроконтроллер запитывается напряжением отличным от напряжения питания SD карты, например 5 В, то нужно согласовать логические уровни . На схеме ниже показан пример согласования уровней карты и микроконтроллера с помощью делителей напряжения. Принцип согласования уровней простой - нужно из 5-и вольт получить 3.0 - 3.2 В.
Линия MISO - DO не содержит делитель напряжения, так как данные по ней передаются от SD карты к микроконтроллеру, но для защиты от дурака можно добавить аналогичный делитель напряжения и туда, на функционировании схемы это не скажется.
Если использовать для согласования уровней буферную микросхему, например CD4050 или 74AHC125, этих недостатков можно избежать. Ниже приведена схема, в которой согласование уровней выполняется с помощью микросхемы 4050. Это микросхема представляет собой 6 неинвертирующих буферов. Неиспользуемые буферы микросхемы "заглушены".
Подключение microSD карт аналогичное, только у них немного отличается нумерация контактов. Приведу только одну схему.
На схемах я рассматривал подключение SD карт к микроконтроллеру напрямую - без разъемов. На практике, конечно, без них не обойтись. Существует несколько типов разъемов и они друг от друга немного отличаются. Как правило, выводы разъемов повторяют выводы SD карты и также содержать несколько дополнительных - два вывода для обнаружения карты в разъеме и два вывода для определения блокировки записи. Электрически эти выводы с SD картой никак не связаны и их можно не подключать. Однако, если они нужны, их можно подключить как обычную тактовую кнопку - один вывод на землю, другой через резистор к плюсу питания. Или вместо внешнего резистора использовать подтягивающий резистор микроконтроллера.
Подключение SD и microSD карт к микроконтроллеру в SD режиме
Ну и для полноты картины приведу схему подключения SD карты в ее родном режиме. Он позволяет производить обмен данными на большей скорости, чем SPI режим. Однако аппаратный интерфейс для работы с картой в SD режиме есть не у всех микроконтроллеров. Например у Atmel`овских ARM микроконтроллеров SAM3/SAM4 он есть.
Шина данных DAT может использоваться в 1 битном или 4-х битном режимах.
Продолжение следует...
Мы выводили картинку на дисплей с sd карточки, но в ней были упущены некоторые моменты, первый - подключение самой карточки, второй - была рассмотрена лишь часть функций библиотеки Petit FatFs , давайте остановимся на этих моментах подробнее.
Общение с карточкой возможно по одному из двух интерфейсов, SPI
или SD
.
Надо сказать, что SD интерфейс может работать в однобитном и четырёхбитном режимах.
Схема подключения карточки по SPI стандартная и выглядит следующим образом, не используемые выводы карточки нужно с помощью резистора 10К подтянуть к питанию.
Но в любительских конструкциях зачастую пренебрегают подтягивающими резисторами, упрощая схему подключения.
Надо отметить, что при подключении по SPI карточка очень требовательна к напряжению питания и небольшая просадка питающего напряжения приводит к неработоспособности карточки, это проверено на личном опыте, по поводу SD интерфейса сказать нечего, ещё не пробовал. Это всё писал к тому, что по питанию обязательно ставить конденсаторы . Что касается дросселя, он должен быть рассчитан на ток до 100мА, но ставить его необязательно.
На схемах, изображённых выше видно, что для работы карточке необходимо 3.3 вольта, соответственно, в линиях передачи данных напряжение не должно выходить за диапазон 0 – 3.3 вольт и тут возникает вопрос, что делать если МК питается от 5 вольт?
Ответ прост, надо согласовать линии передачи данных, а сделать это можно с помощью обычного резистивного делителя.
На схеме видно, что линию MISO согласовывать не надо так, как по этой линии данные передаются от карточки к МК .
На самом деле, мало кто подключает карточку напрямую к МК, гораздо удобнее подключить к МК разъём для карточки или купить шилд с разъемом и всей необходимой обвязкой.
С подключением разобрались, давайте теперь рассмотрим как пользоваться библиотекой Petit FatFs , которая предназначена для 8-битных микроконтроллеров с малым размером памяти.
Библиотека состоит из 5 файлов:
integer.h
- заголовочный файл в котором описаны основные типы данных.
diskio.h - заголовочный файл в котором объявлены прототипы низкоуровневых функций для работы с диском и статусные коды, которые они возвращают.
diskio.c - в этом файле должны быть реализованы низкоуровневые функции, изначально там "заглушки".
pffсonf.h - конфигурационный файл.
pff.h - заголовочный файл в котором объявлены прототипы функций взаимодействия с файловой системой диска.
pff.c - файл содержит реализации функций для взаимодействия с файловой системой диска.
Видно, что для того чтобы библиотека заработала необходимо реализовать низкоуровневые функции. Но если речь идет о AVR или PIC, для них сайте можно скачать пример работы с библиотекой, в котором есть файл mmc , в нем уже реализованы низкоуровневые функции. Также необходимо задать конфигурацию библиотеки в файле pff.h и написать функции необходимые для работы SPI.
Функции Petit FatFs.
FRESULT pf_mount (FATFS*) - функция монтирует/демонтирует диск. Эту функцию необходимо вызывать до начала работы с диском, если вызвать функцию с нулевым указателем диск демонтируется. Функция может быть вызвана в любой момент времени.
Параметры
FATFS* fs
- указатель на объект типа FATFS, описание этой структуры можно посмотреть в файле pff.h. Нам надо всего лишь объявить переменную такого типа.
Возвращаемые значения:
FR_OK (0)
FR_NOT_READY
- устройство не может быть инициализировано
FR_DISK_ERR
- возникла ошибка во время чтения с диска
FR_NO_FILESYSTEM
- на диске нет правильного раздела FAT
FATFS fs;//объявляем объект типа FATFS //монтируем диск if (pf_mount(&fs) == FR_OK) { //диск смонтирован, работаем с ним //демонтируем диск pf_mount(NULL); } else { //не удалось смонтировать диск }
FRESULT pf_open (const char* path) - функция открывает существующий файл. После того как файл открыт с ним можно работать, то есть читать из него и записывать в него. С открытым файлом можно работать до тех пор, пока не будет открыт другой файл. Функция может быть вызвана в любой момент времени.
Параметры
const char* path
- указатель на строку, указывающую путь к файлу. Путь надо указывать полностью относительно корневой директории, разделяя директории слэшем.
Возвращаемые значения:
FR_OK (0)
- возвращается в случае успешного выполнения функции
FR_NO_FILE
- файл не найден
FR_DISK_ERR
- ошибка диска
FR_NOT_ENABLED
- диск не был смонтирован
FATFS fs;//объявляем объект типа FATFS //монтируем диск if (pf_mount(&fs) == FR_OK) { //открываем файл лежащий в корневой директории if(pf_open("hello.txt") == FR_OK) { //делаем что-то } //открываем файл лежащий в папке new if(pf_open("new/hello.txt") == FR_OK) { //делаем что-то } //демонтируем диск pf_mount(NULL); } else { //не удалось смонтировать диск }
FRESULT pf_read(void* buff, WORD btr, WORD* br)
- функция читает указанное количество байт из файла и сохраняет их в буфер. Если количество прочитанных байт меньше чем указано, значит был достигнут конец файла.
#define _USE_READ 1
Параметры:
void* buff
- указатель на буфер, в котором сохраняются прочитанные данные
WORD btr
- количество байт, которые нужно прочитать
WORD* br
- указатель на переменную, в которой хранится количество прочитанных байт.
Возвращаемые значения:
FR_OK (0)
- возвращается в случае успешного выполнения функции
FR_DISK_ERR
- ошибка диска
FR_NOT_OPENED
- файл не был открыт
FR_NOT_ENABLED
- диск не был смонтирован
FATFS fs;//объявляем объект типа FATFS BYTE buff;//буфер для чтения файла WORD br; //счетчик прочитанных байт //монтируем диск if (pf_mount(&fs) == FR_OK) { //открываем файл лежащий в корневой директории if(pf_open("hello.txt") == FR_OK) { //читаем из него 10 байт pf_read(buff, 10, &br); if(br != 10) { //если br не равно 10 //значит мы достигли конца файла } } }
FRESULT pf_write(const void* buff, WORD btw, WORD* bw)
- функция позволяет записывать данные в открытый файл. Для того чтобы функция работала в файле pffconf.h надо записать
#define _USE_WRITE 1
Параметры:
void* buff
- указатель на буфер, который хотим записать, нулевое значение финализирует запись
WORD btw
- количество байт, которые хотим записать
WORD* bw
- указатель на переменную, хранящий количество байт, которые удалось записать. Анализируя, эту переменную можно узнать был ли достигнут конец файла.
Возвращаемые значения:
FR_OK (0)
- возвращается в случае успешного выполнения функции
FR_DISK_ERR
- ошибка диска
FR_NOT_OPENED
- файл не был открыт
FR_NOT_ENABLED
- диск не был смонтирован
Из-за того, что библиотека рассчитана на микроконтроллеры с малым объемом памяти, эта функция имеет ряд ограничений:
- нельзя создавать новые файлы, а записывать можно только в существующие
- нельзя увеличивать размер файла
- нельзя обновить временную метку
- операцию записи можно начать/остановить только на границе сектора
- файловый атрибут "только для чтения" не может запретить запись
Для того чтобы понять предпоследний пункт, надо знать, что память карточки разбита на блоки(сектора) по 512 байт и запись можно начать только с начала сектора . Таким образом если мы хотим записать 1000 байт, то первый сектор запишется полностью, а во второй запишется только 488 байт, а оставшиеся 24 байта заполнятся нулями.
Для записи в открытый файл надо выполнить следующие действия:
- установить указатель на границу сектора, если установить не на границу, то указатель будет округлен до нижней границы сектора
- вызвать функцию записи нужное количество раз
- финализировать запись, вызвав функцию с нулевым указателем
Для того, чтобы привести пример работы функции записи необходимо рассмотреть ещё одну функцию.
FRESULT pf_lseek(DWORD offset)
- устанавливает указатель чтения/записи в открытом файле. Устанавливать указатель можно абсолютным или относительным смещением, для абсолютного смещения необходимо передать в функцию число
pf_lseek(5000);
для относительного, передать значение указателя на текущую позицию fs.fptr
и величину смещения
pf_lseek(fs.fptr + 3000);
Для того чтобы функция работала в файле pffconf.h надо записать
#define _USE_LSEEK 1
Параметры:
DWORD offset
- количество байт, на которые нужно сместить указатель.
Возвращаемые значения:
FR_OK (0)
- возвращается в случае успешного выполнения функции
FR_DISK_ERR
- ошибка диска
FR_NOT_OPENED
- файл не был открыт
Записать данные в файл можно следующим образом.
FATFS fs;//объявляем объект типа FATFS
BYTE buff;//буфер для чтения файла
WORD br; //счетчик прочитанных байт
//монтируем диск
if (pf_mount(&fs) == FR_OK)
{
//открываем файл лежащий в корневой директории
if(pf_open("hello.txt") == FR_OK)
{
//устанавливаем указатель на первый сектор
pf_lseek(0);
//записываем
pf_write(buff, 10, &br);
//финализируем запись
pf_write(0, 0, &br);
}
}
Также оставляю тут кусок реально работающего кода, в котором используются все выше описанные функции.
#define F_CPU 8000000UL
#define buff_size 10
#include
FRESULT pf_opendir(DIR* dp, const char * path)
- функция открывает существующую директорию и создает указатель на объект типа DIR, который будет использоваться для получения списка файлов открытой директории.
Для того чтобы функция работала в файле pffconf.h надо записать
#define _USE_DIR 1
Параметры:
DIR *dp
- указатель на переменную типа DIR.
const char * path - указатель на строку, которая содержит путь к директории, директории разделяются слэшем
Возвращаемые значения:
FR_OK (0)
- возвращается в случае успешного выполнения функции
FR_NO_PATH
- не удалось найти путь
FR_NOT_READY
- не удалось инициализировать диск
FR_DISK_ERR
- ошибка диска
FR_NOT_ENABLED
- диск не был смонтирован
//объявляем переменные FATFS fs; DIR dir; //монтируем диск pf_mount(&fs); //открываем директорию pf_opendir(&dir, "MY_FOLDER");
FRESULT pf_readdir(DIR* dp, FILINFO* fno)
- функцию позволяет прочитать содержимое директории. Для этого нужно открыть директорию с помощью функции pf_opendir() и вызывать pf_readdir(). Каждый раз при вызове функция будет возвращать название объекта(папки/файла) лежащего в указанной директории. Когда она пройдется по всем объектам, вернет нулевую строку в элементе массива fno.fname.
Для того чтобы функция работала в файле pffconf.h надо записать
#define _USE_DIR 1
Параметры:
DIR *dp
- указатель на переменную типа DIR, которая должна быть предварительно объявлена
FILINFO *fno - указатель на переменную типа FILINFO, которая должна быть предварительно объявлена.
Возвращаемые значения:
FR_OK
- успешное завершение функции
FR_DISK_ERR
- ошибка диска
FR_NOT_OPENED
- не открыта директория
FATFS fs; FRESULT res; FILINFO fno; DIR dir; //монтируем диск pf_mount(&fs); //открываем директорию res = pf_opendir(&dir, MY_FOLDER); //читаем содержимое директории for(;;){ res = pf_readdir(&dir, &fno); //проверяем не возникло ли ошибок при чтении // и есть ли еще файлы в указанной директории if ((res != FR_OK) || (fno.fname == 0)){ break; } //выводим удобным способом fno.fname usart_sendStr(fno.name); usart_sendStr(/r); }
Ну и напоследок оставлю тут рабочий проект
Artem Makarov aka Robin
27.09.2014
В последнее время всё чаще приносят на восстановление информации флешки, выполненные на монокристальной основе, так называемые монолиты. Сегодня речь пойдёт о процессе восстановления данных с такого монолита, - карты памяти SD которую прислал партнер из города Кемерово. На карточке была записана видеосъемка свадьбы, и когда торжество успешно окончилось и пора было приступать к монтажу и выпуску подарочных DVD, флешка приказала долго жить.
Восстановление монолитных SD карт памяти
Примечательно, что внешне не понять, - это "классическая" SD карточка, с платой текстолита, NAND памятью и контроллером, или монокристалл. До тех пор, пока не вскроется пластиковый корпус. Чаще всего выход таких карт памяти из строя обусловлен сбоем в таблицах трансляции. Реже - электромеханическими повреждениями.
Для восстановления файлов с такой карточки первым делом надо вычитать дампы с кристалла. Для этого механическим (очисткой и шлифованием) путем удаляется защитный лак, скрывающий дорожки и контактные площадки монолита. После чего флешка начинает выглядеть так:
Дорожки и распиновка монолитной SD карты
Видны контактные площадки, к которым подключены шина данных, chip enable, read/write busy, питание и т.п. Разумеется ничего не промаркировано, и даташитов, в которых подробно расписано, что куда подключать, в свободном доступе так же нету. Распиновку можно отыскать либо взяв точно такую же исправную флешку (а их великое множество типов, и найдя такой же по виду условный SD Kingston, можно получить внутри совершенно по другому сделанный девайс) и вооружившись логическим анализатором кропотливо изыскивать что куда и зачем. Либо купив распиновку у человека/конторы, которые такую работу за тебя уже сделали.
В итоге получается нечто такое:
Или такое:
Теперь в полученных дампах нужно устранить внутренние преобразования. Первым делом убрать маску XOR, которую накладывал при записи информации в ячейки NAND контроллер флешки. С этой маской сектор выглядит так:
а когда нужная маска XOR подобрана и применена, то сектор приобретает осмысленный вид:
После устранения XOR преобразований нужно выставить корректную геометрию сектора, описать маркеры и область ECC корректировки данных. С помощью алгоритма ECC поправить битовые ошибки. Выяснить, в какой последовательности были расположены блоки, их размер. Поскольку тип контроллера неизвестен (это ж монолит!), то надо определить, каким сборщиком пользоваться в данном конкретном случае. Будет ли это сборка финального образа по маркеру сектора или по остаткам таблиц трансляции.
После того, как образ собран, проверить конфликтные блоки, имеющие одинаковый маркер, на актуальность и подставить в образ те, с которыми итоговый результат будет наилучшим. Получив привычный образ с файловой системой можно открыть его в любом дисковом редакторе и выгрузить нужные пользователю файлы.
Безусловно, многие операции достаточно автоматизированы, но тем не менее объем работ при восстановлении данных с монолитов (монокристаллов) весьма велик. Далеко не каждый инженер или компания, восстанавливающая информацию, горит желанием с такими работами связываться. И ценник на такого рода восстановление весьма далёк от понятия "бюджетный".
Вот еще один случай на примере восстановления SD Sandisk - такой же монолит, только внутри чуть по-другому сделан:
Готово для чтения
Восстановление MicroSD флешек
А вот как выглядят контактные площадки на Micro SD карточке. Сразу нужно оговориться, что это только несколько примеров из множества вариантов компоновки.
А вот вариант распиновки монолитной карты памяти Memory Stick Pro Duo
Вот - не сказать что монолит, но и не обычная USB флешка. Микросхема памяти (кристалл) залита компаундом (клеем).
А вот как выглядит монолитная карта памяти Olympus XD Picture card, с которой потребовалось восстановить фотоснимки:
Восстановление поломанных Микро СД
Отдельно стоит упомянуть об успешном выполнении задач по восстановлению информации с MicroSD флешек, сломанных на части, с отломанным куском, с трещинами на корпусе и т.п. Несколько примеров на картинках ниже:
Во всех случаях, когда речь идет о флешке разломанной на куски, с отломанной частью и т.п. есть возможность восстановления информации если остался цел кристалл NAND. Например в микро-флешке Сандиск из примера ниже в результате неаккуратной эксплуатации откололся кусок с повреждением дорожек, отмеченных красным овалом.
Лаборатория "Хардмастер" одна из немногих, имеющих опыт и квалификацию в восстановлении данных с монолитных USB, SD, microSD, Memory Stick и т.п. карт памяти. Если на вашей монолитной поломанной флешке остались важные файлы которые хотелось бы вернуть - обращайтесь к нам!