Слід знати, що в режимі SPI підтримуються тільки команди читання / запису в режимі одного блоку або декількох блоків (в режимі MMC підтримується режим послідовної читання / запису). Розмір блоку для читання / запису може бути розміром в сектор карти пам'яті і розміром в 1 байт. Підтримка операцій часткового читання / запису блоку даних зберігається в регістрі CSD карти пам'яті.
Мало не забули поговорити про регістрах, які містить карта пам'яті стандарту MMC (SD). Цихрегістрів трохи більше, ніж перерахую я, але ті, які я не вкажу або не особливо потрібні, або не доступні в режимі SPI. Основними регістрами, які представляють для нас інтерес є наступні:
- CID (Card identification data): містить дані, за якими можна ідентифікувати карту пам'яті (серійний номер, ID виробника, дату виготовлення і т.д.)
- CSD (Card-specific data): містить всіляку інформацію про карту пам'яті (від розміру сектора карти пам'яті до споживання в режимі читання / запису).
- OCR (Operation Conditions Register): містить напруги живлення карти пам'яті, тип харчування карти пам'яті, статус процесу ініціалізації карти.
Багато хто, напевно, помітили, що в таблиці пропущені деякі команди. Як я говорив раніше, в режимі SPI недоступні деякі функції, які доступні в режимі MMC. Тому деякі команди так само не доступні. Так само з таблиці видно, що у всіх команд в поле «Resp» присутній абревіатура R1 (2, 3, 7 та ін.). Це і є так званий відповідь карти на що посилається їй команду. Наведу невеликий приклад обміну інформацією з картою пам'яті для ілюстрації описаного вище.
Розглянемо докладніше цей приклад. Ми бачимо, що ми відправляємо карті (лінія DataIn) деякою команду, прийнявши яку, карта через деякий проміжок часу видасть відповідь (лінія DataOut). Розмір відповіді залежить від посилається команди і має свій формат. Наведу формат відповідей, які ми можемо отримати від карти пам'яті.
Тепер торкнемося самих команд для карти пам'яті. З таблиці команд видно, що у кожної команди є свій індекс. Використовуйте цей параметр для отримання істинного значення команди, яку необхідно відправити в карту пам'яті. Загальний вигляд команди представлений нижче (команда в режимі SPI має довжину в 6 байт):
Варто відзначити, що в протоколі MMC весь обмін даними завершується полем CRC, яке є необхідним. Що стосується режиму SPI, то за замовчуванням при переході в цей режим, контроль CRC відключений. Виняток становлять команди CMD0 і CMD8, оскільки вони відправляються в карту, яка ще перебуває в режимі MMC, тому поле CRC для цих команд має бути вірним. Оскільки CMD0 відправляється один раз і все 6 байт цієї команди відомі заздалегідь і не змінюються, то в поле CRC для будь-якої команди ми будемо відправляти CRC для команди CMD0 (воно дорівнює 0x95). Що стосується CMD8, то поле CRC в ній не є константою і залежить від переданих параметрів. Хочу зауважити, що перевірку поля CRC можна активувати і в режимі SPI. Робиться це за допомогою відповідної команди (CMD59).
Трохи розібравшись з теорією, подивимося на процес ініціалізації карти пам'яті. Спробую представити це у вигляді блок-схеми. Ось що вийшло у мене вимутіть з datasheet'а (викладаю тільки суть, за вирахуванням деяких моментів, які я розпишу після блок-схеми):
Ну ось, скажуть деякі, намалював не зрозумій чого, а ви тут розбирайтеся;) Але все не так вже й погано. Перше, що необхідно чітко вказати в цій схемі це те, що карти як би того не хотілося, бувають різні (тому напевно вони і називаються по різному). І на цій схемою ми бачимо, що буває їх ні багато ні мало, а цілих 4: MMC, SD версії 1.х стандартної ємності, SD версії 2.х стандартної ємності і карта SD версії 2.х підвищеної ємності (SD карти розширеної ємності або SDHC). Все б нічого, але всі вони вимагають різної ініціалізації і це найприкріше. В принципі, є загальний спосіб ініціалізації всіх їх крім SDHC, але він не є правильний, оскільки працювати з картою SD версії 2.х стандартної ємності і картою MMC як з однаковими картами неправильно (відмінність у структурах CID і CSD). Звичайно, можна побудувати алгоритм для роботи з кожною картою окремо, але ми підемо універсальної дорогий (і найважчим на перший погляд).
З наведеної структури намічається наступний шлях роботи (я буду вказувати основні моменти, які необхідно виконувати, але вони не вказані на даній схемі). Ми визначили, що в роз'єм картоприймача вставили якусь фігню. Ми в свою чергу робимо наступне: подаємо харчування в межах від 2.7-3.6 В, очікуємо
1мс (точно не знаю скільки, але щоб харчування вляглося). SPI налаштований як годиться (я думаю всі вміють це робити) і висновок _CS карти пам'яті виставлений в логічну "1". Після цього нам необхідно подати мінімум 74 тактових імпульсу на лінію SCLK SPI. Виконавши все це ми виставляємо логічний "0" на висновок _CS карти пам'яті і відсилаємо команду CMD0. З таблиці команд бачимо, що відповіддю на CMD0 є R1, структуру якого ми знаємо. Трохи відступлю від думки і зверну увагу на те, що всі відповіді містять в собі першим байтом R1, 7-й біт якого завжди є 0. Таким чином, ми можемо відрізняти відповіді від що йде по лінії MISO байтів 0xFF. Отже, прийнявши R1, перевіряємо біт «In idle state» на рівність «1». Якщо це так, то карта знаходиться на етапі ініціалізації. А ось тепер прийшов перший етап визначення типу карти пам'яті. Надсилаємо команду CMD8, яка вказує мапі підтримувані МК напруги живлення для її і запитує у вибраній карти чи може вона працювати в даному діапазоні напруг, чекаємо відповіді R7. Як видно з блок-схеми, карти пам'яті стандарту MMC і SD версії 1.х цю команду не підтримують і, відповідно, в своїй відповіді будуть містити біт «illegal command». Якщо сказане раніше вірно, то встановлена карта або MMC, або SD версії 1.Х. Тепер прийшов час розпізнати, яка саме з цих двох типів карт вставлена в картоприймач. Для цього відправимо карті пам'яті команду ACMD41, яка ініціює процес ініціалізації карти. Ця команда посилається в циклі або для її виконання зводиться таймер, по якому перевіряється відповідь на цю команду. У будь-якому випадку, карта MMC не підтримує ACMD41 і поверне «illegal command» в своїй відповіді. В такому випадку вставлена карта є MMC і для її ініціалізації потрібно команда CMD1 (так само посилається в циклі, поки відповідь на неї не буде дорівнює 0). Отримавши відповідь на CMD1 рівний 0х00 карта MMC готова до роботи. Якщо відповідь на ACMD41 не містить ніяких встановлених бітів (тобто дорівнює 0х00), то карта SD версії 1.х і вона готова до роботи. Тепер повернемося трохи вище і припустимо, що у відповідь на команду CMD8 не містив біт «illegal command», тобто у нас карта пам'яті формату SD версії 2.х стандартної ємності (SDSC версії 2.х) або SDHC. Наступним кроком в такому випадку є відправка команди ACMD41 з параметром, що вказує карті пам'яті, чи підтримує наше обладнання карти пам'яті SDHC. Незалежно від того, є підтримка SDHC або її немає, ми циклічно відправляємо цю команду карті то тих пір, поки вона (карта) закінчить процес ініціалізації. Коли відповідь від ACMD41 буде дорівнює 0х00, карта пам'яті проініціалізувати і готова до роботи. Але для того, щоб дізнатися, яка у на карта, ми відправимо їй команду CMD58. Відповіддю від цієї команди є R3, який в свою чергу містить регістр OCR. Проаналізувавши OCR на установку біта CSS можна визначити тип карти: CCS == 1 - карта SDHC або SDXC, CCS == 0 - карта SDSC. Щоб не бути голослівним, наведу мою ділянку коду ініціалізації карти пам'яті:
P.S. Забігаючи трохи вперед, пару скроневої читання інформації з карти пам'яті: