First of all. This issue has only come up a couple of times for myself so far. As I have zero clue how much work will be required on the sophisticated Ada compiler then it may not be worth the effort?
I have ignored pins to show the idea succinctly.
The idea is to be able to have the following instead of overloaded procedures and functions:
Any record components accessed that did not exist in both or all of the Or'd parameters would cause a compile error.
Procedure Configure_SPI (MISO_Port : in out GPIOA_Peripheral | GPIOI_Peripheral;
MISO_Port : in out GPIOA_Peripheral | GPIOI_Peripheral;
CLK_Port : in out GPIOA_Peripheral | GPIOI_Peripheral;
CS_Port: in out GPIOA_Peripheral | GPIOI_Peripheral);
procedure Configure_GPIO (Port : in out GPIOA_Peripheral | GPIOI_Peripheral;
Mode : in GPIO.Mode.Operant);
Background information follows.
These files are generated from ARM CMSIS SVD xml files by adacores svd2ada tool.
for GPIOA_Peripheral use record
MODER at 16#0# range 0 .. 31;
OTYPER at 16#4# range 0 .. 31;
OSPEEDR at 16#8# range 0 .. 31;
PUPDR at 16#C# range 0 .. 31;
IDR at 16#10# range 0 .. 31;
ODR at 16#14# range 0 .. 31;
BSRR at 16#18# range 0 .. 31;
LCKR at 16#1C# range 0 .. 31;
AFRL at 16#20# range 0 .. 31;
AFRH at 16#24# range 0 .. 31;
BRR at 16#28# range 0 .. 31;
ASCR at 16#2C# range 0 .. 31;
end record;
-- General-purpose I/Os
GPIOA_Periph : aliased GPIOA_Peripheral
with Import, Address => GPIOA_Base;
-- General-purpose I/Os
GPIOB_Periph : aliased GPIOA_Peripheral
with Import, Address => GPIOB_Base;
-- General-purpose I/Os
GPIOC_Periph : aliased GPIOA_Peripheral
with Import, Address => GPIOC_Base;
-- General-purpose I/Os
GPIOD_Periph : aliased GPIOA_Peripheral
with Import, Address => GPIOD_Base;
-- General-purpose I/Os
GPIOE_Periph : aliased GPIOA_Peripheral
with Import, Address => GPIOE_Base;
-- General-purpose I/Os
GPIOF_Periph : aliased GPIOA_Peripheral
with Import, Address => GPIOF_Base;
-- General-purpose I/Os
GPIOG_Periph : aliased GPIOA_Peripheral
with Import, Address => GPIOG_Base;
-- General-purpose I/Os
GPIOH_Periph : aliased GPIOA_Peripheral
with Import, Address => GPIOH_Base;
for GPIOI_Peripheral use record
MODER at 16#0# range 0 .. 31;
OTYPER at 16#4# range 0 .. 31;
OSPEEDR at 16#8# range 0 .. 31;
PUPDR at 16#C# range 0 .. 31;
IDR at 16#10# range 0 .. 31;
ODR at 16#14# range 0 .. 31;
BSRR at 16#18# range 0 .. 31;
LCKR at 16#1C# range 0 .. 31;
AFRL at 16#20# range 0 .. 31;
AFRH at 16#24# range 0 .. 31;
BRR at 16#28# range 0 .. 31;
end record;
-- General-purpose I/Os
GPIOI_Periph : aliased GPIOI_Peripheral
with Import, Address => GPIOI_Base;
These records differ by the one last register in GPIOA; ASCR. Leading to two distinct types being generated.
Use function overloading.
This is nice and simple but has the issue of code duplication as well as the issue of a higher level function possibly wanting to set various combinations of GPIO port types. Such as for an SPI function with MISO, MOSI, CLK, CS arguments.
I am currently considering switching from overloading to an enum of peripheral addresses as the parameter (as Integers). With a slight erosion of type safety in terms of one more layer for typos but a better API facilitation.
Mark Rogers suggested that he uses Unchecked_Unions to solve this problem.
Generics do not seem to be an option due to wanting to conduct operations on the record sub components.
Tagged type tags would cause problems for memory overlays.
p.s. I believe Ada is the best language for general embedded development. One concern I have is that the HIS portrayal of Ada may be scaring some users away. Perhaps Ada descriptions could bear that in mind?
First of all. This issue has only come up a couple of times for myself so far. As I have zero clue how much work will be required on the sophisticated Ada compiler then it may not be worth the effort?
I have ignored pins to show the idea succinctly. The idea is to be able to have the following instead of overloaded procedures and functions:
Any record components accessed that did not exist in both or all of the Or'd parameters would cause a compile error.
Background information follows.
These files are generated from ARM CMSIS SVD xml files by adacores svd2ada tool.
"https://github.com/kevlar700/STM32L4R9_SVD/blob/main/stm32_svd-gpio.ads" "https://github.com/kevlar700/STM32L4R9_SVD/blob/main/stm32_svd-tim.ads"
I shall demonstrate the simplest case.
These records differ by the one last register in GPIOA; ASCR. Leading to two distinct types being generated.
There are various ways to tackle this currently.
Create a record and use that as an all encompassing peripheral as accomplished in Ada_Drivers_Library Timer peripheral. https://github.com/AdaCore/Ada_Drivers_Library/blob/master/arch/ARM/STM32/drivers/stm32-timers.ads This has the issue of maintenance for new chips and complexity in matching to the newly generated svd.
Use function overloading. This is nice and simple but has the issue of code duplication as well as the issue of a higher level function possibly wanting to set various combinations of GPIO port types. Such as for an SPI function with MISO, MOSI, CLK, CS arguments.
I am currently considering switching from overloading to an enum of peripheral addresses as the parameter (as Integers). With a slight erosion of type safety in terms of one more layer for typos but a better API facilitation.
Mark Rogers suggested that he uses Unchecked_Unions to solve this problem.
Generics do not seem to be an option due to wanting to conduct operations on the record sub components.
Tagged type tags would cause problems for memory overlays.
p.s. I believe Ada is the best language for general embedded development. One concern I have is that the HIS portrayal of Ada may be scaring some users away. Perhaps Ada descriptions could bear that in mind?