Розпинування sd та microsd. Відновлення даних з монолітних SD та MicroSD карт. Передача байта карті

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 тощо. карт пам'яті. Якщо на вашій монолітній поламаній флешці залишилися важливі файли, які хотілося б повернути - звертайтесь до нас!

Як відомо, карти пам'яті SD сумісні з інтерфейсом SPI, тому їх можна легко підключити до мікроконтролера і налагодити з ними обмін даними. Адаптери для карт типу microSD також є доступними, з такого адаптера ми можемо зробити слот для картки microSD для нашого макету. На фотографіях нижче показано зовнішній виглядвиготовленого адаптера для підключення до макетної плати

У проект спочатку використовувалася картка пам'яті microSD об'ємом 1 Гбайт. Мікроконтроллер – ATmega8 або ATmega32, що працює на частоті 8 МГц від внутрішнього RC осцилятора. Крім того, для підключення макету до персонального комп'ютера для моніторингу даних використовувався інтерфейс RS-232. Для перетворення логічних рівнів інтерфейсу використовується мікросхема MAX232. Для живлення схеми необхідне стабілізоване джерело живлення 3.3 (мікросхема MAX232 розрахована на напругу живлення 5 В, проте, як показала практика, зберігає працездатність при 3.3 В). Підключення карти пам'яті за 7-провідною схемою, відповідно до розпинування (див. рис).

Принципова схема мікроконтролера ATmega8.

Підтягуючі резистори R1, R2 номіналом 51 кОм інтерфейсу SPI надають кращу стабільність при роботі з різними картами. Стабілітрони D1, D2 призначені для захисту картки пам'яті під час роботи внутрішньосхемного програматора (ISP). Висновки мікросхеми MAX232 VCC та GND на схемах не вказані, але їх необхідно підкличити до відповідних точок схеми.

Принципова схема для мікроконтролера ATmega32

Принципова схема для мікроконтролера ATmega32 (додано годинник реального часу на мікросхемі DS1307)

Як ви помітили, живлення останнього варіанту пристрою здійснюється від джерела 12, а на платі встановлені два регулятори напруги 5.0 (LM7805) і 3.3 (LM1117-3.3). Для живлення інтерфейсу SD карти використовується 3.3, решта схеми живиться від джерела 5.0 В. Мікросхема годинника реального часу DS1307 в стандартному включенні і підключена до інтерфейсу I2C мікроконтролера.

Спочатку був вивчений «сирий» формат передачі даних, на прикладі операцій читання будь-якого блоку даних, читання та запису декількох блоків даних, стирання декількох блоків, запису даних у будь-який блок пам'яті SD. Пристрій, зібраний на макетній платі, підключався до комп'ютера за інтерфейсом RS-232. Для відображення прочитаних даних із картки пам'яті, а також для введення та запису даних на картку використовується програма HyperTerminal (або аналогічна) на комп'ютері.

Після успішної реалізації обміну даними без специфікації, картка пам'яті була відформатована (FAT32) в операційній системі Windows XP, потім на карту було записано кілька текстових файлів, директорій та інші типи файлів (в кореневу директорію карти). Після цього були написані підпрограми та функції роботи з файловою системою FAT32 для читання файлів, для отримання списку файлів на карті пам'яті (з використанням HiperTerminal), для отримання інформації про повний і вільний обсяг пам'яті.

Вигляд вікна HiperTerminal з функціями роботи з карткою пам'яті SD:

Користувачеві пропонуються понад 10 опцій роботи з карткою пам'яті (для варіанту з годинником).

