Industrial Programming
Programming microcontrollers
Manufacture and development of electronics
30 August 2018

Портирование Arm Mbed OS на специализированный контроллер



Arm Mbed OS — популярный проект с открытым исходным кодом ускоряющий разработку устройств для интернета вещей (IoT). Если вы создали свое уникальное процессорное устройство, то первой задачей будет портирование на него какой либо операционной системы (OS).

Здесь представлена пошаговая инструкция по запуску Arm Mbed OS на плате с микроконтроллером семейства NXP Kinetis.

Проект Arm Mbed OS

является собственность фирмы ARM и предназначен только для архитектуры ARM. Вопреки распространенному мнению Mbed не написан полностью на C++, не заточен исключительно для Cortex-M и не такой уж новый. Его истоки лежат в далеких 90-х когда фирма Keil создала RTX — операционную систему реального времени (RTOS) для I8051. Впоследствии RTX была Keil-ом перенесена на ARM7 и ARM9, а потом появились Cortex-ы.

Фирма ARM приобрела Keil и RTOS получила название CMSIS-RTOS. Она все еще была целиком написана на С. И наконец с приходом бума IoT и Arduino появился Mbed. Веяния Arduino подвигли сделать оболочку на C++ и упрощенное API со знакомым набором из нескольких десятков пинов, UART-ом и светодиодом, а IoT наполнил проект стеками TCP/IP, Bluetooth Low Energy, 6LoWPAN, Thread… Но RTX5 по прежнему сидит в глубине исходников Mbed OS.

Марка Keil продолжает существовать и в дистрибутиве средств разработки Keil можно найти CMSIS-RTOS с большим выбором промежуточного ПО и примеров портирования на больший ассортимент семейств микроконтроллеров чем предлагает Mbed. Однако это закрытый коммерческий проект.

Специализированная плата,


на которую производится портирование взята здесь для примера и ее схема не имеет большого значения. Важнее микроконтроллер который на ней установлен. Это MKE18F512VLL16 семейства Kinetis фирмы NXP. Основные его параметры:
Ядро — ARM Cortex-M4F 32-Bit
Максимальная частота ядра — 168MHz
Flash 512KB (512K x 8)
RAM 64 KB
100-LQFP (14x14)

Содержимое микроконтроллера




Этого микроконтроллера нет в списке поддерживаемых ARM Mbed OS. Можно объяснить тем, что он сравнительно новый.

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



Шаг 1. Скачивание инструментов NXP


  • Конфигурируем онлайн на сайте www.nxp.com свой вариант MCUXpresso Software Development Kit (SDK) для семейства MKE18F512xxx16
  • Когда нужно указать Toolchain/IDE выбираем IAR IDE. Далее будет рассматриваться работа именно в IAR IDE.
  • Выбираем все доступные Software Components.
  • Скачиваем полученный MCUXpresso Config Tools, Windows 64bit package с сайта.

    Это будет 30-и мегабайтный архив MKE18F512xxx16.zip с таким содержимым:

  • — Скачиваем также MCUXpresso Config Tools v4.1 for Windows. С помощью него настроим подсистему тактирования микроконтроллера.

Шаг 2. Получение проекта приложения без RTOS


  • Запускаем MCUXpresso Config Tools v4.1 for Windows

  • В качестве шаблона выбираем один из самых простых проектов демонстрационных примеров — led_blinky.

  • Настраиваем схему тактирования и даем команду на генерацию исходников инициализации тактирования. Исходники инициализации обновляются прямо в директориях проекта.

  • Копируем полученный проект с исходниками под IDE IAR в свою директорию. В проекте выбираем отладчик J-Link, канал отладки через интерфейс SWD. Модифицируем команды записи в порт светодиода, компилируем и заливаем на плату.


Шаг 3. Конфигурирование и конвертация проекта Mbed


  • Заходим на сайт проекта Mbed в раздел платформ — os.mbed.com/platforms.

    Там ищем плату с микроконтроллером максимально похожим на выбранный нами.
  • Выбираем плату FRDM-K66Fos.mbed.com/platforms/FRDM-K66F. Выбор не случайный, с подобным микроконтроллером есть опыт работы.
  • На странице с презентацией платы решаем выбирать демонстрационный пример — mbed-os-example-blinky — os.mbed.com/teams/mbed-os-examples/code/mbed-os-example-blinky/?platform=FRDM-K66F

    Это самый простой пример и его будет легче всего адаптировать для другой платы.
  • Регистрируемся и заходим в раздел on-line компилятора — os.mbed.com/compiler
  • Для начала выбираем платформу — FRDM-K66F, а потом импортируем выбранный нами демонстрационный пример — mbed-os-example-blinky. В панели Programs этот демонстрационный пример будет иметь название mbed_blinky.

  • Компилируем для проверки данный пример, а потом экспортируем его.

