[Из песочницы] Адское программирование голого железа

habr.png

Доброго времени суток! Обидно мало статей посвящено адскому программированию замечательному языку программирования Ада, а уж тем более нет их по программированию на нем для микроконтроллеров. А ведь сам язык даже позиционируется как язык встроенных систем… Может, это очень сложно?

Постараюсь в этой небольшой заметке привести классический пример программы мигания светодиодом, но на Аде, с тем, чтобы все желающие могли повторить.

В качестве платы у меня используется какая-то китайская плата с процессором stm32f407vet6, у нее светодиод подключен на порту А на пин PA6. В качестве среды программирования буду использовать gnat для arm под ubuntu, для заливки подключен st-link v2 и к нему установлен пакет st-link (его надо собрать и установить из stlink.git), но можно использовать и любой другой программатор (например SEGGER).

К счастью, в состав поддерживаемых процессоров входит и stm32f4xx, так что все, что надо сделать — это создать файл проекта с указанием версии target и runtime. Ну и написать собственно нашу программу. Для облегчения жизни я использовал программу svd2ada для автоматической генерации файлов описания периферии из svd файла для моего процессора. Svd описание можно взять из стандарного пакета, а программа svd2ada есть на GitHub.

Все исходные тексты доступны на GitHub.

Итак — собственно программа ниже:

with STM32F40x;      use STM32F40x;
with STM32F40x.RCC;  use STM32F40x.RCC;
with STM32F40x.GPIO; use STM32F40x.GPIO;
with Ada.Real_Time;  use Ada.Real_Time;

procedure main is
  Led_Pin : constant := 6;
  Port    : ODR_Field renames GPIOA_Periph.ODR.ODR;
begin
  --  Включить clock for GPIO-A
  RCC_Periph.AHB1ENR.GPIOAEN := 1;
  --  Конфигурировать PA6
  GPIOA_Periph.MODER.ARR(Led_Pin) := 2#01#;
  GPIOA_Periph.OTYPER.OT.ARR(Led_Pin) := 0;
  GPIOA_Periph.OSPEEDR.ARR(Led_Pin) := 0;
  -- Переключать раз в секунду
  loop
     Port.Arr (Led_Pin) := Port.Arr (Led_Pin) xor 1;
     delay until Clock + To_Time_Span(1.0);
  end loop;
end main;


Сначала как все это собрать и запустить…

Ниже все команды для bash в каталоге проекта, все утилиты установлены в /opt/gnat/bin

Шаг 1. Устанавливаем пути для того, чтобы был вызван нужный нам toolchain

export PATH=/opt/gnat/bin:$PATH


Шаг 2. Собираем выполнимый файл.

gprbuild -P step1.gpr


Шаг 3. Создаем загрузочный бинарник для st-flash:

arm-eabi-objcopy -O binary main main.bin


Шаг 4. Загружаем нашу прошивку через st-link2, подключенный через USB

st-flash write main.bin 0x8000000


Если все прошло успешно, то можно любоваться на мигающий светодиод…

Теперь некоторые пояснения. Для этой целевой платы уже написан весь необходимый код инициалиации, причем частота процессора устанавливается в 168 Мгц, так что кода нам писать пришлось очень мало. Строка Port: ODR_Field renames GPIOA_Periph.ODR.ODR введена для удобочитаемости кода. Фунция Clock возвращает текущее время (точность — микросекунды).

Кроме того, для Ада-программ практически не нужна операционная система (так-то она сама себе ОС) для реализации задач, средств синхронизации и т.д.

Все богатство языка Ада для этого процессора недоступно, так как определен специальный профиль для компилятора —, а именно Pragma Profile (Ravenscar). Этот профиль вводит ряд ограничений для того, чтобы ваша программа гарантированно работала в таком окружении.

Впрочем, эти ограничения можно искуственно обойти, но в том-то и состоит существенное преимущество этой возможности языка, что если вы напишите программу в рамках такого профиля, то скорее всего она будет работать…

На этом всё, пишите в комментариях, что непонятно, постараюсь ответить. В следующей статье постараюсь привести полный цикл разработки интересного приложения на Аде для того же микропроцессора начиная с описания и анализа системы на aadl и заканчивая автоматическим доказательством с помощью SPARK.

© Habrahabr.ru