Опції 0 - 4- Це низькорівневі функції. Після використання опцій 0 - 3 Вам необхідно переформатувати карту перед використанням FAT32 підпрограм.
Опції 5 - 9- відносяться до файлової системи FAT32. На даний момент підтримуються лише короткі імена файлів (8 Байт – ім'я файлу, 3 Байта – розширення файлу). Якщо будуть записані файли з довгими іменами, вони будуть відображені в термінальній програмі в короткому форматі. Для тестування цих опцій не забудьте відформатувати картку у файловій системі FAT32, записати кілька директорій та текстових файлів.

Опис опцій:

0 - Erase Blocks- стирання обраної кількості блоків, починаючи з зазначеного.
1 - Write Single Block- запис даних у блок із певною адресою. Дані вводяться з клавіатури у програмі Hiperterminal;
2 - Read Single Block- Читання даних з блоку з певною адресою. Прочитані дані відображаються у вікні термінальної програми;
3 - Writing multiple blocks- запис кількох блоків, починаючи з певної адреси;
4 - Reading multiple blocks- Читання декількох блоків, починаючи з певної адреси.

Примітка.Тут функції роботи з декількома блоками (опції 3 та 4) відключені через брак пам'яті мікроконтролера ATmega8, оскільки ці функції не потрібні для тестування файлової системи FAT32. Для увімкнення цих опцій необхідно видалити макрос у файлі SD_routines.h (#define FAT_TESTING_ONLY). І якщо Ви використовуєте ATmega8, на час тестування опцій 3 і 4 бібліотека FAT32 може бути видалена з метою звільнення пам'яті мікроконтролера.

5 - Get File List- відображає список доступних директорій та файлів із займаним ними обсягом пам'яті (у кореневій директорії картки);
6 - Read File- Читання зазначеного файлу та відображення вмісту у вікні термінальної програми;
7 - Create File- створити/додати файл із зазначеним ім'ям;
8 - Delete File- видалити всі файли файл із зазначеним ім'ям;
9 - Read SD Memory Capacity- інформація про повний та вільний обсяг карти пам'яті (використовується FSinfo сектор SD карти).

У термінальній програмі послідовний порт налаштовується на швидкість обміну 19 200 бод, без контролю потоку та без перевірки парності.

Для версії з годинником реального часу (DS1307) на мікроконтроллері ATmega32 властивості створюваних або оновлюваних файлів прив'язуються до дати і часу (дата створення/зміни), ці властивості прописуються у файловій таблиці і можуть бути перевірені за допомогою комп'ютера, а також годинник може бути корисним. збиранні даних. У меню опцій у термінальній програмі додано три опції.

Оновлено18.12.15. Всім привіт. Сьогодні ми продовжимо розробку контролера збору даних, а саме збереження інформації безпосередньо на картку SD . Минулої статті було налагоджено роботу термометра. Тепер цю інформацію за часом при підключенні внадалі годинника реального часу(стаття №29), ми заноситимемо на карту пам'яті, отримавши своєрідну базу даних. А також надалі перенесемо цю інформацію на ПК (стаття №42), до бази даних під керуванням MySQL (стаття №48), через невеликий додаток на Java (стаття №44). Але спочатку розберемося що таке SD - карта і як з нею працювати.Почнемо з короткого огляду історії. Попередником Flash-пам'яті є один з енергонезалежних видів пам'яті, типу, яка зарекомендувала себе і використовується у мікроконтролерах. Flash-пам'ять виникла в ході потреби збільшення ємності та зміни технології стирання (у разі пам'яті EPROM). Тому в 1984 році інженер компанії Toshiba Фудзіо Масуокой змінив технологію стирання, що вирішив недоліки попередників Flash-пам'яті. Хочеться додати, що ця пам'ять почала ділиться по внутрішньому пристрої з'єднання осередків в масив і алгоритмами читання-запису - це NOR-і NAND-технологія. А також відмінність за кількістю бітів, що зберігаються в елементарному осередку. Це SLC-пристрої (single-levelcell), тобто. однобітові осередки розрізняють лише два рівні заряду на плаваючому затворі. І MLC-пристрої (multi-levelcell) - багатобітові осередки розрізняють більше рівнів заряду. Другий тип приладів дешевший і більш ємний, ніж SLC-прилади, проте з більшим часом доступу та меншою кількістю перезаписів (близько 10 тис. і 100 тис. — SLC).

Взагалі пристрої технології NOR - це двомірна матриця провідників, що дозволяє отримати швидший доступ до кожного осередку пам'яті, але при цьому площа осередку вважається великою, тому дана технологія використовується для пам'яті програм мікропроцесорів і для зберігання невеликих допоміжних даних, сюди можна включити і спеціалізовані мікросхеми початкового завантаження комп'ютерів
(POST і BIOS), процесорів ЦГЗ та програмованої логіки. Типові об'єми - від 1 кбайта до 1 Мбайта.
Другий тип пристрою – NAND-технологія – тривимірний масив має малу площу осередку, але відносно тривалий доступ одразу до великої групи осередків. Використовується для великого обсягу пам'яті.Ось із цією пам'яттю ми і працюватимемо.
Але перед цим хочеться сказати про нестачу. Як і все є свій термін використання, так і у пам'яті є ресурс зносу. Виробники у гонці за ємністю та лідерством на ринку, завжди упускають такий показник як якість, т.к. він не сумісний із високою ціною. Так повертаючись до зносу, хочеться відзначити, що термін зберігання інформації при використанні MLC-пристроїв становить приблизно 5 років, що пов'язано з накопиченням незворотних змін при зміні заряду. Якщо брати пам'ять NAND c SLC-пристрою, то вони є якіснішими, і відповідно дорогими. Варто відзначити, що термін зберігання інформації дуже залежить від температури, гамма-радіації і частинок високої енергії.
Вище було сказано, що недолік картки - це обмежена кількість циклів перезаписів. Коли ми будемо використовувати файлову систему для управління файлами, то повинні знати, що такі системи записують дані в одне місце, природно витрачаю ресурс виділеної області в результаті виведення її з ладу і відповідно зменшуючи ємність. Для цього типу пам'яті використовується NAND-контролер, який має рівномірно розподіляти зношування. Однак для здешевлення пристроїв контролер може і не використовуватись, а його роботу виконуватиме програмний NAND-драйвер в операційній системі. Після цього відкриття багато компаній зайнялися розробкою своїх стандартів портативних карт.

Далі перейдемо безпосередньо до розгляду картки.
Secure Digital Memory Card (SD) – формат карт пам'яті, розроблений для використання в основному в портативних пристроях. Щоб розібратися в її роботі, ми будемо використовувати специфікацію, яка описує цей стандарт і називається SD Specifications ver3.01.
Перше, що нам необхідно, так це розібратися як працювати з цією картою, як підключити та інше. Спочатку виберемо картку. Для експериментів я взяв microSD ємністю 2Гб стандарт ємності SDSC. Шина карти може працювати за двома протоколами SD та SPI. Хочеться відзначити, що дана карта це свого роду модифікація карти MMC, де (у карті SD) основна увага була приділена системі безпеки. Тому алгоритм роботи з протоколу SPI такий же, і вони однобічно сумісні. Тобто ми можемо в слот картки SD вставити MMC, але не навпаки.

На малюнку нижче представлена ​​схема підключення карти SD по протоколу SPI .
Цей інтерфейс дозволяє обмінюватися даними на високій швидкості, задіявши при цьому мінімальну кількість висновків мікроконтролера, які оснащені модулем SPI. Із цього моменту почнемо використовувати специфікацію. Перше, що нас цікавить - вибір режиму. Розберемося у тонкощах на рис. нижче з розділу 6.4.1.1 представлена ​​діаграма напруги живлення та послідовність посилки команди. Тут чітко видно, що після включення картки необхідно почекати кілька мілісекунд (1мс + від 0.1 до 35 мс (наростання)) на стабілізацію. Протягом цього часу на CS, MOSI лінії має бути подана 1. Далі відбувається затримка ініціалізації максимум 1 мс, при подачі на вхід CLK 74 імпульсів (тактів), після чого має йти команда CMD0. Перейдемо до глави 7, де чітко описана послідовність дій.

Діаграма напруги живлення

SPI протокол вибирається після включення живлення та подачі команди скидання CMD0. Сама по собі картка SD працює в режимі SD. Вхід у режим здійснюється, якщо сигнал SC при подачі команди CMD0 буде 0. При переході в режим SPI карта відповість форматом R1 (рисунок нижче). Формат відповіді є байт (залежить від команди див. таблицю 7.3 у специфікації) з прапорами визначають стан карти. Правильні відповіді для нас це буде 1 (у разі команди CMD0) та 0 у всіх інших випадках.
1-й біт – режим очікування
2-й – помилка стирання
3-й – невідома команда
4-й – помилка команди
5-й – помилка у послідовності стирання
6-й – помилка адреси
7-й – помилка аргументу

У процесі скидання карта повинна відповісти 0×01, що відповідає першому біту.

У специфікації є чітка послідовність ініціалізації для SPI. Для чого використовується команда CMD8 для перевірки робочого стану карти, де відбувається досить простий алгоритм перевірки. Далі команда CMD58 визначення типу карти SDSD або SDHC і SDXC. А також команда CMD41 для запуску та перевірки ініціалізації. Досить не простий процес ініціалізації з перевірками, але я думаю, що для простого запису даних можна використовувати більш спрощений процес. У розділі 7.2.7. говориться, що у режимі очікування єдино допустимі команди картки CMD41, CMD8, CMD58, CMD59 , і навіть для карт (товстих 2.1мм) пам'яті SD CMD1, який ідентичний команді CMD41. У стандарті ця команда вважається забороненою для ініціалізації, і використовується виключно для розходження карт 1,4 мм та 2,1 мм.
Ходімо більш простим шляхом і використовуємо команду CMD1. Все вище описане відобразимо в коді функції ініціалізації, але перед цим розглянемо формат команди. Кожна команда або блок даних складаються з восьми бітів, які вирівнюються за сигналом CLK. Тобто. кожна команда вирівнюється на межі 8 тактів. Повідомлення SPI складаються з команди, відповіді та даних. Весь зв'язок контролюється мікроконтролером. Усі команди мають довжину 6 байт. Передача починається з першого лівого біта.

На малюнку нижче представлено формат команди.


Старт біт з 0 починається будь-яка команда.Переданий біт теж завжди дорівнює 1.
Індекс – безпосередньо передається команда.
Аргумент- для кожної команди аргумент вказано у таблиці специфікації.
CRC – перевірка надмірності коду. За замовчуванням у режимі SPI вимкнено. Тому ми її використовуємо тільки для команди CMD0, яка надсилається до входу в режим і має значення CRC 0×95.
Стоп біт кінець команди, що передається.
Що ж приступимо до написання коду.
Почнемо з необхідних 2-х функцій: передача та прийом байта.
1. Передача байта карті.
void trans_byte_sd (unsigned char data) // передаємо масив бітів
{
for (unsigned char i=0;i<8;i++) //Перебираємо байт
{
if ((data&0×80)==0×00)//Якщо старший біт = 0
PORTB&=~_BV (PB3);//Виставити MOSI (DI) -0
else
PORTB | = _BV (PB3);//1
data=data<<1; // сдвиг влево
PORTB|=_BV (PB5); //Імпульс або строб
asm ("nop"); //Пауза 1 такт
PORTB&=~_BV (PB5);
}
}
2. Прийом байта мікроконтролером.
unsigned char receive_byte_sd (void) // Повертаємо відповідь
{
unsigned char data = 0; // ініціалізуємо масив
for (unsigned char i=0; i<8; i++)
{
PORTB|=_BV (PB5); //Фронт імпульсу
data=data<<1; // Зрушуємо вліво
if ((PINB&_BV (PB4))!=0×00) // Якщо стан піна 1
data=data|0×01;
PORTB&=~_BV (PB5); //0
asm ("nop");
}
return data; // Повертаємо відповідь
}

З вище описаних основних функцій почнемо писати подальший код. Далі пропишемо функцію передачі команди. Тут хочеться звернути увагу, на те, що Ви можете передавати всі 5 аргументів: безпосередньо саму команду і 4-аргументи, що відповідають за адресу осередків пам'яті самої карти. Що стосується 6-го байта, то CRC при вході в режим SPI відключається (за замовчуванням) і значення постійно дорівнює 0×95, яке використовується тільки для CMD0, коли карта не в режимі. Увімкнути перевірку коду можна за допомогою CMD58. Для експериментів я передаю два аргументи.

3.Передача команди.
unsigned char comand_sd (char CMD, char arg) /*передаємо команду та адресу до якої звертаємось та повертаємо відповідь*/
{
long int i = 0; // змінна для лічильника
unsigned char r1; // відповідь карти
trans_byte_sd (CMD); // команда
trans_byte_sd (0×00);
trans_byte_sd (0×00);
trans_byte_sd (arg); // передача адреси
trans_byte_sd (0×00);
trans_byte_sd (0×95); // Передача CRC
/* Після передачі команди чекаємо відповіді формату R1. Кожній команді відповідає свою відповідь*/
/* Цикл для очікування відповіді за певний час*/
do
{
r1=receive_byte_sd();
i++;
)while (((r1&0×80)!=0×00)&&(i<0xffff)); /* Як тільки старший біт байта не дорівнює 0 і i не перевищує 65535 тактів*/
return r1; // Повертаємо відповідь
}
4. І ніціалізація картки.

Тепер ми можемо прописати ініціалізацію картки. Коротко програма описується наступним чином: перше, що необхідно, так це перевести карту в режим SPI. При подачі живлення картка встановлюється в режим SD. Для вибору режиму SPI на вхід CS подається логічний 0, у цей час подається команда скидання CMD0 та ініціалізації CMD1 на вхід карти MOSI. Звернемо увагу, що команда починається від шістнадцяткового 0×40, до якого необхідно додати номер команди CMD у шістнадцятковому вигляді.

unsigned char spi_card_init (void)// функція повертає відповідь
{
unsigned char r1; // змінна прийому відповіді
long int i = 0; // змінна для лічильника
_delay_ms (10); / / Невелика затримка для стабілізації напряж.
PORTB|=_BV (PB1); //CS, встановлюємо 1, при подачі тактів
PORTB | = _BV (PB3); //Лінія подачі команд - 1 MOSI (DI)
for (unsigned char i=0; i<80;i++) // посилаємо понад 74 імпульси
{
PORTB|=_BV (PB5); //CLK - 1
asm ("nop"); //затримка в один такт
PORTB&=~_BV (PB5); //CLK - 0
}
PORTB&=~_BV (PB1); /* умова для входу в режим SPI лінія CS повинна дорівнювати 0 */
r1=comand_sd (0×40,0×00); // CMD0=0×40, адреса не має різниці
if (r1!=0×01) return 4;//Коди помилок можете ставити будь-які
trans_byte_sd (0xff); /* посилаємо строб, своєрідна пауза перед прийомом відповіді */
do // цикл прийому відповіді карти
{
r1=comand_sd (0×41,0×00); /* посилаємо команду ініціалізації */
trans_byte_sd (0xff); // пауза
i++; // лічильник
)while ((r1! = 0)&&(i<65535)); /*поки не отримано відповідь 0 та кількість циклів не перевищує 0xffff */
if (i>=0xffff) return 5; /* повертаємо помилку якщо перевищив час опитування */
return 0; //Повертаємо 0 у разі успішної ініціалізації
}

Наступний важливий момент, у специфікації пишеться, що інформація передається блоками, по 512 біт, причому якщо карта SDSC як у нашому випадку, то довжину блоку можна встановити від 1 до 512 біт командою CMD16. Типово 512 біт. Далі опишемо дві функції прийому та передачі блоків. У специфікації дані блок-діаграми, спираючись на які ми напишемо код.

Передача інформації на карту.

За передачу ЄДИНОГО блоку відповідає команда CMD24. Після подачі команди, чекаємо відповідь Після чого слідує стартовий байт, який готує контролер картки до прийому інформації, після закінчення картка відповідає байтом про стан передачі, описаний у розділі 7.3.3.1. Тобто. правильна відповідь має бути = 5. Також чекаємо на звільнення шини для подальшої передачі.

Байт відгук про стан передачі.

У розділі 7.3.3.2 описується формат блоку, що передається.
unsigned char receive_block_sd (char * block, char arg)/* передаємо масив для запису даних та адресу до якої звертаємось*/
{
long int i = 0;
unsigned char r1;
r1=comand_sd (0X51, arg);// CMD17
if (r1!=0×00) return 5;//Вийти, якщо відповідь не 0×00
trans_byte_sd (0xff);
do //Чекаємо початку пакету даних
{
r1=receive_byte_sd();
i++;
)while ((r1! = 0xfe)&&(i<65535));
if (i>=0xffff) return 5;
for (int i=0;i<512;i=i+1) //Прийом даних
block[i] = receive_byte_sd();
receive_byte_sd(); //Байт CRC
receive_byte_sd(); //Байт CRC
return 0;
}

Перед тим, як використовувати програму, розглянемо апаратну частину. Як ми говорили, вище, що картка сумісна з мікроконтролером у режимі SPI. Зазначимо такі нюанси роботи з карткою:
1. Поєднання логічних рівнів, необхідне при різній напрузі живлення SD-карти та мікроконтролера AVR. Можна використовувати резистивний дільник напруги, що є лінійним, тобто. Напруга на виході залежить від напруги на вході. А можна паралельний параметричний стабілізатор напруги на стабілітроні, теж що і перший варіант, тільки в нижньому плечі використовується стабілітрон, який є нелінійним дільником, і слідкує за опорною напругою за рахунок своїх властивостей при підвищенні вхідної напруги зменшувати внутрішній опір, і навпаки.
Я використав другий варіант. У схемі нижче на сигнальній лінії опору є баластними (токообмежувачі), на вхід дільника надходить напруга 4,5 - 5, а вихідне знімається з нижнього плеча дільника.Струмообмежувачі необхідні для захисту картки та іншої периферії при збоях мікроконтролера. При добре налагодженому пристрої немає потреби.

Зверніть увагу, що лінія MISO не потребує узгодження, т.к. працює тільки в один бік від картки до мікроконтролера.
2. Другий момент, я не використовую перевірку наявності карти та захисту запису. У когось є ці контакти в слотах, у когось немає.
3. Останній момент-живлення. Або Ви живите 3.3 вольта всю схему, включаючи мікроконтролер, або ставите дільник на вхід схеми, не дуже надійно. Або стабілізатор 3.3 вольта, як і зробив на мікросхемі LP2980 . Важливим моментом є електролітичний (танталовий) конденсатор, який захищає мікроконтролер від скидання при просіданнях напруги.
Нижче представлена ​​програма та результат.Як завжди, я намагаюся використовувати одну програму, постійно її змінюючи. Цей код взято із статті №5 (семісегментний індикатор).

#include
#include
#include
#include
//макроси для роботи з індикатором
#define a 128
#define b 32
#define c 8
#define d 2
#define e 1
#define f 64
#define g 16
#define dp 4

// Змінні

char block = ();//буфер запису/читання даних на карту
short unsigned int j, k = 0; //у макросі переривання
unsigned char Slot; // Масив чисел для відображення на індикаторі

//Оголошуємо функції

void trans_byte_sd (unsigned char data);// функція передачі байта
unsigned char receive_byte_sd (void); //Функція прийому байта
unsigned char comand_sd (char, char); // функція передачі команди
unsigned char spi_card_init (void); //Функція ініціалізації картки пам'яті
unsigned char receive_block_sd (char * block, char arg); //Функція прийому блоку
unsigned char trans_block_sd (char * block, char arg); //Функція передачі блоку
// Ініціалізації індикатора
void Slot_init()
{…………………….};
// Змінні для відображення цифр
char Elem1, Elem2, Elem3;
// Виведення на індикатор
void Display (float i)
{ …………………………... }
int main (void) //початок основою програми
{
DDRB = 0x2A; //0010 1010 - PB1, PB3, PB5
DDRD = 0xff; //Всі висновки порту - виходи
PORTD = 0×00; //встановлюємо 0
PORTB | = 0хdb; //1101 1011 (PB0,1,3,4,6,7)
Slot_init();
sei(); / / або SREG | = (1<< 7); разрешить общее прерывание
//ініціалізація таймера Т0
TIMSK = (1</*Прапор дозволу з переповнення таймера лічильника Т0*/
TCCR0 = (0< //1000000/8 = 125000
unsigned char temp;
int i;
for (i=0;i<512;i=i+1)
block [i] = i; //записуємо в буфер
spi_card_init(); //ініціалізація
trans_block_sd (block,0×04); // надсилаємо дані карті
// Обнулюємо буфер
for (int i=0;i<512;i=i+1)
block [i] = 0;
// Вважаємо дані з картки
receive_block_sd (block, 0×04); ;//Функція прийому байта
for (int i=0;i<512;i=i+1)
{
char otv;
otv = block [i];
Display (OTV);
_delay_ms (100);
}
//Запишемо за адресою на згадку 0
for (int i=0;i<512;i=i+1)
block [i] = 0;
unsigned char comand_sd (char, 0×00); //функція передачі команди
trans_block_sd (block,0×04); // надсилаємо дані карті
}
//Виведення на індикатор
ISR (TIMER0_OVF_vect)
{ ……………. }

Важливий момент це таймаути. Важливо стежити за часом читання запису та стирання карти, оскільки може зависнути мікроконтролер у режимі очікування відповіді карти. У специфікації чітко описані таймаути картки. Простий карти триває 5 мс, після чого переходить в енергозберігаючий режим, у якому допустимі наступні команди CMD0, CMD1, CMD41 та CMD58. Тому при перевищенні ліміту простою передаємо CMD1, відповідь і надалі працюємо з карткою.
Внизу представлено два скріншоти з програми WinHex, за допомогою якої ми можемо переглянути вміст комірок пам'яті. Програма працює наступним чином: Записуємо дані в буфер, відправляємо карті, обнулюємо буфер, зчитуємо дані з картки в буфер і виводимо на дисплей, тим самим переконуємося в передачі даних карті. Дивимося вміст карти, обнулюємо буфер, записуємо 0 в карту і знову відкриваємо вміст карти, тим самим переконуємось у працездатності програми та схеми. Як завжди незабутній про дрібниці, такі як не допайка, не великі тріщенки в доріжках та ін, що може забрати левову частку часу. Тому якщо є під руками осцилограф, неодмінно використовуйте його для налагодження. Встатті №24я навів невеликий приклад діагностики картки на всіх етапах її роботи.ми познайомимося здатчиком вологості та температуриDHT11. Після цього почнемо записувати дані (температуру та вологість) у текстовий файл, своєрідну базу даних. Поки що на цьому все. Бувайте усі.

Всім доброго дня! Сьогодні ми поговоримо про підключенні картки пам'яті SDдо мікроконтролера STM32.

Здавалося б, пам'яті повно у контролерів STM32F10x, навіщо там ще додаткова, але це враження оманливе. байт. Ось і отримуємо близько 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 clock transition on which the bit capture is made. Цей параметр може бути значенням @ref SDIO_Clock_Edge */ uint32_t SDIO_ClockBypass; /* Specifies whether the SDIO Clock divider bypass is enabled or disabled. Цей параметр може бути значенням @ref SDIO_Clock_Bypass */ uint32_t SDIO_ClockPowerSave; /* Specifies whether SDIO Clock output is enabled or disabled when the bus is idle. Цей параметр може бути значенням @ref SDIO_Clock_Power_Save */ uint32_t SDIO_BusWide; /* Specifies the SDIO bus width. Цей параметр може бути значенням @ref SDIO_Bus_Wide */ uint32_t SDIO_HardwareFlowControl; /* Specifies whether the SDIO hardware flow control is enabled or disabled. Цей параметр може бути значенням @ref SDIO_Hardware_Flow_Control */ uint8_t SDIO_ClockDiv; /* Specifies the clock frequency of the SDIO controller. Цей параметр може бути значення між 0x00 і 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. Якщо комбінації містяться в argumentі, він повинен бути завантажений в цей ареал перед тим, як писати в список 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. Цей параметр може бути значенням @ref SDIO_Response_Type */ uint32_t SDIO_Wait; /* Specifies whether SDIO wait-for-interrupt request is enabled or disabled. Цей параметр може бути значенням @ref SDIO_Wait_Interrupt_State */ uint32_t SDIO_CPSM; /* Specifies whether SDIO Command path state machine (CPSM) is enabled or disabled. Цей параметр може бути значенням @ref SDIO_CPSM_State */) SDIO_CmdInitTypeDef; typedef struct (uint32_t SDIO_DataTimeOut; /* Specifies 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. Цей параметр може бути значенням @ref SDIO_Data_Block_Size */ uint32_t SDIO_TransferDir; /* Specifies the data transfer direction, whether the transfer is a read or write. Цей параметр може бути значенням @ref SDIO_Transfer_Direction */ uint32_t SDIO_TransferMode; /* Specifies whether data transfer is в stream or block mode. Цей параметр може бути значенням @ref SDIO_Transfer_Type */ uint32_t SDIO_DPSM; /* Specifies whether SDIO Data path state machine (DPSM) is enabled or disabled. Цей параметр може бути значенням @ref SDIO_DPSM_State */) SDIO_DataInitTypeDef;

Зазначимо, як у SPL реалізована передача команд карті пам'яті. Для цих цілей відведено окрему структуру SDIO_CmdInitTypeDef.У полі SDIO_CmdIndexвводимо код команди, у полі SDIO_Argument- Аргумент команди, також заповнюємо інші поля. А для цього нам приготували функцію:

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 байт.

Якщо ми запустимо програму під налагоджувачем, то побачимо, що лічені дані відповідають записаним =) Отже експеримент можемо вважати вдалим. На цьому сьогодні закінчуємо, до швидких зустрічей!

Сьогодні SD-картки використовуються усюди. Вони встромляються в ноутбуки, планшети, телефони, відеокамери, роутери, фоторамки, диктофони, електронні книги, mp3-плеєри, одноплатні комп'ютери і навіть квадрокоптери — словом, вони скрізь. Часто про них думають, як щодо повільних пристроїв, здатних зберігати пару гігабайт інформації. Однак у наші дні вже доступні SD-карти об'ємом 512 Гб та швидкістю читання-запису 90 Мбайт/сек (не мегабіт!). Теоретично обсяг збереженої інформації обмежений 2 Тб. А чим ще прекрасні SD-карти, це тим, що з ними можна працювати по простому протоколу, заснованому на SPI.

Небагато матчасті

"SD" розшифровується як "Secure Digital". До того ж тут безпеку не знає ніхто. Усередині SD-карти знаходиться звичайна flash-пам'ять та мікроконтролер, який здійснює спілкування із зовнішнім світом. Тобто, в першому наближенні, це точно така ж non-volatile пам'ять, як і SPI flash.

SD-картки бувають трьох типів. Карти SDSC (SC = Standard Capacity) дозволяють зберігати до 2 Гб інформації та використовують файлову систему FAT12 або FAT16. Ці карти морально застаріли, в магазинах їх знайти непросто, та й за ціною вони можна порівняти з картами більшого обсягу. Крім того, вони використовують протокол, який трохи відрізняється від протоколу SDHC/SDXC-карт. У силу названих причин, з цього моменту про існування SDSC ми забудемо. До сучасних типів карт відносяться SDHC (HC = High Capacity), що використовують файлову систему FAT32 і здатні зберігати до 32 Гб даних, а також SDXC (XC = eXtended capacity), що використовують exFAT та мають об'єм до 2 Тб. З погляду протоколу ці карти не відрізняються. Різниця полягає лише у файловій системі, вибір якої диктується специфікацією.

Зрозуміло, ніщо не заважає відформатувати карту SDHC під exFAT, або карту SDXC під який-небудь ZFS. Але ваш смартфон чи фотоапарат, ймовірно, не зможе працювати з такою карткою.

Fun fact!Трапляються підроблені SDHC карти, які насправді є SDSC. У звичайному магазині ви такі, швидше за все, не знайдете, а ось на eBay можна налетіти. Якщо вам пропонують купити типу SDHC карту обсягом лише 1 Гб, вона напевно насправді є SDSC.

Карти поділяють на різні класи, залежно від мінімальної послідовноюшвидкості запису(Зверніть увагу на виділення курсивом). Клас швидкості позначають у стилі C4 (class 4) або V30 (class 30). В обох випадках цифра означає швидкість Мбайт/сек. Відмінність C від V полягає лише в тому, що V натякає на придатність карти для запису відео високої роздільної здатності. Ще зустрічаються маркування U1 та U3 для 10 Мбайт/сек та 30 Мбайт/сек відповідно, де U означає Ultra High Speed. C10, V10 і U1 - це те саме.

SD-карти бувають різних форм-факторів – SD, MiniSD та MicroSD. MiniSD сьогодні практично не трапляються. Багато карток випускаються у формі MicroSD з перехідником у звичайний SD-формат. Це дозволяє покупцям використовувати карти з різними пристроями.

На наступному фото зображена моя невелика колекція SD та MicroSD-карт, а також модулів для підключення їх до налагоджувальних плат (Arduino, Nucleo та подібним):

Усі представлені тут модулі працюють однаково добре. Якщо сумніваєтеся, який брати - беріть той, що зображений зліва внизу. Він дозволяє працювати як із SD, так і з MicroSD-картами (через перехідник), а також має додаткові піни для підключення логічного аналізатора. Модуль не важко знайти на eBay. Ще зустрічаються модулі взагалі без резисторів, стабілізаторів напруги і так далі, що мають лише слот для підключення карти та піни. З ними деякі карти не працюватимуть! Далі стане зрозуміло чому. Нарешті, модуль легко спаятиме з адаптера для MicroSD-карт. Далі буде розказано як.

Підключення SD-карти

Нижче зображено розпинування SD та MicroSD-карт (ілюстрація запозичена звідси):

Найбільший інтерес для нас має права колонка. На перший погляд, все просто - дивимося на картинку, хоч прямо припаюємося до карти проводами, і починаємо надсилати і приймати байти по SPI. Але є низка важливих моментів:

  • У жодному разі не подавайте 5 В на пін VDD! Усі SD-карти гарантовано працюють від 3.3В. Деякіпри цьому можуть працювати і від 5 В, але це не гарантується. Якщо подати 5 В, ви ризикуєте спалити вашу дорогу картку на 128 Гб, після чого її залишиться лише викинути;
  • З тих же міркувань, якщо ваш проект використовує п'ятивольтову логіку, рекомендується використовувати конвертер рівнів, наприклад TXS0108E (даташит );
  • Плати Arduino мають пін 3V3, але не можуть подавати на нього великий струм. Якщо запитати SD-карту від цього піна, можна зловити кумедні глюки. Наприклад, картка буде нормально працювати на самоті, але переставати працювати при підключенні до плати TFT-екранчика на базі ST7735, чиє підсвічування також живиться від 3V3. Тому, якщо ви проектуєте модуль або Arduino-шилд, використовуйте знижувальний стабілізатор напруги на 3.3 на кшталт AMS1117, що живиться від 5 В;
  • Пін DO (він же MISO) має бути обов'язковопідтягнутий до плюсу через резистор на 10 ком або близько того. Деякі карти просто не стартуватимуть без цього резистора. Наприклад, я спостерігав таку поведінку на картах виробництва Sony;

Тепер стає зрозуміло, чому прості модулі, які мають лише слот для підключення картки, не дуже підходять. Також тепер ясно, як зробити модуль для підключення MicroSD карт з адаптера. Зазначу, що піни із землею (VSS1 і VSS2) в адаптері, як правило, вже з'єднані між собою, тому додатково з'єднувати їх дротиком не потрібно. Про всяк випадок варто перевірити ще раз, чи з'єднані піни, продзвонивши їх мультиметром.

Тонкощі протоколу

Хороший опис протоколу було знайдено у статті How to Use MMC/SDC на сайті elm-chan.org. Тут я не бачу сенсу її переказувати. Зацікавлені читачі можуть ознайомитись з оригіналом, а також повною реалізацією протоколу для мікроконтролерів STM32 у вихідниках до цього посту. Замість переказу я лише пробіжуся основними моментами. Також зазначу, що у статті я не знайшов згадки про кілька вкрай важливих нюансів, про які буде розказано далі.

Отже, типова команда виглядає якось так:

Команди завжди мають формат 01xxxxxx, і відповідно до значення бітів xxxxxx називаються CMD0, CMD1, і так далі до CMD63. Слідом за командою йдуть 4 байти аргументу, за якими йде байт у форматі yyyyyyy1 із семибітним CRC. Контрольні суми за замовчуванням вимкнені та перевіряються лише для перших кількох команд на етапі ініціалізації. В інших випадках CRC заповнюється одиницями.

Більшість команд одержують у відповідь один байт, так званий R1:

/*
R1: 0abcdefg
||||||`- 1th bit (g): card is in idle state
|||||`-- 2th bit (f): erase sequence cleared
||||`--- 3th bit (e): illigal command detected
|||`---- 4th bit (d): crc check error
||`----- 5th bit (c): error in the sequence of erase commands
|`------ 6th bit (b): misaligned addres used in command
`------- 7th bit (a): command argument outside allowed range
(8th bit is always zero)
*/

Якщо старший біт відповіді дорівнює одиниці, то SD-карта ще обробляє запит. Іноді за R1 слідують додаткові дані. Також у певних ситуаціях у протоколі фігурують data tokens (байти 0 x FC, 0 x FE), stop transaction token (0 x FD), error token та data response. Деталі не дуже захоплюючі, до того ж вони добре описані на elm-chan.org і їх можна вивчити за кодом. Набагато цікавіше те, чого у статті немає або позначено не надто явно.

По-перше, ви можете пам'ятати, що SPI за один такт SCLK одночасно приймається і передається один біт інформації. Так ось, виявляється, що якщо при читанні відповіді від SD-карти випадково надіслати по SPI щось відмінне від одиниць, деяким SD-карт це рве вежу. Тому прийом даних від картки виглядає якось так:

static int SDCARD_ReadBytes(uint8_t * buff, size_t buff_size) (
// make sure FF is transmitted during receive
uint8_t tx = 0xFF;
while (buff_size > 0) (
HAL_SPI_TransmitReceive(& SDCARD_SPI_PORT, & tx, buff, 1 ,
HAL_MAX_DELAY);
buff++;
buff_size--;
}

return 0;
}

По-друге, у статті чітко описано, що у певних випадках карта може позначати себе зайнятою (busy), притягуючи MISO до землі. У таких ситуаціях слід дочекатися готовності карти. Але на практиці виявилося, що перевірку на готовність потрібно виконувати перед кожноюкомандою, навіть якщо за поточних обставин карта не може бути зайнятою. Тобто, по суті, перед кожною командою потрібно надсилати 0 x FF (на ілюстрації з форматом команд цей момент опущено). Інакше деякікартки відмовляються працювати. Зокрема, я спостерігав таку поведінку карт виробництва SanDisc.

Відповідна перевірка:

static int SDCARD_WaitNotBusy() (
uint8_t busy;
do (
if (SDCARD_ReadBytes(& busy, sizeof (busy) )< 0 ) {
return - 1;
}
) while (busy! = 0xFF);

return 0;
}

Fun fact!Зрозуміти я це зміг, піддивившись у Arduino-бібліотеку SD. Користуючись нагодою, зазначу, що ця бібліотека в цілому досить погана. Мені не здається дуже гарною ідеєю заважати в одну купу коду для SDSC і SDHC/SDXC карт, як зроблено в цій бібліотеці. Також я помітив, що в ній чомусь немає підтримки CMD18 (READ_MULTIPLE_BLOCK), незважаючи на те, що CMD25 (WRITE_MULTIPLE_BLOCK) реалізована. І ще бібліотека відмовилася працювати з деякими картами, які я маю, незважаючи на те, що код, написаний мною з нуля, чудово з ними працює. Ось і користуйся після цього готовими бібліотеками!

Нарешті, по-третє, картка може ділити SPI-шину з іншими пристроями. Зрозуміло, що в цьому випадку насамперед після запуску прошивки потрібно помітити всі пристрої, як неактивні, подавши відповідну напругу, зазвичай високу, на піни CS. Після чого вже можна спокійно спілкуватися з кожним пристроєм окремо, не турбуючись, що якийсь інший пристрій помилково вирішить, що поводилися з ним. Але проблема полягає в тому, що SD-карта певним чином інтерпретує дані, що передаються SPI, навіть не будучи вибраним пристроєм. Якщо конкретніше, то при ініціалізації картки потрібно передати 74 або більше одиниць (наприклад, 10 байт 0 x FF) з високою напругою CS. З цієї причини карта або повинна жити на окремій шині, або ініціюватися перед іншими пристроями. Інакше карта може відмовитись працювати, я перевіряв.

бібліотека, що вийшла

У ході вивчення мною протоколу SD-карт було написано бібліотеку для STM32, що реалізує цей протокол. Бібліотека заснована на HAL і має наступний інтерфейс:

#define SDCARD_SPI_PORT hspi1
#define SDCARD_CS_Pin GPIO_PIN_5 // Arduino shield: D4
#define SDCARD_CS_GPIO_Port GPIOB
extern SPI_HandleTypeDef SDCARD_SPI_PORT;

// call before initializing any SPI devices
void SDCARD_Unselect();

// all procedures return 0 on success,< 0 on failure
// size of block == 512 bytes

int SDCARD_Init();
int SDCARD_GetBlocksNumber(uint32_t * num) ;
int SDCARD_ReadSingleBlock(uint32_t blockNum, uint8_t * buff) ;
int SDCARD_WriteSingleBlock(uint32_t blockNum, const uint8_t * buff) ;

// Read Multiple Blocks
int SDCARD_ReadBegin(uint32_t blockNum) ;
int SDCARD_ReadData(uint8_t * buff);
int SDCARD_ReadEnd();

// Write Multiple Blocks
int SDCARD_WriteBegin(uint32_t blockNum) ;
int SDCARD_WriteData(const uint8_t * buff);
int SDCARD_WriteEnd();

SD-карти можуть реалізовувати додаткові функції, такі як очищення блоків і захист блоків від запису. Але вони підтримуються не всіма картами, тому не реалізовані. Також протокол дозволяє увімкнути перевірку контрольних сум. Але ця можливість не реалізована, оскільки дані можуть зіпсуватися не тільки під час передачі, і тому їх цілісність повинна перевірятися вище за рівень протоколу, на рівні конкретного додатка. Додатково обчислюючи і перевіряючи CRC на рівні протоколу, ми, швидше за все, тільки дарма з'їмо міліампери і займемо flash-пам'ять. Та й взагалі, я не переконаний у надійності семибітних CRC.

Висновок

Як джерела додаткової інформації я рекомендував би наступні:

Повну версію вихідних записів до цієї посади ви знайдете на GitHub . Зверніть увагу, що тамтешній приклад коду пише на карту на рівні блоків, нічого не знаючи про які файлові системи. Тому, якщо вирішите його запускати, рекомендую вибрати SD-карту без особливо цінних даних.

Озброївшись здобутими сьогодні знаннями, можна реалізувати багато божевільних ідей. Наприклад, можна зробити RAID із SD-карток, або пристрій з інтерфейсом SD-карти, що стискає та/або шифрує дані. Або взагалі відправляє їх на сервер бездротового зв'язку. Звичайно ж, зовсім не було порушено питання роботи з файловими системами. Йому буде присвячена одна з наступних нотаток.

На цьому у мене поки що все. А чи доводилося вам використовувати SD-карти у своїх проектах, і якщо так, то для яких завдань?