Экспортируем в формате предназначенном для IDE IAR



Теперь мы получили исходники рабочего проекта Mbed для IAR. Однако полученный проект неудобен для работы.

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



Шаг 4. Преобразование проекта IAR в нормальную форму


— С помощью специально написанных утилит на Python проводим несколько операций преобразования.

Во-первых, удаляем из директорий демонстрационного проекта все исходники, не попавшие в проект. Перечень исходников получаем из файла mbed-os-example-blinky.ewp. Утилита называется Clear_from_unused_files_and_dirs.py. Она также удаляет пустые директории, образовавшиеся после удаления файлов.

Во-вторых, с помощью утилиты Convert_ewp_file.py мы переконфигурируем файл проекта mbed-os-example-blinky.ewp так чтобы группы в нем соответствовали директориям проекта. Получаем проект уже с более понятной структурой, где можно удалять или добавлять пакеты. Тут же можем переименовать проект. Для этого редактируем тэг
<configuration> <name>mbed-os-example-blinky</name> 
в файле mbed-os-example-blinky.ewp. Изменяем название файла mbed-os-example-blinky.ewp ( в данном случае Test_proj.ewp), исправляем тэг
<path>$WS_DIR$/mbed-os-example-blinky.ewp</path> 
в файле mbed-os-example-blinky.eww ( в данном случае на Test_proj.ewp) и изменяем название файла mbed-os-example-blinky.eww на выбранное нами ( в данном случае Test_proj.eww)



В результате имеет такую структуру проекта





— Изучаем исходники чтобы определить те из них, которые зависят от особенностей микроконтроллера. Для этого удобнее использовать более специализированные редакторы, например SlickEdit или Eclipse. Редактору также стоит сообщить о макросах, объявленных в настройках IDE. Для этого создаем дополнительный заголовочный файл Extra_options.h и копируем туда содержимое Extra Options из IDE IAR.



Шаг 5. Редактирование проекта Mbed


Мы готовы к редактированию проекта. Начнем с анализа макросов в файле Extra_options.h. Это делаем в редакторе с соответствующими возможностями, можно делать и в среде IAR.

— Удаляем неиспользуемые макросы, чтобы они не отвлекали внимания при дальнейшем анализе. Остальные сортируем. Около половины макросов оказалось неиспользуемыми.

— В Extra Options вводим новый макрос — TARGET_MKE18F. Он определяет начальный адрес стека в файле mbed_rtx.h. Стек растет в сторону уменьшения адресов. В Mbed принято стек начинать с верхней границы доступной RAM. Для MKE18F ставим эту границу равной 0x20008000UL

— Находим директорию TARGET_K66F. Там хранятся файлы, зависящие от типа микроконтроллера. Их там довольно много — 136 файлов. Создаем рядом с директорией TARGET_K66F свою с названием TARGET_MKE18F .

— Из директории демонстрационного проекта SDK led_blinky\CMSIS копируем в директорию Mbed-os\targets\TARGET_Freescale\TARGET_MCUXpresso_MCUS\TARGET_MKE18F\device файлы:
• fsl_device_registers.h. (макрос CPU_MK66FN2M0VMD18 в Extra Options заменяем на CPU_MKE18F512VLL16)
• MKE18F16.h
• MKE18F16_features.h
• system_MKE18F16.h
• system_MKE18F16.c

— Удаляем файлы
• MK66F18.h
• MK66F18_features.h
• system_MK66F18.c
• system_MK66F18.h

