Технология программирования ARM Cortex-M0+

503a6ec3d433eb63656b1ab561ef8596.png
Здесь я расскажу об удобном наборе средств и о технологии быстрой разработки простых программ на микроконтроллере S9KEAZN64AMLC с 32-х битным 40 МГц ядром ARM Cortex-M0+. Как аппаратную основу возьмем плату от анонсированного ранее проекта. Плата оказалась на удивление живучей при низких температурах и даже превзошла в этом смысле ожидания.
Начнем с подробного описания создания термометра без использования внешних датчиков и с функцией логера.
Как и положено по законам Мерфи первая же спаянная свежая плата сгорела. Но зато позволила выяснить, что S9KEAZN64 способен выдерживать без пробоя напряжение до 12 В, а стабилизатор LT3973IDD-5#PBF отлично переносит короткие замыкания по выходу и сохраняет стабильное выходное напряжение 5 В при практически нулевой нагрузке. Причиной неудачи оказалась плохая пайка корпуса стабилизатора.
Но это было не всё! Невнимательное изучение документации привело к ошибочной схеме подключения двух сегментов индикатора к линиям PTA2и PTA3 микроконтроллера, они оказались выводами с чистым открытым коллектором, т.е. без верхнего необходимого ключа. Пришлось их запараллелить с выводами PTB7, PTB6 и потерять функциональность которая ранее планировалась для них. Также невнимательность привела к отсутствию фильтрующего конденсатора на выходе источника опорного напряжения U2. Всё это привело к небольшим исправлениям платы, которые я благозвучно называю тюнингом.
b8aa8e2e877ad79d4f0a8686db4c6833.png
(Кликнуть для увеличения)

Привожу заключительную версию платы с микроконтроллером с отмеченным тюнингом.
a15e40c13fde6e0f2bebee264dc99294.png
(Кликнуть для увеличения)


Центральный элемент схемы — микроконтроллер S9KEAZN64AMLC.
У него:

- 32-а вывода, 
- Частота процессорного ядра до 40 Мгц, 
- Частота внутренней шины, связывающей ядро с периферией до 20 Мгц. 
- Объем внутренней FLASH памяти - 64 кБ, 
- Объем ОЗУ - 4 кБ.
- Напряжение питания 5 В

Код программы записывается в микроконтроллер через интерфейс SWD (Serial Wire Debug). Интерфейс SWD составляют две цифровые линии, обозначенные на схеме как: SWD_DIO, SWD_CLK.
Микроконтроллер имеет в себе многоканальный 12-и битный цифро-аналоговый преобразователь, аналоговый компаратор, два канала широтно-импульсных модуляторов, внутренний генератор тактовой частоты с умножителем до 40 МГц, датчик температуры, интерфейсы SPI, I2S, UART.
Микроконтроллер может быть переведен в глубокий сон при сохранении активности АЦП и аналогового компаратора.
Цифровые входы дополнительно защищены от помех встроенными аппаратными фильтрами цифровых сигналов.

Для точного измерения аналоговых сигналов на плате находится формирователь опорного напряжения U2 (ISL21080CIH341Z-TK) с выходным напряжением равны 4.096 В. Это удобно сочетается с диапазоном 12-и битного АЦП равным 4096 отсчётам.

Изначальным назначением платы являлась работа в качестве контроллера автомобильных фар. Поэтому оставлены исходные метки назначения пар контактов на плате. Но они конечно могут выполнять и другие произвольные функции. Перечислю эти пары:
LED — Выход. Подключение внешнего светодиода. Может быть входом.
TERMISTOR — Вход. Подключение внешнего датчика температуры на основе термистора, но может быть и другой датчик с изменяемым сопротивлением.
VAN — Вход. Измерение напряжения от 0 до 30 В
BUTTON — Вход. Подключение кнопки. Может быть выходом или аналоговым входом.
High-Side switch — группа сигналов, предназначенных для управления платой силового многоканального ключа с интерфейсом SPI. При отсутствии такой платы сигналы остаются свободными для других функций.

Микроконтроллер по спецификации способен работать до -40 С°. Во время испытаний он продолжал работать при -42 С°. Меньшую температуру просто не удалось получить.

Для платы была измерена зависимость максимального тока потребления от напряжения питания, со всеми включенными светодиодными индикаторами.
Нормальная работа платы согласно этому графику лежит в диапазоне от 6 до 30 В. После 30 В начинает активизироваться шунтирование супрессора D2 и дальше ток возрастает неограниченно до пробоя супрессора или срабатывания самовосстанавливающегося предохранителя F1 рассчитанного на 1.1 А продолжительного тока.
Включается плата при напряжении 3.5 В, но АЦП нормально функционировать начинает с 5 В, а достаточно низкий уровень шумов в измерениях начинается с 6 В.
82b82d98f2785edb7e93585d4010d700.png
(Кликнуть для увеличения)


SWD интерфейс это то что в корне отличает программирование для ARM от программирования 8-и битных микроконтроллеров таких как Arduino. C SWD интерфейсом программу на микроконтроллере также легко отлаживать словно она выполняется локально на вашем компьютере. Если к этому добавить удобства такой технологии как канал связи и отладки в реальном времени RTT, то возвращаться к 8-и битным микроконтроллером полностью отпадет всякое желание.
На схеме интерфейс обозначен прямоугольником SWD с находящимся рядом с ним контактами P1, P2, P3, P4, P6. Я использую в качестве SWD адаптера J-Link фирмы Segger. Для него у меня есть переходники на более миниатюрные разъемы. Таким переходником я здесь воспользовался для подключения к плате. Питание в данном случае идет от платы к адаптеру J-Link. В адаптере находится буфер-преобразователь уровней с двухсторонним питанием, поэтому нет никакого риска подавать 5-ть вольт на адаптер. Как именно подпаять сигналы адаптера к плате можно узнать, прочитав мануал к адаптеру. Более экономным вариантом могло быть использование адаптеров OpenSDA которые присутствуют на многих дешевых отладочных платах от NXP-Freescale, но в таком случае придется пожертвовать некоторыми фичами J-Link.

904c502f5fe0ecaa563bb9cd23d6faa3.png


Для микроконтроллеров серии Kinetis от бывшей фирмы Freescale существует специальная среда разработки Kinetis Design Studio (KDS). Среда создавалась с намерением избавить разработчика от глубокого изучения руководств по программированию и даташитов.В какой-то мере это получается.Поэтому мы начинаем с KDS. Среда сгенерирует нам исходные тексты процедур инициализации периферии микроконтроллера, структуру директорий проекта и заглушку для функции main, вставит нужные заголовочные файлы и конфигурацию линковщика. В ней же мы можем провести и компиляцию проекта пока не перейдем на более эффективный инструмент.

Создаем поддиректорию Firmware в директории проекта. Запускаем Kinetis Design Studio 3.0.0 IDE и создаем рабочее пространство в Firmware. Потом в меню File→New→Kinetis Project вводим название проекта, скажем — AccTester. Выбираем семейство микроконтроллеров SKEAZN64xxx2
2ea06d2311776c7751a978181dbe3552.png
(Кликнуть для увеличения)

Потом такой диалог:
0c4d3d61e3486c88723977c8d6aeebeb.png
(Кликнуть для увеличения)

Потом мы выбираем компилятор IAR. Можем выбрать и GCC, но дальше статья будет про IAR.
Объяснение можно найти в этом сравнении компиляторов было проведено здесь.

Может понадобится перед этим указать где искать компилятор IAR, или иначе предыдущий пункт может зависнуть.
Сам Add-On IAR для среды Eclipse коей является KDS можно найти здесь. Я использовал версию eclipse-iar-arm-7.20–201510121518.zip. Add-On надо поставить до того, как начнем создавать проект в KDS
ec5e7b70e9de448706fbc6b8ff5b680a.png
(Кликнуть для увеличения)

В результате получаем такое окно проекта:
3ebd24e91e127d25b921e0322f2d64b6.png
(Кликнуть для увеличения)

