Infernal bare iron programming

Good day! It's a shame that few articles are devoted to hellish programming, the wonderful programming language of Hell, and even more so there are no articles on it for microcontrollers. But the language itself is even positioned as the language of embedded systems ... Maybe it is very difficult?

I will try in this small note to give a classic example of a program for flashing an LED, but on Ada, so that everyone can repeat it.

As a board, I use some kind of Chinese board with a stm32f407vet6 processor, its LED is connected on port A to pin PA6. As a programming environment I will use gnat for arm under ubuntu, st-link v2 is connected for uploading and the st-link package is installed on it (it needs to be built and installed from stlink.git ), but you can use any other programmer (for example, SEGGER).

Fortunately, stm32f4xx is also part of the supported processors, so all you have to do is create a project file with the version of target and runtime. Well, write our actual program. To make life easier, I used the svd2ada program to automatically generate peripheral description files from an svd file for my processor. The Svd description can be taken from the standard package, and the svd2ada program is on GitHub .

All sources are available on github .

So - actually the program below:

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;

First, how to collect and run all this ...
Below are all the commands for bash in the project directory, all utilities are installed in / opt / gnat / bin
Step 1. Set the paths so that the toolchain we need is called

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

Step 2. We collect the executable file.

gprbuild -P step1.gpr

Step 3. Create a bootable binary for st-flash:

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

Step 4. Download our firmware via st-link2 connected via USB

st-flash write main.bin 0x8000000

If everything went well, then you can admire the blinking LED ...
Now some explanations. For this target board, all the necessary initialization code has already been written, and the processor frequency is set to 168 MHz, so we had to write very little code. The Port: ODR_Field renames GPIOA_Periph.ODR.ODR line is introduced for readability. The Clock function returns the current time (accuracy - microseconds).

In addition, Ada programs practically do not need an operating system (so it is its own OS) for the implementation of tasks, synchronization tools, etc.

All the richness of the Ada language is not available for this processor, since a special profile for the compiler is defined - namely the Pragma Profile (Ravenscar). This profile introduces a number of restrictions so that your program is guaranteed to work in such an environment.

However, these limitations can be artificially circumvented, but the essential advantage of this feature of the language lies in the fact that if you write a program within such a profile, it will most likely work ...
That's all, write in the comments, which is not clear, I’ll try to answer. In the next article I will try to give a full development cycle of an interesting application on Ada for the same microprocessor, starting with the description and analysis of the system on aadl and ending with automatic proofing using SPARK.