— В директории TOOLCHAIN_IAR заменяем содержимое на файлы startup_MKE18F16.s и MKE18F512xxx16_flash.icf.
— В проекте IDE IAR также для линкера указываем путь к новому файлу MKE18F512xxx16_flash.icf
— Содержимое директории Mbed-os\targets\TARGET_Freescale\TARGET_MCUXpresso_MCUS\TARGET_MKE18F\drivers стираем и заполняем файлами из директории devices\MKE18F16\drivers находящейся в SDK семейства MKE18F512xxx16
— Заменяем файл \mbed-os\targets\TARGET_Freescale\TARGET_MCUXpresso_MCUS\fsl_common.c на аналогичный из директории devices\MKE18F16\drivers, находящейся в SDK семейства MKE18F512xxx16. В директории Mbed-os\targets\TARGET_Freescale\TARGET_MCUXpresso_MCUS\TARGET_MKE18F\drivers такой же файл удаляем.
— Из директории mbed-os\targets\TARGET_Freescale\TARGET_MCUXpresso_MCUS\TARGET_MKE18F\drivers удаляем файлы в названии которых присутствует FreeRTOS.
— Из директории \mbed-os\features\netsocket\emac-drivers удаляем все файлы связанные с периферией EMAC микроконтроллера K66, поскольку в новом микроконтроллере нет EMAC.
— Cнова применяем утилиту Convert_ewp_file.py
— Компилируем и получаем 267 ошибок. Они все в файлах, находящихся в директории TARGET_MCUXpresso_MCUS и имеющих в большинстве своем в названии суффикс api. С каждым файлом надо разбираться по отдельности. Всего появляется 12 файлов с ошибками.

Шаг 6. Редактирование файлов Mbed


Файл fsl_clock_config.c