Выбираем правильный корпус чипа (Select Package в закладке Processor), так как у SKEAZN64 есть несколько вариантов корпусов:
32d592fc4209f73bd5a85d11f1916ef1.png
(Кликнуть для увеличения)


К нашему удобству инициализация тактовой частоты по умолчанию полностью нас устраивает и ничего менять не надо. Но частота по умолчанию установится 32 Мгц. Этого более чем достаточно. Надо внимательно изучить закладку Clock source settings показанную на скриншоте ниже. Все должно быть так.
f9524644e5cb1f48de6228ff6aa54aec.png
(Кликнуть для увеличения)
В закладке Components Library выбираем и вставляем в проект Init_GPIO и Init_PORT
У микроконтроллеров Kinetis как всегда есть разделение функций пинов на два периферийных модуля: PORT и GPIO. PORT отвечает за общие свойства порта такие как сила драйвера, включение линий порта и фильтры на линиях порта. GPIO отвечает за оперативное управление состояниями пинов по отдельности и всех вместе.
Поэтому надо конфигурировать правильную инициализацию в обоих модулях.
C Processor Expert нельзя торопится и пытаться всё сразу сконфигурировать. Можно легко запутаться в неясных параметрах и настройках. Для начала надо разобраться в настройках генератора тактовой частоты ядра и шины микроконтроллера. Потом попытаться вывести простейший внешний сигнал. Таким сигналом будет загоревшийся сегмент на 7-и сегментном индикаторе.

В модуле PORT инициализируем пины PTD1 и PTC6. В модуле GPIOA устанавливаю 1 на этих пинах.
Жмём Project→Generate Processor Expert Code,
a3aca13325959e916e9ef32e9bad379f.png
(Кликнуть для увеличения)

потом Buil All.
b1d79f8679b478c0b8d328867cce9383.png
(Кликнуть для увеличения)

Если процесс проходит без ошибок, выбираем Run→Flash from file… и F11 (Debug)
b36ab7c43b7dc12c01c6350c92872137.png
(Кликнуть для увеличения)

Сегмент зажегся


Для дальнейшей разработки программ нам понадобятся еще АЦП, интерфейс SPI, и таймеры.
Перетаскиваем нужную периферию из панели с закладкой Components library в панель с закладкой Components
Должен получится такой состав:
1d5541ec9296f4db276eb9eede1aaaaf.png
(Кликнуть для увеличения)

Здесь GPIOA и PORT уже осуждали. Добавились компоненты PIT, SysTickInit, ADC, SPI0
Добавление этих компонентов вызовет генерацию исходных текстов для инициализации соответствующей периферии.
А назначение компонентов в контексте этого проекта такое:
PIT — периодический генератор прерываний. Предназначен для формирования сигналов старта преобразования АЦП.
SysTickInit — системный таймер ядра ARM. Используется нами для периодического формирования прерываний в которых производится сканирование дисплея.
ADC — АЦП. В первом проекте мы будем оцифровывать не внешний сигнал, а сигнал внутреннего датчика температуры.
SPI0 — интерфейс SPI с номером 0. Нужен для управления SPI ключом.

Здесь я уже не привожу скриншоты инициализации каждого из компонентов. В исходниках, выложенных на github можно будет открыть проект KDS и все рассмотреть.

Сильно увлекаться конфигурацией разной периферии в Processor Expert не стоит. Дело в том, что этот инструмент не инициализирует все зависимости периферии. Например, АЦП нам понадобится запускать по аппаратному триггеру, но правильно его настроить в Processor Expert не удастся, поскольку нет установки канала аппаратного триггера в регистре SIM_SOPT.
Это несколько усложняет задачу. Заглянуть в руководство по программированию семейства KEA придется уже скоро. Но не до того, как я закончу эту статью.


Нажимаем очередной раз на команду генерации исходников и включаем среду разработки IAR Embedded Workbench.
Тут у многих знакомых с IAR может возникнуть чувство дискомфорта. Ведь в IAR заново и с нуля надо будет сформировать дерево всего проекта, да еще проекта с неизвестной структурой директорий. На помощь приходит моя утилита формирования дерева проекта для IAR.
a025b8b61caddae7661f69738fc3632e.png
(Кликнуть для увеличения)

