Skip to content

GNAT-Academic-Program/gpio_generic

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

gpio_generic

Generic GPIO abstraction layer for bare-metal Ada applications.

Overview

gpio_generic provides a hardware-independent GPIO interface for embedded systems. It separates configuration and data operations through distinct generic packages, enabling flexible instantiation patterns and compile-time optimization.

Features

  • Hardware-agnostic GPIO abstraction
  • Type-safe pin configuration with discriminated records
  • Separate control and data operation packages
  • Combined interface package for convenience
  • Support for all standard GPIO modes (Input, Output, Alternate, Analog)
  • Configurable pull resistors, drive types, and speed levels
  • Zero runtime overhead through generic instantiation

Architecture

The package is organized into three layers:

  • Gpio_Types - Common types and configuration records
  • Gpio_Control - Pin configuration operations
  • Gpio_Data - Pin data operations (set, clear, toggle, read)
  • Gpio_Interface - Combined control and data interface (instantiates Control and Data internally)

API

Gpio_Types

package Gpio_Types is
   GPIO_Error       : exception;
   GPIO_Unsupported : exception;

   type Pin_Mode is (Input, Output, Alternate, Analog);
   type Pull_Resistor is (None, Pull_Up, Pull_Down);
   type Drive_Type is (Push_Pull, Open_Drain);
   type Speed_Level is (Low_Speed, Medium_Speed, High_Speed, Very_High_Speed);
   type Logic_Level is (Low, High);

   subtype Alternate_Function is Natural range 0 .. 15;

   type Gpio_Config (Mode : Pin_Mode := Input) is record
      Pull : Pull_Resistor := None;
      case Mode is
         when Output | Alternate =>
            Drive      : Drive_Type  := Push_Pull;
            Speed      : Speed_Level := Medium_Speed;
            Init_State : Logic_Level := Low;
            case Mode is
               when Alternate =>
                  AF : Alternate_Function := 0;
               when others => null;
            end case;
         when others => null;
      end case;
   end record;
end Gpio_Types;

Gpio_Interface

generic
   type Pin_T is private;
   with procedure Driver_Configure (P : Pin_T; Cfg : Gpio_Types.Gpio_Config);
   with procedure Driver_Set (P : Pin_T);
   with procedure Driver_Clr (P : Pin_T);
   with procedure Driver_Toggle (P : Pin_T);
   with function Driver_Read (P : Pin_T) return MT.Bit;
package Gpio_Interface is
   subtype Pin is Pin_T;
   procedure Configure (P : Pin; Cfg : Gpio_Types.Gpio_Config);
   procedure Set    (P : Pin);
   procedure Clr    (P : Pin);
   procedure Toggle (P : Pin);
   function Read (P : Pin) return MT.Bit;
end Gpio_Interface;

Usage

1. Implement Hardware Driver Layer

Create a hardware-specific package with pin type and driver procedures:

-- stm32g431_gpio.ads
package STM32G431_GPIO is
   type Pin is private;
   
   type Port_Letter is (A, B, C, D, E, F, G);
   subtype Pin_Number is Natural range 0 .. 15;
   
   function Make_Pin (Port : Port_Letter; Nbr : Pin_Number) return Pin;
   
   procedure Driver_Configure (Dev : Pin; Cfg : Gpio_Types.Gpio_Config);
   procedure Driver_Set (Dev : Pin);
   procedure Driver_Clr (Dev : Pin);
   procedure Driver_Toggle (Dev : Pin);
   function Driver_Read (Dev : Pin) return MT.Bit;
private
   -- Hardware-specific implementation
end STM32G431_GPIO;

2. Instantiate Gpio_Interface

Create a vendor-neutral GPIO package at the MCU level:

-- gpio.ads (in stm32g431 crate)
with Gpio_Interface;
with STM32G431_GPIO;

package Gpio is new Gpio_Interface
  (Pin_T            => STM32G431_GPIO.Pin,
   Driver_Configure => STM32G431_GPIO.Driver_Configure,
   Driver_Set       => STM32G431_GPIO.Driver_Set,
   Driver_Clr       => STM32G431_GPIO.Driver_Clr,
   Driver_Toggle    => STM32G431_GPIO.Driver_Toggle,
   Driver_Read      => STM32G431_GPIO.Driver_Read);

3. Create Pin Objects at Board Level

In your board package, create pin objects using the hardware driver's Make_Pin function:

-- board.ads
with Gpio;
with STM32G431_GPIO;

package Board is
   Led      : Gpio.Pin := STM32G431_GPIO.Make_Pin (STM32G431_GPIO.B, 8);
   Spi_1_Cs : Gpio.Pin := STM32G431_GPIO.Make_Pin (STM32G431_GPIO.A, 4);
   
   procedure Initialize;
end Board;

4. Configure and Use Pins

-- board.adb
with Gpio_Types;

package body Board is
   procedure Initialize is
      Led_Cfg : constant Gpio_Types.Gpio_Config :=
        (Mode       => Gpio_Types.Output,
         Pull       => Gpio_Types.None,
         Drive      => Gpio_Types.Push_Pull,
         Speed      => Gpio_Types.Low_Speed,
         Init_State => Gpio_Types.Low);
   begin
      Gpio.Configure (Led, Led_Cfg);
   end Initialize;
end Board;
-- Application code
with Board;
with Gpio;

procedure Main is
begin
   Board.Initialize;
   
   loop
      Gpio.Set (Board.Led);
      delay 0.5;
      Gpio.Clr (Board.Led);
      delay 0.5;
   end loop;
end Main;

Configuration Examples

Output pin with push-pull drive:

Cfg : constant Gpio_Types.Gpio_Config :=
  (Mode       => Gpio_Types.Output,
   Pull       => Gpio_Types.None,
   Drive      => Gpio_Types.Push_Pull,
   Speed      => Gpio_Types.High_Speed,
   Init_State => Gpio_Types.Low);

Input pin with pull-up resistor:

Cfg : constant Gpio_Types.Gpio_Config :=
  (Mode => Gpio_Types.Input,
   Pull => Gpio_Types.Pull_Up);

Alternate function (e.g., UART TX on AF7):

Cfg : constant Gpio_Types.Gpio_Config :=
  (Mode       => Gpio_Types.Alternate,
   Pull       => Gpio_Types.Pull_Up,
   Drive      => Gpio_Types.Push_Pull,
   Speed      => Gpio_Types.Very_High_Speed,
   Init_State => Gpio_Types.High,
   AF         => 7);

Analog input:

Cfg : constant Gpio_Types.Gpio_Config :=
  (Mode => Gpio_Types.Analog,
   Pull => Gpio_Types.None);

Design Rationale

Discriminated Configuration Record

The Gpio_Config type uses Ada's discriminated records to ensure type safety. Only valid fields are accessible for each mode, with compile-time verification of configuration correctness.

Generic Instantiation

Hardware abstraction through generics provides zero runtime overhead with no virtual dispatch, compile-time binding to hardware drivers, and type safety with private pin types.

Layered Architecture

The separation between generic interface (gpio_generic), MCU driver (stm32g431_gpio), MCU-level facade (gpio), and board-level pin objects (Board.Led) enables portability and clear separation of concerns.

Integration

Add to your alire.toml:

[[depends-on]]
gpio_generic = "^0.1.0"

Dependencies

  • machine_types - Provides MT.Bit type for GPIO read operations

License

MIT OR Apache-2.0 WITH LLVM-exception

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages