Постараюсь в этой небольшой заметке привести классический пример программы мигания светодиодом, но на Аде, с тем, чтобы все желающие могли повторить.
В качестве платы у меня используется какая-то китайская плата с процессором 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.
Комментарии (12)

UA3MQJ
13.03.2018 14:56Только я начал читать… и статья закончилась.
Появилась ли поддержка народно любимого STM32F103?
Спасибо! Пишите, пожалуйста, еще про Ада и STM.
oam2oam Автор
13.03.2018 15:37Для STM32F107 я специально сделал версию BSP. Думаю, что не сложно сделать и для STM32F103. Вот только ОЗУ у них маловато… Что, впрочем решается использованием controlled типов.

Shamrel
13.03.2018 14:59Писать для МК на Ada можно. Но зачем? (сарказм off)
Это определенной целевая аудитория или специфические задачи? Или просто «по приколу»?
oam2oam Автор
13.03.2018 15:43Одной из целей было привлечь внимание к использованию языка Ада. Сам я 30 лет пишу на С (и еще многих других языках), но Ада — это совсем другой подход…
А вот МК выбран осознанно — именно там обычно очень велика цена ошибки, особенно неотловленной в процесса отладки. Именно для МК, для написания критических приложений, мне кажется и стоит использовать Аду.

Shamrel
13.03.2018 16:25Тогда жду статьи об использовании этого языка!
Предлагаю для начала темы:
- Небольшой ликбез по языку (применительно к теме МК).
- «Сама себе ОС» — особенности окружения.

Whuthering
13.03.2018 20:25Хотелось бы увидеть более подробный рассказ в стиле «А зачем?»: какие именно преимущества есть у языка в целом и для встраиваемых систем (с примерами), каких проблем его использование позволяет избежать (тоже с примерами), какие пока что есть ограничения и как они могут быть решены, и т.д.

el_gato
13.03.2018 23:30Мне в Аде нравится злая система типов. Синтетическая ситуация — нужно написать функцию для вычисления площади прямоугольника.
и чтобы вот длина могла быть от 1 до 10, ширина от 1 до 5 и никак иначе, ну и площадь соответственно. На Аде будет выглядеть как-то так.
with Ada.Text_IO; procedure Main is type Rectangle_Width is digits 5 range 1.0..10.0; type Rectangle_Length is digits 5 range 1.0..5.0; type Rectangle_Square is digits 5 range 1.0 .. 50.0; function "*"(A: Rectangle_Width; B: Rectangle_Length) return Rectangle_Square is Result: Rectangle_Square; begin Result := Rectangle_Square(A) * Rectangle_Square(B); return Result; end "*"; Width: constant Rectangle_Width := 5.0; Height: constant Rectangle_Length := 5.0; Area: Rectangle_Square; begin Area := Width * Height; Ada.Text_IO.Put_Line(Area'Image); end Main;
Если какой-то из параметров выйдет за пределы допустимых значений — бросает исключение, а если значения известны на этапе компиляции, то даже и не скомпилируется.
Нужно посчитать то же самое, но вот чтобы размеры указывались с точностью 1/100 и чтобы никаких там 1.124568 меняем floating point на fixed point
type Rectangle_Width is delta 0.01 range 1.0..10.0; type Rectangle_Length is delta 0.01 range 1.0..5.0; type Rectangle_Square is delta 0.01 range 1.0 .. 50.0;
Но что мне нравится больше всего, так это то что можно говорить при случае — «Я знаю язык программирования ада».

oam2oam Автор
14.03.2018 07:46Вы правы, но для МК это имеет еще и важное следствие, вот пример:
type CFGR_PPRE_Field_Array is array (1 .. 2) of CFGR_PPRE_Element with Component_Size => 3, Size => 6;
тут определен массив из двух элементов по 3 бита общей длины 6 бит. Любой программист для МК встречал необходимость описывать и использовать битовые поля регистров. Ну и конечно, можно создать свой тип практически любого вида и описать его область значений…
Не буду даже говорить, насколько это спасает от ошибок времени компиляции и разработки!

Tsvetik
14.03.2018 11:03Поддержу. Давно пишу на C для embedded и все время поглядываю в сторону Ada. Очень нравится строгая типизация и отлов большинства ошибок на этапе компиляции.

burdakovd
14.03.2018 13:26Result := Rectangle_Square(A) * Rectangle_Square(B);Но в этом случае мы получается конвертируем длины в
Squareещё до умножения, что несколько странно.
Т.е. если бы условия были скажем такими:
type Rectangle_Width is digits 5 range 0.1..0.5; type Rectangle_Length is digits 5 range 0.1..0.5; type Rectangle_Square is digits 5 range 0.01 .. 0.25;
тогда выражение
Rectangle_Square(A)могло бы выбросить исключение еслиA > 0.25?
el_gato
14.03.2018 15:00Оно и выбросит исключение при таких условиях. А типы привести надо так как мы не можем использовать операцию умножения между двумя разными типами в той же самой функции которой мы собственно эту операцию и определяем. Безконечная рекурсия получится.
(Можно обойтись и без этой функции просто перемножив предварительно приведя к одному типу
)Area := Rectangle_Square(Width) * Rectangle_Square(Height);
В Aде нельзя производить какие либо операции с различными типами данных без предварительного приведения.
el_gato
Можно еще добавить что AdaCore держит на гитхабе достаточно часто обновляемую библиотеку драйверов для STM32 на Ada с примерами использования, а так же ежегодно проводит челленджи «Make with Ada» для разработчиков встраиваемых систем, с целью популяризации языка.