В директории IAR_Proj вместе с рабочим пространством IAR находится файл IARC.exe. Это утилита автоматического формирования дерева проекта для IAR. Используется она следующим образом:
1. Если ещё не создано рабочее пространство IAR то оно создается в IDE IAR командой File→New→Workspace. Даём ему имя AccTester для определенности.
2. В рабочем пространстве создаем пустой проект Project→Create New Project…
e765284053e205856dba13b86fa92369.png
(Кликнуть для увеличения)

называем его тем же именем что и рабочее пространство.
3. В проекте создаем пустую группу и называем ее произвольно. Сохраняем проект. Получаем файлы с расширением .eww и .ewp и одинаковым именем.
32e07dbdc1364db1313585c9ed2a488a.png
(Кликнуть для увеличения)

4. Запускаем утилиту IARC.exe. Утилита хранит свои настройки в Ini.JSON и EscDirs.JSON. На скриншоте она сконфигурирована на преобразования проекта с именем AccTester.ewp и сканирование дерева директорий с корнем C:\Embedded\Projects\AccTester\Firmware_IAR\AccTester
5. Нажимаем кнопку Exec.
6. Программа проходит рекурсивно все директории начиная от корня и пропуская исключённые директории. Все найденные С-и и .h файлы будут включены в файл проекта IAR соответствующим образом.
7. Открываем файл рабочего пространства .eww в IAR. В нем увидем дерево проекта с групами повторяющими структуру директорий. Дальше можем продолжать настраивать опции проекта: выбрать тип микроконтроллера, настроить тип библиотек, отладчик и т.д.

В директории IAR_Proj уже находится подготовленное рабочее пространство IAR которое можно изучить.

Важно то что, настроив таким образом IAR мы не теряем возможности продолжать использовать Processor Expert. Только каждый раз после новой генерации исходников и если это вызывает появление новых файлов нужно снова запустить IARC.exe и нажать кнопку Exec. Проект в IAR после этого требуется полностью перекомпилировать, но это занимает доли секунды.


Проект IAR настраивать долго не придется. Самое важное правильно установить тип микроконтроллера в окне options:
5ded914a396655050ee95fa3833b3af4.png
(Кликнуть для увеличения)

Оптимизация по умолчанию будет минимальной.
Файл карты памяти с расширением .icf IAR использует из своей собственной директории и это нам подходит.
В закладке отладчика нужно выбрать J-Link.
41f12821b54647132ef0bc0a9493ffbf.png
(Кликнуть для увеличения)

IAR имеет свой модуль загрузчика для микроконтроллера, только укажем, что им надо воспользоваться. Отмечаем галочку Use Flash Loader:
2f760d8e0f0e5a4c1b8146b8750ef87b.png
(Кликнуть для увеличения)


Processor Expert умеет генерировать процедуры инициализвции и в нём же можно указать флаги генерации обработчиков прерываний от периферии. Но сгенерированные обработчики появляются в исходных текстах для соответствующей периферии закоментированные. Поэтому были вручную перенесены обработчики прерываний из файлов ADC.c и SysTick.c в файл Events.c и раскоментированы.

Важно. Если планировать дальше использовать Processor Expert совместно с IAR, то нужно хорошо знать какие файлы будут
перезаписаны, а в каких файлах введенная нами информация сохранится.
Перезаписаны будут все файлы в директории Generated Code.
Файл main.c также перезаписывается, но в нём остается нетронутой строчка после соответствующего коментария.
Вот как это выглядит:

/*lint -save  -e970 Disable MISRA rule (6.3) checking. */
int main(void)
/*lint -restore Enable MISRA rule (6.3) checking. */
{
  /* Write your local variable definition here */

  /*** Processor Expert internal initialization. DON'T REMOVE THIS CODE!!! ***/
  PE_low_level_init();
  /*** End of Processor Expert internal initialization.                    ***/

  /* Write your code here */
  Application();

  /*** Don't write any code pass this line, or it will be deleted during code generation. ***/
  /*** RTOS startup code. Macro PEX_RTOS_START is defined by the RTOS component. DON'T MODIFY THIS CODE!!! ***/
  #ifdef PEX_RTOS_START
    PEX_RTOS_START();                  /* Startup of the selected RTOS. Macro is defined by the RTOS component. */
  #endif
  /*** End of RTOS startup code.  ***/
  /*** Processor Expert end of main routine. DON'T MODIFY THIS CODE!!! ***/
  for(;;){}
  /*** Processor Expert end of main routine. DON'T WRITE CODE BELOW!!! ***/
} /*** End of main routine. DO NOT MODIFY THIS TEXT!!! ***/

/* END main */

Здесь я добавил только строку Application(); чтобы передать управление в свою процедуру в файле Indicator.c
Больше в файле main.c я ничего не меняю.

Processor Expert также создает множество фалов в директории Static_code\PDD. Практической пользы от них мало, я их не использую. В них по сути обертки доступа к регистрам периферии к которым можно обращаться и напрямую. Смысл таких файлов в переносимости проектов с одного типа микроконтроллеров на другой внутри одного семейства. Они нужны скорее для разработчиков самого Processor Expert, чем для конечных пользователей, у которых нет такой острой нужды оперативного переключения между микроконтроллерами в рамках одного проекта.

Вся логика приложения у меня сконцентрирована в файле Indicator.c. В нем находятся и главный цикл, и все обработчики прерываний. Программа слишком маленькая чтобы ее разбивать на отдельные файлы.

А вот так выглядит сам основной цикл приложения:

void Application(void)
{
  unsigned int uuid[2];
  ADC_prepere();
  Clear_display();
  // Выводим в интерфейс RTT информацию о чипе и его уникальный идентификатор
  Get_unique_identificator(uuid);
  RTT_printf("\r\n\r\nS9KEAZN64AMLC (64 KB FLASH, 4 KB RAM) UUID=%08X-%08X\r\n", uuid[0], uuid[1]);

  // Входим в основной цикл
  for (;;)
  {
    if (meas_done != 0) // Ожидаем установки флага из обработчика прерываний АЦП
    {
      // приводим значение взятого отсчета АЦП к напряжению с типом float
      if (INTTEMPER_adcr > T25SMPL)
      {
        //  Ниже 25 С
        int_temperature = 25 - (INTTEMPER_adcr - T25SMPL) / (1000.0 * TSLOPE_LOW);
      }
      else
      {
        // Выше 25 С
        int_temperature = (T25SMPL - INTTEMPER_adcr) / (1000.0 * TSLOPE_HIGH) + 25;
      }
      Show_float("%0.1f", int_temperature);     // Вывод на  дисплей
      RTT_printf("%0.3f\r\n", int_temperature); // Вывод в интерфейс RTT с повышенной разрядностью числа
      meas_done = 0; // Сбрасываем флаг, чтобы ждать следующей его установки
    }
  }
}


В качестве датчика температуры используется внутренний температурный сенсор чипа. Логирование результатов измерения производится в интерфейс RTT.
На компьютере интерфейс RTT виден как telnet порт вида: telnet://localhost:19021
К этому порту можно подключиться, например, с помощью программы эмулятора терминала TeraTerm такой строкой:

"C:/Program Files (x86)/teraterm/ttermpro.exe"  /T=1 telnet://localhost:19021  /X=0 /Y=0   /W="Jlink RTT"  

Но надо помнить, что этот порт открыт только при работе отладчика IAR через адаптер J-Link.
При отключении адаптера порт сразу же закрывается.

Вот так выглядит вывод в терминал.
e150496c2aae51d0288e4cfcf70c939a.png
(Кликнуть для увеличения)

Первые три строчки выводятся самим адаптером J-Link.

На этом пока все. Удачных экспериментов с ARM Cortex-M0+!

f3621dea07d8faee42aad25b0a394cb3.png
(Кликнуть для увеличения)

Все исходники по прежнему доступны на https://github.com/Indemsys/Light-Control-Module-PCB

© Geektimes