LPCXpresso Урок 11

Використовуємо схему з минулого уроку з підключенням роз'єму USB і додаємо підключення картки. Для цього нам треба зібрати таку схему:

роботи
Можете підпаяти проводки або безпосередньо до картки, яку не шкода, або як я скористатися слотом для картки. Наведена схема однакова як SD і MMC карти. Усі зайві (не показані) висновки MMC картки залишаються непідключеними.

Доопрацьовуємо код

Завдання універсальності собі ставити не станемо. Робитимемо код під конкретну карту пам'яті (обсяг картки). Як основа для даного проекту візьмемо приклад з минулого уроку і доопрацюємо його. Доопрацювання пройде так:

  1. Налаштування SPI
  2. Код для роботи з карткою пам'яті
  3. Доопрацювання функцій читання/запису USB-диску
Для перших двох пунктів звернемося за допомогою до бібліотекиLPC1343 Code Base. Крім цього, треба видалити те, що нам не потрібно. У директоріїsrcпроекту видаляємо файлdiskimg.cта в директоріїincфайлdiskimg.h, т.к. вони нам більше не потрібні. Для цього у файлу викликаємо контекстне меню та вибираємо пунктDelete. На питання видалити чи файл із файлової системи відповідаємо позитивно.

Налаштування SPI

У проекті (не бібліотеці, тому що тут ми її не підключали) створюємо файлssp.hз наступним вмістом:

Оскільки картка пам'яті має ініціалізуватися на швидкості 400кГц, а працювати може і на 20МГц, то функцію ініціалізації напишемо з одним параметром, що задає повільний/високошвидкісний режим роботи SPI. Створюємо файлssp.cз реалізацією функцій. Після підключення заголовних файлів додаємо функції длявибору пристрою.Source Fileпишемоssp.cі тиснемоFinish.

Ці функції потрібні, т.к. ми не будемо використовувати наявний апаратний контроль, а вибиратимемо картку самостійно (через деякі обмеження в протоколі роботи з карткою пам'яті). Далі реалізуємо функцію передачі. У ній ми просто заносимо дані передачі в регістр даних DR контролера SPI. Після цього контролер SPI самостійно запускає цикл обміну. Нам залишається тільки чекати його завершення, про що повідомить нам другий біт в регістрі SR контролера SPI. Після закінчення обміну ми виймаємо з регістру даних DR контролера SPI прийняті дані та повертаємо їх як результат роботи функції.

Тепер приступимо до функції ініціалізації:

Крім уже відомих нам дозволу роботи, подачі тактів і вибору висновків функції для роботи з периферією у нас є так само:

  • встановлення в регістрSSPCLKDIVдільника тактової частоти для контролера SPI (завдання частоти роботи контролера SPI) 10 або 1, залежно від необхідного режиму;
  • встановлення в регістрCR0формату пакета (докладно в документації до контролера) і додаткового дільника (завдання частоти тактової лінії SPI) 8 чи 1, залежно від необхідного режиму;
  • встановлення в регістрCPSRдільника частоти для опорної частоти тактової лінії SPI мінімальне значення 2;
  • видалення сміття з приймального буфера SPI;
  • встановлення в регістрCR1роботи контролера в режимі «майстер» та дозвіл тим самим роботи контролера SPI;
На перший погляд може бути складною система завдання частоти шини SPI. Тому спробую описати послідовно. Системна частота ділитися на дільник урегістріSSPCLKDIVі ця частота задається основною для роботи контролера SPI. Потім вона ділиться на дільник у регістріCPSRдля формування опорної частоти шини SPI (це ще немає частота шини). І, нарешті, опорна частота поділяється на коефіцієнт, задані в полі регіструCR0(+1) для одержання частоти тактового сигналу шини. Переривання нам тут не потрібні, ми власник шини і самі визначаємо коли здійснювати передачу. Тому тут все.

Робота з карткою

Усі імена самі, що були у прикладі. Вкажіть тут кількість блоків вашої картки пам'ятіMSC_BlockCount. Ще раз нагадаю, що SDHC не підтримуються і більше 2Гб не може бути. Також додався виклик ініціалізація картки пам'яті в функціїmainу файліusbmemrom_main.c:

ФункціяSetLedпризначена для цілей діагностики. Так, якщо при ініціалізації карти виникла помилка, то буде запалений світлодіод на платі, індикуючи помилку.

Функції читання/запису

У файліmsccallback.cправимо функції читання та запису блоку диска. Але так як розмір блоку на диску у нас 512 байт, а розмір блоку USB всього 64 байта, то для читання одного блоку диска функція читання буде викликана 8 разів поспіль з різним зміщенням одного і того ж блоку. І так само для запису. Що б не робити кілька читань одного блоку з диска (а тим більше записів), додамо кешування:

Після цього функція читання виглядає дуже просто:

І функція запису така проста, тільки доданий код запису буфера по досягненню кінця блоку:

У коді присутній виклик тієї жSetLedцього разу з метою індикації звернення до карти.

Як зазвичай компілюємо та виправляємо помилки. Післяпідключення доданого роз'єму до комп'ютера світлодіод почне блимати, а в системі з'явиться новий знімний диск. Якщо світлодіод постійно яскраво світиться, що буває, коли на початку був інший код, який збив ініціалізацію карті, то знеструмте плату і знову подайте харчування. Якщо система пропонує вам диск відформатувати, то ймовірно, у вас в коді не вірно вказаний розмір. Хоча можливо, просто картка не була відформатована. Я повторно рекомендую не використовувати картки з важливими для вас даними. Сам я при експериментах вказував і менші і більші розміри, але хто знає як поведеться нестабільна система.

Статистика

Код у Debug версії у мене вийшло 4216 байт коду. Швидкість читання становила 194 кБайт/с, швидкість запису 84 кБайт/с.

картки
роботи
Після перемикання в Release версію код зменшився до 2772 байт. Швидкість читання у своїй зросла до 239 кБайт/с, а записи до 95кБайт/с.
контролера
урок

Замість ув'язнення

З жалем має визнати, що урок вийшов об'ємним та незрозумілим. При цьому при всьому безпосередньо на тему (SPI) пара жалюгідних абзаців. Навіть виключення принципів роботи з карткою пам'яті хоч і скоротило статтю, але недостатньо. Однак, сподіватимусь, що вивчення минулих прикладів навчило вас розбиратися в коді.