Это самый важный файл на данном этапе. В нем происходит инициализация тактирования всех подсистем чипа. Функция инициализации RTOS mbed_sdk_init вызывает из этого файла функцию BOARD_BootClockRUN. Заменяем файл fsl_clock_config.c на проверенный файл из проекта led_blinky. Там он называется clock_config.c (переименовываем после копирования в fsl_clock_config.h и исправляем #include в нем там где надо ), а вызов функции BOARD_BootClockRUN в файлах RTOS заменяем на BOARD_BootClockHSRUN, поскольку хотим завести чип на максимальной частоте 168 МГц.

— Рассматриваем оставшиеся файлы. Сразу вызывают сомнения их необходимость. Действительно многие из них представляют собой простые обертки над функциями работы с периферией с упрощенным интерфейсом. Скорее всего, они сделаны для аудитории начинающих программистов, для которых важно подобие API системам на базе Arduino. Мы можем пренебречь этими файлами как не несущими полезной нагрузки, хотя за это нас не примут в сообщество Mbed.

Удаляемые файлы:
API
• analogin_api.c
• analogout_api.c
• dma_api.c
• i2c_api.c
• pwmout_api.c
• spi_api.c
• dma_api_hal.h

Drivers
• AnalogIn.cpp
• I2C.cpp
• I2CSlave.cpp
• SPI.cpp
• SPISlave.cpp
• AnalogIn.h
• AnalogOut.h
• I2C.h
• I2CSlave.h
• PwmOut.h
• SPI.h
• SPISlave.h

HAL
• analogin_api.h
• analogout_api.h
• i2c_api.h
• pwmout_api.h
• spi_api.h

  • Редактируем файл mbed.h чтобы закомментировать подключение файлов которые мы удалили. Также редактируем object.h .
  • Отредактируем функцию mbed_die вызываемую при крахе системы. По умолчанию она мигает светодиодом. Удаляем мигание, у нас такого светодиода нет.
  • Очищаем файлы PinNames.h и PeripheralNames.h от объявлений пинов и структур, связанных с удаленными перед этим файлами api
  • Удаляем ненужные массивы в файле PeripheralPins.c, после этого остается только отредактировать в нем карту пинов для UART-ов.
  • Немного меняем структуру директорий и расположение файлов в поддиректории targets, чтобы уменьшить хаотичность именований и разрозненность файлов.

Список оставшихся файлов, требующих коррекции:
• serial_api.c
• trng_api.c
• flash_api.c
• sleep.c
• us_ticker.c

Эти файлы нельзя просто удалить, так как от них зависят важные сервисы RTOS. Проблема в основном в том, что в семействе MKE18F512xxx16 применяется другое именование периферии чем в MK66FN2M0VMD18, хотя периферия для основных API практически осталась неизменной.

Файл serial_api.c


В нем в основном меняем имена функций и перечислений, доставшиеся от чипа K66. Данный файл определяет низкоуровневые функции для отладочного вывода RTOS через UART.

Файл us_ticker.c


важен тем, что определяет механизм получения точного времени в тиках для RTOS( в нашем примере значение тика равно 1 мкс). Это API используется в функциях задержки RTOS и в сервисах очереди событий с заданным временем активизации на шкале времени. Для организации непрерывного счетчика времени используются связанные каналы 0 и 1 модуля PIT. Канал 0 имеет период в 1 мкс, канал 1 заканчивает цикл через 429 сек (в него загружается 0xFFFFFFFF, счетчик канала декрементируется). Для организации очереди событий используются каналы 2 и 3 модуля PIT с прерываниями от канала 3. Таким образов выясняется, что Mbed занял весь модуль PIT и его больше ни для чего другого использовать нельзя.

Файл trng_api.c

реализует аппаратную генерацию случайных чисел. В чипе MKE18F512xxx16 нет такого генератора, поэтому ставим заглушки из стандартной С функции rand. Хороший генератор случайных чисел нужен для протоколов шифрации данных SSL и TLS. Пока такие применять не планируем на нашей плате.

Файл sleep.c

реализует функции входа и выхода из sleep режима. При этом затрагивается работа ускорителя работы с Flash памятью. Нужно скорректировать названия функций, разрешающих и запрещающих кэш Flash памяти.

Файл flash_api.c

реализует функции для программирования внутренней Flash памяти. Здесь натолкнулись на то, что в чипах семейства MKE18F512xxx16 могут быть два раздела Flash памяти. Выбрали работу с разделом 0.

— Корректируем макросы со значениями внутренних частот чипа в файле system_MKE18F16.h

Файл линкера MKE18F512xxx16_flash.icf.


В нем должно быть объявление символа __VECTOR_RAM. Это адрес с которого будет размещаться таблица векторов прерываний в RAM. В Mbed OS таблица векторов прерываний всегда копируется из Flash в RAM поскольку она в течении работы может программно модифицироваться системой.

Курьёз


Уперлись в то, что на векторе SVC_Handler стоит заглушка и зациклена на себя. А инициализация Mbed OS вызывает именно этот вектор. Где-то пропущен момент установки правильного вектора. Оказывается забыли подключить к IAR ассемблерные файлы с расширением с большой буквой S. А там самый важный файл с переключателем контекста — irq_cm4f.S. Спасибо Python-у. Исправляем утилиту Convert_ewp_file.py и снова запускаем. Перекомпилируем проект.

Как оживить мертвый чип


Инициализируя порты GPIO можно случайно неправильно инициализировать линии ввода/вывода для отладчика и кварца. В этом случае чип перестает отлаживаться и даже перестает программироваться SWD адаптером J-Link. В нашем случае решить проблему можно просто. Закорачиваем один вывод внешнего кварца на землю, снимаем питание и снова подаем. Наша программа не дойдет до неправильной инициализации GPIO поскольку застрянет на ожидании включения кварца. В это время становится вновь доступным программирование SWD адаптером.

Проблема неправильного времени задержки функции wait


Измерив период мигания светодиода обнаружилось замедление выполнения функции wait дольше чем положено ровно в два раза. Для проверки правильности настроек внутренних частот инициализируем выдачу на внешний вывод клока внутреннего PLL деленного на 8. Видим частоту 21 МГц. Все правильно.

При инициализации частоты тиков RTX параметры которой задаются в файле RTX_Config.h используется переменная SystemCoreClock, а она в свою очередь присваивается в функции BOARD_BootClockHSRUN при инициализации системы и равна 168000000. Тут тоже все правильно.

Проверено в окне TimeLine отладчика IAR частота прерываний системного тика, она равна 1 КГц, тоже правильно.

Оказалась был неправильно инициализирован модуль PIT. Он переставал считать когда RTX переходил в режим SLEEP. А в этот режим RTX переходит при каждом тике если нет активных задач. Таким образом таймер останавливался, но его значения использовались в функции wait чтобы обеспечить максимально точную задержку. А ведь эту ошибку мы унаследовали от официального порта Mbed для K66!

На третий день портирование ARM Mbed OS успешно завершено и светодиод мигает.
github.com/Indemsys/Mbed_led_blinky_MKE18F


+14
5.1k 44
Comments 2