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