AdaCore / Ada_Drivers_Library

Ada source code and complete sample GNAT projects for selected bare-board platforms supported by GNAT.
BSD 3-Clause "New" or "Revised" License
241 stars 142 forks source link

How to write a generic Driver ? #357

Closed NicoPy closed 4 years ago

NicoPy commented 4 years ago

Hi,

I'm trying to write a UART driver for a Kinetis K22F51212 chip. The particularity of this chip is that UART0 registers are defined differently from UART1 and UART2 ones :

   --  Serial Communication Interface
   UART0_Periph : aliased UART0_Peripheral
     with Import, Address => UART0_Base;

   --  Serial Communication Interface
   UART1_Periph : aliased UART_Peripheral
     with Import, Address => UART1_Base;

   --  Serial Communication Interface
   UART2_Periph : aliased UART_Peripheral
     with Import, Address => UART2_Base;

I used the Ada_Drivers_Library/arch/ARM/STM32/drivers/uart_stm32f4/stm32-usarts.ads example to code my driver.

The problematic line is :

   type Internal_USART is new STM32_SVD.USART.USART1_Peripheral;

I tried to replace STM32_SVD.USART.USART1_Peripheral with a generic parameter but failed. I always get an error when using This in the functions bodies : no selector "C2" for private type "Internal_UART" defined at kinetis-uart.ads:94 (C2 is a UART register).

Here is what I did : The generic package parameter is defined like this : type t_uart_port is limited private; The "internal" UART type is defined like this : type Internal_UART is new t_uart_port; The package instantiation is like this : package uart1 is new kinetis.uart(UART_Peripheral);

I have still not enough Ada knowledge to find a solution.

How can I make my driver generic ?

Nicolas

Fabien-Chouteau commented 4 years ago

Hi @NicoPy,

This is usually a tricky situation.

How much of a difference there is between UART0 and the others? Is UART0 a subset?

NicoPy commented 4 years ago

UART0 is a superset of UART1 and UART2; Their definitions are automatically generated by SVD2ADA.

Fabien-Chouteau commented 4 years ago

In that case you should use the full definitions from UART1/2, add a discriminant to identify the "simpler" device, and in the code make sure that you only use the subset when dealing with a "simpler" UART.

   type Internal_USART is limited private;

   type USART (Periph : not null access Internal_USART;
                         Simpler : Boolean) 
   is limited new HAL.UART.UART_Port with private;```
private
   type Internal_USART is new STM32_SVD.USART.USART1_Peripheral;

   type USART (Periph : not null access Internal_USART;
                         Simpler : Boolean)
   is limited new HAL.UART.UART_Port with null record;

And then when you declare de drivers you can do:

   Internal_UART_0 : aliased Internal_UART with Import, Volatile, Address => USRT0_Base;
   Internal_UART_1 : aliased Internal_UART with Import, Volatile, Address => USRT1_Base;

   UART_0 : aliased USART (Internal_UART_0'Access, Simpler => True);
   UART_1 : aliased USART (Internal_UART_1'Access, Simpler => False);

(Simpler is maybe not the best name here)

NicoPy commented 4 years ago

Just for my knowledge, no solution with a generic (package or anything else) ?

Fabien-Chouteau commented 4 years ago

Not that I can think of.

NicoPy commented 4 years ago

Thanks for your help.

Fabien-Chouteau commented 4 years ago

You are welcome :)