diff --git a/components/src/radio/si4432/README.md b/components/src/radio/si4432/README.md new file mode 100644 index 000000000..80299037c --- /dev/null +++ b/components/src/radio/si4432/README.md @@ -0,0 +1,6 @@ +This directory contains the driver for Si4432B1 radio module. The Si4432 +EZRadioPRO ISM Band supports a frequency range between 240 and 930 MHz and +output power range between 1 and 20 dBm. + +The examples/STM32F429_Discovery/si4432_f429disco.gpr project contains +a simple example. diff --git a/components/src/radio/si4432/si4432.adb b/components/src/radio/si4432/si4432.adb new file mode 100644 index 000000000..2a9abd2af --- /dev/null +++ b/components/src/radio/si4432/si4432.adb @@ -0,0 +1,3080 @@ +------------------------------------------------------------------------------ +-- -- +-- Copyright (C) 2025, AdaCore -- +-- -- +-- Redistribution and use in source and binary forms, with or without -- +-- modification, are permitted provided that the following conditions are -- +-- met: -- +-- 1. Redistributions of source code must retain the above copyright -- +-- notice, this list of conditions and the following disclaimer. -- +-- 2. Redistributions in binary form must reproduce the above copyright -- +-- notice, this list of conditions and the following disclaimer in -- +-- the documentation and/or other materials provided with the -- +-- distribution. -- +-- 3. Neither the name of the copyright holder nor the names of its -- +-- contributors may be used to endorse or promote products derived -- +-- from this software without specific prior written permission. -- +-- -- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -- +-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -- +-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -- +-- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -- +-- HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -- +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -- +-- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -- +-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -- +-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -- +-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -- +-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- +-- -- +------------------------------------------------------------------------------ + +with Interfaces; use Interfaces; + +package body Si4432 is + + function From_Boolean (Value : Boolean) return Bit; + function To_Boolean (Value : Bit) return Boolean; + + function To_Synchronization_Word_Index + (Index : UInt2) + return Register_Name; + + function To_Transmit_Header_Index + (Index : UInt2) + return Register_Name; + + function To_Check_Header_Index + (Index : UInt2) + return Register_Name; + + function To_Header_Enable_Index + (Index : UInt2) + return Register_Name; + + ---------------- + -- Initialize -- + ---------------- + + procedure Initialize + (This : out Si4432_Driver; + CSN_Pin : HAL.GPIO.Any_GPIO_Point; + SDN_Pin : HAL.GPIO.Any_GPIO_Point; + SPI : HAL.SPI.Any_SPI_Port) is + begin + if CSN_Pin = null then + This.Holder := Holder_Type' + (Kind => Hardware, + SPI => SPI, + SDN_Pin => SDN_Pin); + else + This.Holder := Holder_Type' + (Kind => Software, + SPI => SPI, + CSN_Pin => CSN_Pin, + SDN_Pin => SDN_Pin); + end if; + end Initialize; + + ---------------------- + -- Device_Type_Code -- + ---------------------- + + function Device_Type_Code (This : Si4432_Driver) return UInt8 is + begin + return UInt8 (Read_Register (This, Device_Type_Code_Name)); + end Device_Type_Code; + + ------------------ + -- Version_Code -- + ------------------ + + function Version_Code (This : Si4432_Driver) return UInt8 is + begin + return UInt8 (Read_Register (This, Version_Code_Name)); + end Version_Code; + + --------------- + -- Set_Power -- + --------------- + + procedure Set_Power + (This : Si4432_Driver; + Mode : On_Off) is + begin + if This.Holder.SDN_Pin /= null then + if Mode = Off then + This.Holder.SDN_Pin.Set; + else + This.Holder.SDN_Pin.Clear; + end if; + end if; + end Set_Power; + + --------------- + -- Set_State -- + --------------- + + procedure Set_State + (This : Si4432_Driver; + State : Chip_State) + is + Data : Register := Read_Register + (This, Operating_Mode_And_Function_Control_1_Name); + Reg : Operating_Mode_And_Function_Control_1_Register with Import, + Address => Data'Address; + begin + Reg.xton := 1; + case State is + when Idle => + Reg.rxon := 0; + Reg.txon := 0; + + when RX => + Reg.rxon := 1; + Reg.txon := 0; + + when TX => + Reg.rxon := 0; + Reg.txon := 1; + end case; + + Write_Register (This, Operating_Mode_And_Function_Control_1_Name, Data); + end Set_State; + + -------------------- + -- Software_Reset -- + -------------------- + + procedure Software_Reset (This : Si4432_Driver) + is + Data : Register := 0; + Register : Operating_Mode_And_Function_Control_1_Register with Import, + Address => Data'Address; + begin + Register.swres := 1; + Write_Register (This, Operating_Mode_And_Function_Control_1_Name, Data); + end Software_Reset; + + ---------------------------- + -- Get_Interrupt_Statuses -- + ---------------------------- + + function Get_Interrupt_Statuses + (This : Si4432_Driver) + return Interrupt_Statuses + is + Data : Interrupt_Statuses; + begin + Read_Register (This, Interrupt_Status_1_Name, Data); + return Data; + end Get_Interrupt_Statuses; + + ---------------------------- + -- Get_Interrupt_Status_1 -- + ---------------------------- + + function Get_Interrupt_Status_1 + (This : Si4432_Driver) + return UInt8 + is + Data : constant Register := + Read_Register (This, Interrupt_Status_1_Name); + begin + return UInt8 (Data); + end Get_Interrupt_Status_1; + + ---------------------------- + -- Get_Interrupt_Status_2 -- + ---------------------------- + + function Get_Interrupt_Status_2 + (This : Si4432_Driver) + return UInt8 + is + Data : constant Register := + Read_Register (This, Interrupt_Status_2_Name); + begin + return UInt8 (Data); + end Get_Interrupt_Status_2; + + ---------------------- + -- Clear_Interrupts -- + ---------------------- + + procedure Clear_Interrupts (This : Si4432_Driver) is + Dummy : Interrupt_Statuses; + begin + Dummy := Get_Interrupt_Statuses (This); + end Clear_Interrupts; + + ------------------- + -- Set_Frequency -- + ------------------- + + procedure Set_Frequency + (This : Si4432_Driver; + Value : Frequency) + is + Data : HAL.SPI.SPI_Data_8b (1 .. 3) := (others => 0); + Reg : Frequency_Band_Select_Register with Import, + Address => Data (1)'Address; + + High_Band : constant Natural := (if Value >= 480.00 then 1 else 0); + Calc : constant Float := + (Float (Value) / Float (10 * (High_Band + 1))) - 24.0; + Band : UInt5; + Carrier : Unsigned_16; + + begin + Band := UInt5 (Float'Truncation (Calc)); + Carrier := Unsigned_16 ((Calc - Float (Band)) * 64000.0); + + Reg.fb := Band; + Reg.hbsel := Bit (High_Band); + Reg.sbsel := 1; + + Data (2) := UInt8 (Shift_Right (Carrier, 8)); + Data (3) := UInt8 (Carrier and 16#FF#); + + Write_Register (This, Frequency_Band_Select_Name, Data); + end Set_Frequency; + + ------------------------ + -- Set_Frequency_Band -- + ------------------------ + + procedure Set_Frequency_Band + (This : Si4432_Driver; + Band : UInt5; + High_Band : Boolean; + Side_Band : Boolean) + is + Reg : constant Frequency_Band_Select_Register := + (fb => Band, + hbsel => From_Boolean (High_Band), + sbsel => From_Boolean (Side_Band), + Reserved => 0); + + Data : Register with Import, Address => Reg'Address; + begin + Write_Register (This, Frequency_Band_Select_Name, Data); + end Set_Frequency_Band; + + ------------------------ + -- Get_Frequency_Band -- + ------------------------ + + procedure Get_Frequency_Band + (This : Si4432_Driver; + Band : out UInt5; + High_Band : out Boolean; + Side_Band : out Boolean) + is + Data : Register; + Register : Frequency_Band_Select_Register with Import, + Address => Data'Address; + begin + Data := Read_Register (This, Frequency_Band_Select_Name); + Band := Register.fb; + High_Band := To_Boolean (Register.hbsel); + Side_Band := To_Boolean (Register.sbsel); + end Get_Frequency_Band; + + ----------------------------------- + -- Set_Nominal_Carrier_Frequency -- + ----------------------------------- + + procedure Set_Nominal_Carrier_Frequency + (This : Si4432_Driver; + Value : UInt16) + is + Local : constant Unsigned_16 := Unsigned_16 (Value); + Data : HAL.SPI.SPI_Data_8b (1 .. 2); + begin + Data (1) := UInt8 (Shift_Right (Local, 8)); + Data (2) := UInt8 (Local and 16#FF#); + + Write_Register (This, Nominal_Carrier_Frequency_1_Name, Data); + end Set_Nominal_Carrier_Frequency; + + ----------------------------------- + -- Get_Nominal_Carrier_Frequency -- + ----------------------------------- + + function Get_Nominal_Carrier_Frequency + (This : Si4432_Driver) + return UInt16 + is + Data : HAL.SPI.SPI_Data_8b (1 .. 2); + begin + Read_Register (This, Nominal_Carrier_Frequency_1_Name, Data); + + return UInt16 + (Shift_Left (Unsigned_16 (Data (1)), 8) + Unsigned_16 (Data (2))); + end Get_Nominal_Carrier_Frequency; + + -------------------------- + -- Set_Frequency_Offset -- + -------------------------- + + procedure Set_Frequency_Offset + (This : Si4432_Driver; + Value : Frequency_Offset) + is + Local : constant Unsigned_16 := Unsigned_16 (Value); + Data : HAL.SPI.SPI_Data_8b (1 .. 2); + begin + Data (1) := UInt8 (Local and 16#FF#); + Data (2) := UInt8 (Shift_Right (Local, 8)); + + Write_Register (This, Frequency_Offset_1_Name, Data); + end Set_Frequency_Offset; + + -------------------------- + -- Get_Frequency_Offset -- + -------------------------- + + function Get_Frequency_Offset + (This : Si4432_Driver) + return Frequency_Offset + is + Data : HAL.SPI.SPI_Data_8b (1 .. 2); + begin + Read_Register (This, Frequency_Offset_1_Name, Data); + + return Frequency_Offset + (Shift_Left (Unsigned_16 (Data (2)), 8) + Unsigned_16 (Data (1))); + end Get_Frequency_Offset; + + ------------------------------------------ + -- Set_Frequency_Hopping_Channel_Select -- + ------------------------------------------ + + procedure Set_Frequency_Hopping_Channel_Select + (This : Si4432_Driver; + Value : UInt8) is + begin + Write_Register + (This, + Frequency_Hopping_Channel_Select_Name, + Register (Value)); + end Set_Frequency_Hopping_Channel_Select; + + ------------------------------------------ + -- Get_Frequency_Hopping_Channel_Select -- + ------------------------------------------ + + function Get_Frequency_Hopping_Channel_Select + (This : Si4432_Driver) + return UInt8 is + begin + return UInt8 + (Read_Register (This, Frequency_Hopping_Channel_Select_Name)); + end Get_Frequency_Hopping_Channel_Select; + + ------------------------------------- + -- Set_Frequency_Hopping_Step_Size -- + ------------------------------------- + + procedure Set_Frequency_Hopping_Step_Size + (This : Si4432_Driver; + Value : UInt8) is + begin + Write_Register + (This, + Frequency_Hopping_Step_Size_Name, + Register (Value)); + end Set_Frequency_Hopping_Step_Size; + + ------------------------------------- + -- Get_Frequency_Hopping_Step_Size -- + ------------------------------------- + + function Get_Frequency_Hopping_Step_Size + (This : Si4432_Driver) + return UInt8 is + begin + return UInt8 + (Read_Register (This, Frequency_Hopping_Step_Size_Name)); + end Get_Frequency_Hopping_Step_Size; + + ---------------------- + -- Set_TX_Data_Rate -- + ---------------------- + + procedure Set_TX_Data_Rate + (This : Si4432_Driver; + Value : UInt16) + is + Local : constant Unsigned_16 := Unsigned_16 (Value); + Data : HAL.SPI.SPI_Data_8b (1 .. 2); + begin + Data (1) := UInt8 (Shift_Right (Local, 8)); + Data (2) := UInt8 (Local and 16#FF#); + + Write_Register (This, TX_Data_Rate_1_Name, Data); + end Set_TX_Data_Rate; + + ---------------------- + -- Get_TX_Data_Rate -- + ---------------------- + + function Get_TX_Data_Rate + (This : Si4432_Driver) + return UInt16 + is + Data : HAL.SPI.SPI_Data_8b (1 .. 2); + begin + Read_Register (This, TX_Data_Rate_1_Name, Data); + + return UInt16 + (Shift_Left (Unsigned_16 (Data (1)), 8) + Unsigned_16 (Data (2))); + end Get_TX_Data_Rate; + + -------------------------- + -- Set_Data_Rates_Below -- + -------------------------- + + procedure Set_Data_Rates_Below + (This : Si4432_Driver; + Value : Boolean) + is + Data : Register := Read_Register (This, Modulation_Mode_Control_1_Name); + Reg : Modulation_Mode_Control_1_Register with Import, + Address => Data'Address; + begin + Reg.txdtrtscale := From_Boolean (Value); + Write_Register (This, Modulation_Mode_Control_1_Name, Data); + end Set_Data_Rates_Below; + + ----------------------------------- + -- Set_Modulation_Mode_Control_1 -- + ----------------------------------- + + procedure Set_Modulation_Mode_Control_1 + (This : Si4432_Driver; + Data_Whitening : Boolean; + Manchester_Coding : Boolean; + Manchester_Data_Inversion : Boolean; + Manchester_Preamble_Polarity : Boolean; + Packet_Handler_Down : Boolean; + Data_Rates_Below : Boolean) + is + Reg : constant Modulation_Mode_Control_1_Register := + (enwhite => From_Boolean (Data_Whitening), + enmanch => From_Boolean (Manchester_Coding), + enmaninv => From_Boolean (Manchester_Data_Inversion), + manppol => From_Boolean (Manchester_Preamble_Polarity), + enphpwdn => From_Boolean (Packet_Handler_Down), + txdtrtscale => From_Boolean (Data_Rates_Below), + Reserved => 0); + + Data : Register with Import, Address => Reg'Address; + begin + Write_Register (This, Modulation_Mode_Control_1_Name, Data); + end Set_Modulation_Mode_Control_1; + + ----------------------------------- + -- Get_Modulation_Mode_Control_1 -- + ----------------------------------- + + procedure Get_Modulation_Mode_Control_1 + (This : Si4432_Driver; + Data_Whitening : out Boolean; + Manchester_Coding : out Boolean; + Manchester_Data_Inversion : out Boolean; + Manchester_Preamble_Polarity : out Boolean; + Packet_Handler_Down : out Boolean; + Data_Rates_Below : out Boolean) + is + Data : Register; + Reg : Modulation_Mode_Control_1_Register with Import, + Address => Data'Address; + + begin + Data := Read_Register (This, Modulation_Mode_Control_1_Name); + + Data_Whitening := To_Boolean (Reg.enwhite); + Manchester_Coding := To_Boolean (Reg.enmanch); + Manchester_Data_Inversion := To_Boolean (Reg.enmaninv); + Manchester_Preamble_Polarity := To_Boolean (Reg.manppol); + Packet_Handler_Down := To_Boolean (Reg.enphpwdn); + Data_Rates_Below := To_Boolean (Reg.txdtrtscale); + end Get_Modulation_Mode_Control_1; + + ----------------------------------- + -- Set_Modulation_Mode_Control_2 -- + ----------------------------------- + + procedure Set_Modulation_Mode_Control_2 + (This : Si4432_Driver; + Modulation : Modulation_Mode; + Invert_TX_RX : Boolean; + Source : Modulation_Source; + TX_Data_Clock : Modulation_TX_Data_Clock) + is + Data : Register; + Reg : Modulation_Mode_Control_2_Register with Import, + Address => Data'Address; + begin + Data := Read_Register (This, Modulation_Mode_Control_2_Name); + + Reg.modtyp := Modulation; + Reg.eninv := From_Boolean (Invert_TX_RX); + Reg.dtmod := Source; + Reg.trclk := TX_Data_Clock; + + Write_Register (This, Modulation_Mode_Control_2_Name, Data); + end Set_Modulation_Mode_Control_2; + + ----------------------------------- + -- Get_Modulation_Mode_Control_2 -- + ----------------------------------- + + procedure Get_Modulation_Mode_Control_2 + (This : Si4432_Driver; + Modulation : out Modulation_Mode; + Invert_TX_RX : out Boolean; + Source : out Modulation_Source; + TX_Data_Clock : out Modulation_TX_Data_Clock) + is + Data : Register; + Reg : Modulation_Mode_Control_2_Register with Import, + Address => Data'Address; + begin + Data := Read_Register (This, Modulation_Mode_Control_2_Name); + + Modulation := Reg.modtyp; + Invert_TX_RX := To_Boolean (Reg.eninv); + Source := Reg.dtmod; + TX_Data_Clock := Reg.trclk; + end Get_Modulation_Mode_Control_2; + + -------------------------------- + -- Set_Frequency_Deviation_Hz -- + -------------------------------- + + procedure Set_Frequency_Deviation_Hz + (This : Si4432_Driver; + Value : Frequency_Deviation_Hz) is + begin + Set_Frequency_Deviation (This, UInt9 (Value / 625)); + end Set_Frequency_Deviation_Hz; + + ----------------------------- + -- Set_Frequency_Deviation -- + ----------------------------- + + procedure Set_Frequency_Deviation + (This : Si4432_Driver; + Value : UInt9) + is + Data : constant Unsigned_16 := Unsigned_16 (Value); + begin + Write_Register + (This, + Frequency_Deviation_Name, + Register (Data and 16#FF#)); + + if (Data and 2#1_0000_0000#) /= 0 then + declare + R : Register := Read_Register + (This, Modulation_Mode_Control_2_Name); + Reg : Modulation_Mode_Control_2_Register with Import, + Address => R'Address; + begin + Reg.fd := 1; + Write_Register (This, Modulation_Mode_Control_2_Name, R); + end; + end if; + end Set_Frequency_Deviation; + + ----------------------------- + -- Get_Frequency_Deviation -- + ----------------------------- + + function Get_Frequency_Deviation + (This : Si4432_Driver) + return UInt9 + is + Data : HAL.SPI.SPI_Data_8b (1 .. 2); + Reg : Modulation_Mode_Control_2_Register with Import, + Address => Data (1)'Address; + + begin + Read_Register (This, Modulation_Mode_Control_2_Name, Data); + + return (if Reg.fd = 1 then 256 else 0) + + UInt9 (Data (2)); + end Get_Frequency_Deviation; + + ------------------------ + -- Set_Header_Control -- + ------------------------ + + procedure Set_Header_Control + (This : Si4432_Driver; + Header_Bytes_Check : UInt4 := 16#C#; + Broadcast_Address_Check : UInt4 := 0; + Synchronization : Synchronization_Word_Length := Word_3_2; + Fix_TR_Packet_Length : Boolean := False; + Header : Header_Length := Header_3_2; + Skipsyn : Boolean := False) + is + Data : HAL.SPI.SPI_Data_8b (1 .. 2); + Reg1 : Header_Control_1_Register := + (hdch => Header_Bytes_Check, + bcen => Broadcast_Address_Check) + with Address => Data (1)'Address; + Reg2 : Header_Control_2_Register with Import, + Address => Data (2)'Address; + + begin + Data (2) := UInt8 (Read_Register (This, Header_Control_2_Name)); + + Reg2.synclen := Synchronization; + Reg2.fixpklen := From_Boolean (Fix_TR_Packet_Length); + Reg2.hdlen := Header; + Reg2.skipsyn := From_Boolean (Skipsyn); + + Write_Register (This, Header_Control_1_Name, Data); + end Set_Header_Control; + + -------------------------- + -- Set_Header_Control_1 -- + -------------------------- + + procedure Set_Header_Control_1 + (This : Si4432_Driver; + Header_Bytes_Check : UInt4; + Broadcast_Address_Check : UInt4) + is + Reg : constant Header_Control_1_Register := + (hdch => Header_Bytes_Check, + bcen => Broadcast_Address_Check); + R : Register with Import, Address => Reg'Address; + + begin + Write_Register (This, Header_Control_1_Name, R); + end Set_Header_Control_1; + + -------------------------- + -- Get_Header_Control_1 -- + -------------------------- + + procedure Get_Header_Control_1 + (This : Si4432_Driver; + Header_Bytes_Check : out UInt4; + Broadcast_Address_Check : out UInt4) + is + R : Register; + Reg : Header_Control_1_Register with Import, + Address => R'Address; + + begin + R := Read_Register (This, Header_Control_1_Name); + + Header_Bytes_Check := Reg.hdch; + Broadcast_Address_Check := Reg.bcen; + end Get_Header_Control_1; + + -------------------------- + -- Set_Header_Control_2 -- + -------------------------- + + procedure Set_Header_Control_2 + (This : Si4432_Driver; + Synchronization : Synchronization_Word_Length; + Fix_TR_Packet_Length : Boolean; + Header : Header_Length; + Skipsyn : Boolean) + is + R : Register := Read_Register (This, Header_Control_2_Name); + Reg : Header_Control_2_Register with Import, + Address => R'Address; + + begin + Reg.synclen := Synchronization; + Reg.fixpklen := From_Boolean (Fix_TR_Packet_Length); + Reg.hdlen := Header; + Reg.skipsyn := From_Boolean (Skipsyn); + + Write_Register (This, Header_Control_2_Name, R); + end Set_Header_Control_2; + + -------------------------- + -- Get_Header_Control_2 -- + -------------------------- + + procedure Get_Header_Control_2 + (This : Si4432_Driver; + Synchronization : out Synchronization_Word_Length; + Fix_TR_Packet_Length : out Boolean; + Header : out Header_Length; + Skipsyn : out Boolean) + is + R : Register := Read_Register (This, Header_Control_2_Name); + Reg : Header_Control_2_Register with Import, + Address => R'Address; + + begin + Synchronization := Reg.synclen; + Fix_TR_Packet_Length := To_Boolean (Reg.fixpklen); + Header := Reg.hdlen; + Skipsyn := To_Boolean (Reg.skipsyn); + end Get_Header_Control_2; + + ------------------------------ + -- Set_Synchronization_Word -- + ------------------------------ + + procedure Set_Synchronization_Word + (This : Si4432_Driver; + Index : UInt2; + Value : UInt8) is + begin + Write_Register + (This, To_Synchronization_Word_Index (Index), Register (Value)); + end Set_Synchronization_Word; + + ------------------------------ + -- Get_Synchronization_Word -- + ------------------------------ + + function Get_Synchronization_Word + (This : Si4432_Driver; + Index : UInt2) + return UInt8 is + begin + return UInt8 (Read_Register (This, To_Synchronization_Word_Index (Index))); + end Get_Synchronization_Word; + + ----------------------------- + -- Set_Data_Access_Control -- + ----------------------------- + + procedure Set_Data_Access_Control + (This : Si4432_Driver; + CRC_Selection : CRC_Polynomial; + CRC_Enable : Boolean; + Enable_Packet_TX_Handling : Boolean; + Skip_2nd_Phase_Preamble_Detection : Boolean; + CRC_Data_Only_Enable : Boolean; + LSB_First_Enable : Boolean; + Enable_Packet_RX_Handling : Boolean) + is + Reg : constant Data_Access_Control_Register := + (crc => CRC_Selection, + encrc => From_Boolean (CRC_Enable), + enpactx => From_Boolean (Enable_Packet_TX_Handling), + skip2ph => From_Boolean (Skip_2nd_Phase_Preamble_Detection), + crcdonly => From_Boolean (CRC_Data_Only_Enable), + lsbfrst => From_Boolean (LSB_First_Enable), + enpacrx => From_Boolean (Enable_Packet_RX_Handling)); + Value : Register with Import, Address => Reg'Address; + begin + Write_Register (This, Data_Access_Control_Name, Value); + end Set_Data_Access_Control; + + ----------------------------- + -- Get_Data_Access_Control -- + ----------------------------- + + procedure Get_Data_Access_Control + (This : Si4432_Driver; + CRC_Selection : out CRC_Polynomial; + CRC_Enable : out Boolean; + Enable_Packet_TX_Handling : out Boolean; + Skip_2nd_Phase_Preamble_Detection : out Boolean; + CRC_Data_Only_Enable : out Boolean; + LSB_First_Enable : out Boolean; + Enable_Packet_RX_Handling : out Boolean) + is + Value : constant Register := Read_Register + (This, Data_Access_Control_Name); + + Reg : Data_Access_Control_Register with Import, + Address => Value'Address; + begin + CRC_Selection := Reg.crc; + CRC_Enable := To_Boolean (Reg.encrc); + Enable_Packet_TX_Handling := To_Boolean (Reg.enpactx); + Skip_2nd_Phase_Preamble_Detection := To_Boolean (Reg.skip2ph); + CRC_Data_Only_Enable := To_Boolean (Reg.crcdonly); + LSB_First_Enable := To_Boolean (Reg.lsbfrst); + Enable_Packet_RX_Handling := To_Boolean (Reg.enpacrx); + end Get_Data_Access_Control; + + ----------------------------- + -- Set_GPIO0_Configuration -- + ----------------------------- + + procedure Set_GPIO0_Configuration + (This : Si4432_Driver; + Pin_Function : GPIO_0_Function; + Pullup_Resistor_Enable : Boolean; + Driving_Capability : UInt2) + is + Reg : constant GPIO0_Configuration_Register := + (gpio => Pin_Function, + pup => From_Boolean (Pullup_Resistor_Enable), + gpiodrv => Driving_Capability); + Value : Register with Import, Address => Reg'Address; + begin + Write_Register (This, GPIO0_Configuration_Name, Value); + end Set_GPIO0_Configuration; + + ----------------------------- + -- Get_GPIO0_Configuration -- + ----------------------------- + + procedure Get_GPIO0_Configuration + (This : Si4432_Driver; + Pin_Function : out GPIO_0_Function; + Pullup_Resistor_Enable : out Boolean; + Driving_Capability : out UInt2) + is + Value : constant Register := Read_Register + (This, GPIO0_Configuration_Name); + + Reg : GPIO0_Configuration_Register with Import, + Address => Value'Address; + begin + Pin_Function := Reg.gpio; + Pullup_Resistor_Enable := To_Boolean (Reg.pup); + Driving_Capability := Reg.gpiodrv; + end Get_GPIO0_Configuration; + + ----------------------------- + -- Set_GPIO1_Configuration -- + ----------------------------- + + procedure Set_GPIO1_Configuration + (This : Si4432_Driver; + Pin_Function : GPIO_1_Function; + Pullup_Resistor_Enable : Boolean; + Driving_Capability : UInt2) + is + Reg : constant GPIO1_Configuration_Register := + (gpio => Pin_Function, + pup => From_Boolean (Pullup_Resistor_Enable), + gpiodrv => Driving_Capability); + Value : Register with Import, Address => Reg'Address; + begin + Write_Register (This, GPIO1_Configuration_Name, Value); + end Set_GPIO1_Configuration; + + ----------------------------- + -- Get_GPIO1_Configuration -- + ----------------------------- + + procedure Get_GPIO1_Configuration + (This : Si4432_Driver; + Pin_Function : out GPIO_1_Function; + Pullup_Resistor_Enable : out Boolean; + Driving_Capability : out UInt2) + is + Value : constant Register := Read_Register + (This, GPIO1_Configuration_Name); + + Reg : GPIO1_Configuration_Register with Import, + Address => Value'Address; + begin + Pin_Function := Reg.gpio; + Pullup_Resistor_Enable := To_Boolean (Reg.pup); + Driving_Capability := Reg.gpiodrv; + end Get_GPIO1_Configuration; + + ----------------------------- + -- Set_GPIO2_Configuration -- + ----------------------------- + + procedure Set_GPIO2_Configuration + (This : Si4432_Driver; + Pin_Function : GPIO_2_Function; + Pullup_Resistor_Enable : Boolean; + Driving_Capability : UInt2) + is + Reg : constant GPIO2_Configuration_Register := + (gpio => Pin_Function, + pup => From_Boolean (Pullup_Resistor_Enable), + gpiodrv => Driving_Capability); + Value : Register with Import, Address => Reg'Address; + begin + Write_Register (This, GPIO2_Configuration_Name, Value); + end Set_GPIO2_Configuration; + + ----------------------------- + -- Get_GPIO2_Configuration -- + ----------------------------- + + procedure Get_GPIO2_Configuration + (This : Si4432_Driver; + Pin_Function : out GPIO_2_Function; + Pullup_Resistor_Enable : out Boolean; + Driving_Capability : out UInt2) + is + Value : constant Register := Read_Register + (This, GPIO2_Configuration_Name); + + Reg : GPIO2_Configuration_Register with Import, + Address => Value'Address; + begin + Pin_Function := Reg.gpio; + Pullup_Resistor_Enable := To_Boolean (Reg.pup); + Driving_Capability := Reg.gpiodrv; + end Get_GPIO2_Configuration; + + --------------------------------------------- + -- Set_Crystal_Oscillator_Load_Capacitance -- + --------------------------------------------- + + procedure Set_Crystal_Oscillator_Load_Capacitance + (This : Si4432_Driver; + Tuning_Capacitance : UInt7; + Shft : Bit) + is + Reg : constant Crystal_Oscillator_Load_Capacitance_Register := + (xlc => Tuning_Capacitance, + xtalshft => Shft); + Value : Register with Import, Address => Reg'Address; + begin + Write_Register (This, Crystal_Oscillator_Load_Capacitance_Name, Value); + end Set_Crystal_Oscillator_Load_Capacitance; + + --------------------------------------------- + -- Get_Crystal_Oscillator_Load_Capacitance -- + --------------------------------------------- + + procedure Get_Crystal_Oscillator_Load_Capacitance + (This : Si4432_Driver; + Tuning_Capacitance : out UInt7; + Shft : out Bit) + is + Value : constant Register := Read_Register + (This, Crystal_Oscillator_Load_Capacitance_Name); + + Reg : Crystal_Oscillator_Load_Capacitance_Register with Import, + Address => Value'Address; + begin + Tuning_Capacitance := Reg.xlc; + Shft := Reg.xtalshft; + end Get_Crystal_Oscillator_Load_Capacitance; + + ----------------------- + -- Set_Packet_Length -- + ----------------------- + + procedure Set_Packet_Length + (This : Si4432_Driver; + Length : UInt8) is + begin + Write_Register (This, Packet_Length_Name, Register (Length)); + end Set_Packet_Length; + + ----------------------- + -- Get_Packet_Length -- + ----------------------- + + function Get_Packet_Length + (This : Si4432_Driver) + return UInt8 is + begin + return UInt8 (Read_Register (This, Packet_Length_Name)); + end Get_Packet_Length; + + -------------------------------- + -- Get_Received_Packet_Length -- + -------------------------------- + + function Get_Received_Packet_Length + (This : Si4432_Driver) + return UInt8 is + begin + return UInt8 (Read_Register (This, Received_Packet_Length_Name)); + end Get_Received_Packet_Length; + + -------------------------- + -- Set_Interrupt_Enable -- + -------------------------- + + procedure Set_Interrupt_Enable + (This : Si4432_Driver; + CRC_Error : Boolean := False; + Valid_Packet_Received : Boolean := False; + Packet_Sent : Boolean := False; + External_Interrupt : Boolean := False; + RX_FIFO_Almost_Full : Boolean := False; + TX_FIFO_Almost_Empty : Boolean := False; + TX_FIFO_Almost_Full : Boolean := False; + FIFO_Underflow_Overflow : Boolean := False; + POR : Boolean := True; + Chip_Ready : Boolean := True; + Low_Battery : Boolean := False; + Wake_Up_Timer : Boolean := False; + RSSI : Boolean := False; + Invalid_Preamble : Boolean := False; + Valid_Preamble : Boolean := False; + Sync_Word : Boolean := False) + is + Data : HAL.SPI.SPI_Data_8b (1 .. 2); + Reg1 : Interrupt_Enable_1_Register := + (encrcerror => From_Boolean (CRC_Error), + enpkvalid => From_Boolean (Valid_Packet_Received), + enpksent => From_Boolean (Packet_Sent), + enext => From_Boolean (External_Interrupt), + enrxffafull => From_Boolean (RX_FIFO_Almost_Full), + entxffaem => From_Boolean (TX_FIFO_Almost_Empty), + entxffafull => From_Boolean (TX_FIFO_Almost_Full), + enfferr => From_Boolean (FIFO_Underflow_Overflow)) + with Address => Data (1)'Address; + + Reg2 : Interrupt_Enable_2_Register := + (enpor => From_Boolean (POR), + enchiprdy => From_Boolean (Chip_Ready), + enlbd => From_Boolean (Low_Battery), + enwut => From_Boolean (Wake_Up_Timer), + enrssi => From_Boolean (RSSI), + enpreainval => From_Boolean (Invalid_Preamble), + enpreaval => From_Boolean (Valid_Preamble), + enswdet => From_Boolean (Sync_Word)) + with Address => Data (2)'Address; + + begin + Clear_Interrupts (This); + Write_Register (This, Interrupt_Enable_1_Name, Data); + Clear_Interrupts (This); + end Set_Interrupt_Enable; + + ---------------------------- + -- Set_Interrupt_Enable_1 -- + ---------------------------- + + procedure Set_Interrupt_Enable_1 + (This : Si4432_Driver; + CRC_Error : Boolean; + Valid_Packet_Received : Boolean; + Packet_Sent : Boolean; + External_Interrupt : Boolean; + RX_FIFO_Almost_Full : Boolean; + TX_FIFO_Almost_Empty : Boolean; + TX_FIFO_Almost_Full : Boolean; + FIFO_Underflow_Overflow : Boolean) + is + Reg : constant Interrupt_Enable_1_Register := + (encrcerror => From_Boolean (CRC_Error), + enpkvalid => From_Boolean (Valid_Packet_Received), + enpksent => From_Boolean (Packet_Sent), + enext => From_Boolean (External_Interrupt), + enrxffafull => From_Boolean (RX_FIFO_Almost_Full), + entxffaem => From_Boolean (TX_FIFO_Almost_Empty), + entxffafull => From_Boolean (TX_FIFO_Almost_Full), + enfferr => From_Boolean (FIFO_Underflow_Overflow)); + Value : Register with Import, Address => Reg'Address; + begin + Write_Register (This, Interrupt_Enable_1_Name, Value); + end Set_Interrupt_Enable_1; + + ---------------------------- + -- Get_Interrupt_Enable_1 -- + ---------------------------- + + procedure Get_Interrupt_Enable_1 + (This : Si4432_Driver; + CRC_Error : out Boolean; + Valid_Packet_Received : out Boolean; + Packet_Sent : out Boolean; + External_Interrupt : out Boolean; + RX_FIFO_Almost_Full : out Boolean; + TX_FIFO_Almost_Empty : out Boolean; + TX_FIFO_Almost_Full : out Boolean; + FIFO_Underflow_Overflow : out Boolean) + is + Value : constant Register := Read_Register + (This, Interrupt_Enable_1_Name); + + Reg : Interrupt_Enable_1_Register with Import, + Address => Value'Address; + begin + CRC_Error := To_Boolean (Reg.encrcerror); + Valid_Packet_Received := To_Boolean (Reg.enpkvalid); + Packet_Sent := To_Boolean (Reg.enpksent); + External_Interrupt := To_Boolean (Reg.enext); + RX_FIFO_Almost_Full := To_Boolean (Reg.enrxffafull); + TX_FIFO_Almost_Empty := To_Boolean (Reg.entxffaem); + TX_FIFO_Almost_Full := To_Boolean (Reg.entxffafull); + FIFO_Underflow_Overflow := To_Boolean (Reg.enfferr); + end Get_Interrupt_Enable_1; + + ---------------------------- + -- Set_Interrupt_Enable_2 -- + ---------------------------- + + procedure Set_Interrupt_Enable_2 + (This : Si4432_Driver; + POR : Boolean; + Chip_Ready : Boolean; + Low_Battery : Boolean; + Wake_Up_Timer : Boolean; + RSSI : Boolean; + Invalid_Preamble : Boolean; + Valid_Preamble : Boolean; + Sync_Word : Boolean) + is + Reg : constant Interrupt_Enable_2_Register := + (enpor => From_Boolean (POR), + enchiprdy => From_Boolean (Chip_Ready), + enlbd => From_Boolean (Low_Battery), + enwut => From_Boolean (Wake_Up_Timer), + enrssi => From_Boolean (RSSI), + enpreainval => From_Boolean (Invalid_Preamble), + enpreaval => From_Boolean (Valid_Preamble), + enswdet => From_Boolean (Sync_Word)); + + Value : Register with Import, Address => Reg'Address; + begin + Write_Register (This, Interrupt_Enable_2_Name, Value); + end Set_Interrupt_Enable_2; + + ---------------------------- + -- Get_Interrupt_Enable_2 -- + ---------------------------- + + procedure Get_Interrupt_Enable_2 + (This : Si4432_Driver; + POR : out Boolean; + Chip_Ready : out Boolean; + Low_Battery : out Boolean; + Wake_Up_Timer : out Boolean; + RSSI : out Boolean; + Invalid_Preamble : out Boolean; + Valid_Preamble : out Boolean; + Sync_Word : out Boolean) + is + Value : constant Register := + Read_Register (This, Interrupt_Enable_2_Name); + + Reg : Interrupt_Enable_2_Register with Import, + Address => Value'Address; + + begin + POR := To_Boolean (Reg.enpor); + Chip_Ready := To_Boolean (Reg.enchiprdy); + Low_Battery := To_Boolean (Reg.enlbd); + Wake_Up_Timer := To_Boolean (Reg.enwut); + RSSI := To_Boolean (Reg.enrssi); + Invalid_Preamble := To_Boolean (Reg.enpreainval); + Valid_Preamble := To_Boolean (Reg.enpreaval); + Sync_Word := To_Boolean (Reg.enswdet); + end Get_Interrupt_Enable_2; + + ----------------------------- + -- Set_IF_Filter_Bandwidth -- + ----------------------------- + + procedure Set_IF_Filter_Bandwidth + (This : Si4432_Driver; + Coefficient : UInt4; + Decimation_Rates : UInt3; + Bypass_Decimate : Boolean) + is + Reg : constant IF_Filter_Bandwidth_Register := + (filset => Coefficient, + ndec_exp => Decimation_Rates, + dwn3_bypass => From_Boolean (Bypass_Decimate)); + + Value : Register with Import, Address => Reg'Address; + begin + Write_Register (This, IF_Filter_Bandwidth_Name, Value); + end Set_IF_Filter_Bandwidth; + + ----------------------------- + -- Get_IF_Filter_Bandwidth -- + ----------------------------- + + procedure Get_IF_Filter_Bandwidth + (This : Si4432_Driver; + Coefficient : out UInt4; + Decimation_Rates : out UInt3; + Bypass_Decimate : out Boolean) + is + Value : constant Register := + Read_Register (This, IF_Filter_Bandwidth_Name); + + Reg : IF_Filter_Bandwidth_Register with Import, + Address => Value'Address; + begin + Coefficient := Reg.filset; + Decimation_Rates := Reg.ndec_exp; + Bypass_Decimate := To_Boolean (Reg.dwn3_bypass); + end Get_IF_Filter_Bandwidth; + + ------------------------------------------ + -- Set_Clock_Recovery_Oversampling_Rate -- + ------------------------------------------ + + procedure Set_Clock_Recovery_Oversampling_Rate + (This : Si4432_Driver; + Value : Clock_Recovery_Oversampling) + is + Data : HAL.SPI.SPI_Data_8b (1 .. 2); + Reg : Clock_Recovery_Offset_2_Register with Import, + Address => Data (2)'Address; + + begin + Data (2) := UInt8 (Read_Register (This, Clock_Recovery_Offset_2_Name)); + Data (1) := UInt8 (Unsigned_16 (Value) and 16#FF#); + Reg.rxosr := UInt3 (Shift_Right (Unsigned_16 (Value), 8)); + + Write_Register (This, Clock_Recovery_Oversampling_Rate_Name, Data); + end Set_Clock_Recovery_Oversampling_Rate; + + ------------------------------------------ + -- Get_Clock_Recovery_Oversampling_Rate -- + ------------------------------------------ + + function Get_Clock_Recovery_Oversampling_Rate + (This : Si4432_Driver) + return Clock_Recovery_Oversampling + is + Data : HAL.SPI.SPI_Data_8b (1 .. 2); + Reg : Clock_Recovery_Offset_2_Register with Import, + Address => Data (2)'Address; + begin + Read_Register (This, Clock_Recovery_Oversampling_Rate_Name, Data); + + return Clock_Recovery_Oversampling + (Shift_Left (Unsigned_16 (Reg.rxosr), 8) + Unsigned_16 (Data (1))); + end Get_Clock_Recovery_Oversampling_Rate; + + ------------------------------- + -- Set_Clock_Recovery_Offset -- + ------------------------------- + + procedure Set_Clock_Recovery_Offset + (This : Si4432_Driver; + NCO_Offset : Clock_Recovery_Offset; + Skip_2nd_Phase : Boolean) + is + Value : Unsigned_32 := Unsigned_32 (NCO_Offset); + Data : HAL.SPI.SPI_Data_8b (1 .. 3); + Reg : Clock_Recovery_Offset_2_Register with Import, + Address => Data (1)'Address; + + begin + Data (1) := UInt8 (Read_Register (This, Clock_Recovery_Offset_2_Name)); + + Data (3) := UInt8 (Value and 16#FF#); + Value := Shift_Right (Value, 8); + Data (2) := UInt8 (Value and 16#FF#); + Reg.ncoff := UInt4 (Shift_Right (Value, 8)); + Reg.skip2phth := From_Boolean (Skip_2nd_Phase); + + Write_Register (This, Clock_Recovery_Offset_2_Name, Data); + end Set_Clock_Recovery_Offset; + + ------------------------------- + -- Get_Clock_Recovery_Offset -- + ------------------------------- + + procedure Get_Clock_Recovery_Offset + (This : Si4432_Driver; + NCO_Offset : out Clock_Recovery_Offset; + Skip_2nd_Phase : out Boolean) + is + Data : HAL.SPI.SPI_Data_8b (1 .. 3); + Reg : Clock_Recovery_Offset_2_Register with Import, + Address => Data (1)'Address; + + Result : Unsigned_32; + begin + Read_Register (This, Clock_Recovery_Offset_2_Name, Data); + + Result := Shift_Left (Unsigned_32 (Reg.ncoff), 8); + Result := Result + Unsigned_32 (Data (2)); + Result := Shift_Left (Result, 8); + Result := Result + Unsigned_32 (Data (3)); + + NCO_Offset := Clock_Recovery_Offset (Result); + Skip_2nd_Phase := To_Boolean (Reg.skip2phth); + end Get_Clock_Recovery_Offset; + + ----------------------------------------- + -- Set_Clock_Recovery_Timing_Loop_Gain -- + ----------------------------------------- + + procedure Set_Clock_Recovery_Timing_Loop_Gain + (This : Si4432_Driver; + Gain : Clock_Recovery_Timing_Loop_Gain; + Multiplying_By_2 : Boolean; + Compensation_Enable : Boolean) + is + Local : constant Unsigned_16 := Unsigned_16 (Gain); + Data : HAL.SPI.SPI_Data_8b (1 .. 2); + Reg : Clock_Recovery_Timing_Loop_Gain_1_Register := + (crgain => UInt3 (Shift_Right (Local, 8)), + cgainx2 => From_Boolean (Multiplying_By_2), + rxncocomp => From_Boolean (Compensation_Enable), + Reserved => 0) with Address => Data (1)'Address; + begin + Data (2) := UInt8 (Local and 16#FF#); + + Write_Register (This, Clock_Recovery_Timing_Loop_Gain_1_Name, Data); + end Set_Clock_Recovery_Timing_Loop_Gain; + + ----------------------------------------- + -- Get_Clock_Recovery_Timing_Loop_Gain -- + ----------------------------------------- + + procedure Get_Clock_Recovery_Timing_Loop_Gain + (This : Si4432_Driver; + Gain : out Clock_Recovery_Timing_Loop_Gain; + Multiplying_By_2 : out Boolean; + Compensation_Enable : out Boolean) + is + Data : HAL.SPI.SPI_Data_8b (1 .. 2); + Reg : Clock_Recovery_Timing_Loop_Gain_1_Register with Import, + Address => Data (1)'Address; + + begin + Read_Register (This, Clock_Recovery_Timing_Loop_Gain_1_Name, Data); + + Gain := Clock_Recovery_Timing_Loop_Gain + (Shift_Left (Unsigned_16 (Reg.crgain), 8) + Unsigned_16 (Data (2))); + Multiplying_By_2 := To_Boolean (Reg.cgainx2); + Compensation_Enable := To_Boolean (Reg.rxncocomp); + end Get_Clock_Recovery_Timing_Loop_Gain; + + ------------------------------------- + -- Set_AFC_Loop_Gearshift_Override -- + ------------------------------------- + + procedure Set_AFC_Loop_Gearshift_Override + (This : Si4432_Driver; + Reset_Preamble : Boolean; + Taps : Boolean; + Bypass : Boolean; + AFC_High_Gear : UInt3; + AFC : Boolean; + AFC_Wideband : Boolean) + is + Reg : constant AFC_Loop_Gearshift_Override_Register := + (ph0size => From_Boolean (Reset_Preamble), + matap => From_Boolean (Taps), + p5bypass => From_Boolean (Bypass), + afcgearh => AFC_High_Gear, + enafc => From_Boolean (AFC), + afcbd => From_Boolean (AFC_Wideband)); + + Value : Register with Import, Address => Reg'Address; + begin + Write_Register (This, AFC_Loop_Gearshift_Override_Name, Value); + end Set_AFC_Loop_Gearshift_Override; + + ------------------------------------- + -- Get_AFC_Loop_Gearshift_Override -- + ------------------------------------- + + procedure Get_AFC_Loop_Gearshift_Override + (This : Si4432_Driver; + Reset_Preamble : out Boolean; + Taps : out Boolean; + Bypass : out Boolean; + AFC_High_Gear : out UInt3; + AFC : out Boolean; + AFC_Wideband : out Boolean) + is + Value : constant Register := Read_Register + (This, AFC_Loop_Gearshift_Override_Name); + Reg : AFC_Loop_Gearshift_Override_Register with Import, + Address => Value'Address; + begin + Reset_Preamble := To_Boolean (Reg.ph0size); + Taps := To_Boolean (Reg.matap); + Bypass := To_Boolean (Reg.p5bypass); + AFC_High_Gear := Reg.afcgearh; + AFC := To_Boolean (Reg.enafc); + AFC_Wideband := To_Boolean (Reg.afcbd); + end Get_AFC_Loop_Gearshift_Override; + + --------------------- + -- Set_AFC_Limiter -- + --------------------- + + procedure Set_AFC_Limiter + (This : Si4432_Driver; + Value : UInt8) is + begin + Write_Register (This, AFC_Limiter_Name, Register (Value)); + end Set_AFC_Limiter; + + --------------------- + -- Get_AFC_Limiter -- + --------------------- + + function Get_AFC_Limiter + (This : Si4432_Driver) + return UInt8 is + begin + return UInt8 (Read_Register (This, AFC_Limiter_Name)); + end Get_AFC_Limiter; + + ------------------------- + -- Set_Preamble_Length -- + ------------------------- + + procedure Set_Preamble_Length + (This : Si4432_Driver; + Value : UInt9) + is + Local : constant Unsigned_16 := Unsigned_16 (Value); + Data : HAL.SPI.SPI_Data_8b (1 .. 2); + Reg : Header_Control_2_Register with Import, + Address => Data (1)'Address; + + begin + Data (1) := UInt8 (Read_Register (This, Header_Control_2_Name)); + Reg.prealen := Bit (Unsigned_16 (Value) and 2#1_0000_0000#); + Data (2) := UInt8 (Local and 16#FF#); + + Write_Register (This, Header_Control_2_Name, Data); + end Set_Preamble_Length; + + ------------------------- + -- Get_Preamble_Length -- + ------------------------- + + function Get_Preamble_Length + (This : Si4432_Driver) + return UInt9 + is + Data : HAL.SPI.SPI_Data_8b (1 .. 2); + Reg : Header_Control_2_Register with Import, + Address => Data (1)'Address; + + begin + Read_Register (This, Header_Control_2_Name, Data); + + return UInt9 + (Shift_Left (Unsigned_16 (Reg.prealen), 8) + Unsigned_16 (Data (2))); + end Get_Preamble_Length; + + ------------------------------------ + -- Set_Preamble_Detection_Control -- + ------------------------------------ + + procedure Set_Preamble_Detection_Control + (This : Si4432_Driver; + RSSI_Offset : UInt3; + Detection_Threshold : UInt5) + is + Reg : constant Preamble_Detection_Control_1_Register := + (rssi_offset => RSSI_Offset, + preath => Detection_Threshold); + + Value : Register with Import, Address => Reg'Address; + begin + Write_Register (This, Preamble_Detection_Control_1_Name, Value); + end Set_Preamble_Detection_Control; + + ------------------------------------- + -- Get_Preamble_Detection_Control -- + ------------------------------------- + + procedure Get_Preamble_Detection_Control + (This : Si4432_Driver; + RSSI_Offset : out UInt3; + Detection_Threshold : out UInt5) + is + Value : constant Register := Read_Register + (This, Preamble_Detection_Control_1_Name); + + Reg : constant Preamble_Detection_Control_1_Register with Import, + Address => Value'Address; + begin + RSSI_Offset := Reg.rssi_offset; + Detection_Threshold := Reg.preath; + end Get_Preamble_Detection_Control; + + ---------------------- + -- Set_AGC_Override -- + ---------------------- + + procedure Set_AGC_Override + (This : Si4432_Driver; + Gain_Override : AGC_Override_Gain; + LNA_Gain_Select : Boolean; + Automatic_Gain_Control : Boolean; + Sgin : Boolean) + is + Reg : constant AGC_Override_Register := + (pga => (if Gain_Override = 0 then 0 + elsif Gain_Override = 3 then 2#0001# + elsif Gain_Override = 6 then 2#0010# + elsif Gain_Override = 12 then 2#0100# + else 2#1000#), + lnagain => From_Boolean (LNA_Gain_Select), + agcen => From_Boolean (Automatic_Gain_Control), + sgin => From_Boolean (Sgin), + Reserved => 0); + + Value : Register with Import, Address => Reg'Address; + begin + Write_Register (This, AGC_Override_Name, Value); + end Set_AGC_Override; + + ---------------------- + -- Get_AGC_Override -- + ---------------------- + + procedure Get_AGC_Override + (This : Si4432_Driver; + Gain_Override : out AGC_Override_Gain; + LNA_Gain_Select : out Boolean; + Automatic_Gain_Control : out Boolean; + Sgin : out Boolean) + is + Value : constant Register := Read_Register (This, AGC_Override_Name); + Reg : AGC_Override_Register with Import, Address => Value'Address; + begin + Gain_Override := + (if Reg.pga = 2#0000# then 0 + elsif Reg.pga = 2#0001# then 3 + elsif Reg.pga = 2#0010# then 6 + elsif Reg.pga = 2#0100# then 12 + else 24); + + LNA_Gain_Select := To_Boolean (Reg.lnagain); + Automatic_Gain_Control := To_Boolean (Reg.agcen); + Sgin := To_Boolean (Reg.sgin); + end Get_AGC_Override; + + ------------------ + -- Set_TX_Power -- + ------------------ + + procedure Set_TX_Power + (This : Si4432_Driver; + Output_Power : UInt3; + LNA_Switch : Boolean) + is + Reg : constant TX_Power_Register := + (txpow => Output_Power, + lna_sw => From_Boolean (LNA_Switch), + Reserved => 0); + + Value : Register with Import, Address => Reg'Address; + begin + Write_Register (This, TX_Power_Name, Value); + end Set_TX_Power; + + ------------------ + -- Get_TX_Power -- + ------------------ + + procedure Get_TX_Power + (This : Si4432_Driver; + Output_Power : out UInt3; + LNA_Switch : out Boolean) + is + Value : constant Register := Read_Register (This, TX_Power_Name); + Reg : TX_Power_Register with Import, Address => Value'Address; + begin + Output_Power := Reg.txpow; + LNA_Switch := To_Boolean (Reg.lna_sw); + end Get_TX_Power; + + --------------------------------------------- + -- Set_Operating_Mode_And_Function_Control -- + --------------------------------------------- + + procedure Set_Operating_Mode_And_Function_Control + (This : Si4432_Driver; + READY_Mode : Boolean := True; + TUNE_Mode : Boolean := False; + RX_On : Boolean := False; + TX_On : Boolean := False; + Oscillator_Select : Crystal_Oscillator := RC_Oscillator; + Wake_Up_Timer : Boolean := False; + Low_Battery_Detect : Boolean := False; + TX_FIFO_Reset : Boolean := False; + RX_FIFO_Reset : Boolean := False; + Low_Duty_Cycle_Mode : Boolean := False; + Automatic_Transmission : Boolean := False; + RX_Multi_Packet : Boolean := False; + Antenna_Diversity : UInt3 := 0) + is + Data : HAL.SPI.SPI_Data_8b (1 .. 2); + Reg1 : Operating_Mode_And_Function_Control_1_Register := + (xton => From_Boolean (READY_Mode), + pllon => From_Boolean (TUNE_Mode), + rxon => From_Boolean (RX_On), + txon => From_Boolean (TX_On), + x32ksel => Oscillator_Select, + enwt => From_Boolean (Wake_Up_Timer), + enlbd => From_Boolean (Low_Battery_Detect), + swres => 0) with Address => Data (1)'Address; + + Reg2 : Operating_Mode_And_Function_Control_2_Register := + (ffclrtx => From_Boolean (TX_FIFO_Reset), + ffclrrx => From_Boolean (RX_FIFO_Reset), + enldm => From_Boolean (Low_Duty_Cycle_Mode), + autotx => From_Boolean (Automatic_Transmission), + rxmpk => From_Boolean (RX_Multi_Packet), + antdiv => Antenna_Diversity) + with Address => Data (2)'Address; + begin + Write_Register (This, Operating_Mode_And_Function_Control_1_Name, Data); + end Set_Operating_Mode_And_Function_Control; + + ----------------------------------------------- + -- Set_Operating_Mode_And_Function_Control_1 -- + ----------------------------------------------- + + procedure Set_Operating_Mode_And_Function_Control_1 + (This : Si4432_Driver; + READY_Mode : Boolean; + TUNE_Mode : Boolean; + RX_On : Boolean; + TX_On : Boolean; + Oscillator_Select : Crystal_Oscillator; + Wake_Up_Timer : Boolean; + Low_Battery_Detect : Boolean; + Software_Reset : Boolean) + is + Reg : constant Operating_Mode_And_Function_Control_1_Register := + (xton => From_Boolean (READY_Mode), + pllon => From_Boolean (TUNE_Mode), + rxon => From_Boolean (RX_On), + txon => From_Boolean (TX_On), + x32ksel => Oscillator_Select, + enwt => From_Boolean (Wake_Up_Timer), + enlbd => From_Boolean (Low_Battery_Detect), + swres => From_Boolean (Software_Reset)); + + Value : Register with Import, Address => Reg'Address; + begin + Write_Register (This, Operating_Mode_And_Function_Control_1_Name, Value); + end Set_Operating_Mode_And_Function_Control_1; + + ----------------------------------------------- + -- Get_Operating_Mode_And_Function_Control_1 -- + ----------------------------------------------- + + procedure Get_Operating_Mode_And_Function_Control_1 + (This : Si4432_Driver; + READY_Mode : out Boolean; + TUNE_Mode : out Boolean; + RX_On : out Boolean; + TX_On : out Boolean; + Oscillator_Select : out Crystal_Oscillator; + Wake_Up_Timer : out Boolean; + Low_Battery_Detect : out Boolean) + is + Value : constant Register := Read_Register + (This, Operating_Mode_And_Function_Control_1_Name); + Reg : Operating_Mode_And_Function_Control_1_Register with Import, + Address => Value'Address; + begin + READY_Mode := To_Boolean (Reg.xton); + TUNE_Mode := To_Boolean (Reg.pllon); + RX_On := To_Boolean (Reg.rxon); + TX_On := To_Boolean (Reg.txon); + Oscillator_Select := Reg.x32ksel; + Wake_Up_Timer := To_Boolean (Reg.enwt); + Low_Battery_Detect := To_Boolean (Reg.enlbd); + end Get_Operating_Mode_And_Function_Control_1; + + ----------------------------------------------- + -- Set_Operating_Mode_And_Function_Control_2 -- + ----------------------------------------------- + + procedure Set_Operating_Mode_And_Function_Control_2 + (This : Si4432_Driver; + TX_FIFO_Reset : Boolean; + RX_FIFO_Reset : Boolean; + Low_Duty_Cycle_Mode : Boolean; + Automatic_Transmission : Boolean; + RX_Multi_Packet : Boolean; + Antenna_Diversity : UInt3) + is + Reg : constant Operating_Mode_And_Function_Control_2_Register := + (ffclrtx => From_Boolean (TX_FIFO_Reset), + ffclrrx => From_Boolean (RX_FIFO_Reset), + enldm => From_Boolean (Low_Duty_Cycle_Mode), + autotx => From_Boolean (Automatic_Transmission), + rxmpk => From_Boolean (RX_Multi_Packet), + antdiv => Antenna_Diversity); + + Value : Register with Import, Address => Reg'Address; + begin + Write_Register (This, Operating_Mode_And_Function_Control_2_Name, Value); + end Set_Operating_Mode_And_Function_Control_2; + + ----------------------------------------------- + -- Get_Operating_Mode_And_Function_Control_2 -- + ----------------------------------------------- + + procedure Get_Operating_Mode_And_Function_Control_2 + (This : Si4432_Driver; + TX_FIFO_Reset : out Boolean; + RX_FIFO_Reset : out Boolean; + Low_Duty_Cycle_Mode : out Boolean; + Automatic_Transmission : out Boolean; + RX_Multi_Packet : out Boolean; + Antenna_Diversity : out UInt3) + is + Value : constant Register := Read_Register + (This, Operating_Mode_And_Function_Control_2_Name); + + Reg : Operating_Mode_And_Function_Control_2_Register with Import, + Address => Value'Address; + begin + TX_FIFO_Reset := To_Boolean (Reg.ffclrtx); + RX_FIFO_Reset := To_Boolean (Reg.ffclrrx); + Low_Duty_Cycle_Mode := To_Boolean (Reg.enldm); + Automatic_Transmission := To_Boolean (Reg.autotx); + RX_Multi_Packet := To_Boolean (Reg.rxmpk); + Antenna_Diversity := Reg.antdiv; + end Get_Operating_Mode_And_Function_Control_2; + + ----------------------- + -- Get_Device_Status -- + ----------------------- + + procedure Get_Device_Status + (This : Si4432_Driver; + Power : out Chip_State; + Frequency_Error : out Boolean; + Header_Error : out Boolean; + RX_FIFO_Empty : out Boolean; + RX_TX_FIFO_Underflow : out Boolean; + RX_TX_FIFO_Overflow : out Boolean) + is + Value : constant Register := Read_Register (This, Device_Status_Name); + Reg : Device_Status_Register with Import, + Address => Value'Address; + begin + Power := Reg.cps; + Frequency_Error := To_Boolean (Reg.freqerr); + Header_Error := To_Boolean (Reg.headerr); + RX_FIFO_Empty := To_Boolean (Reg.rxffem); + RX_TX_FIFO_Underflow := To_Boolean (Reg.ffunfl); + RX_TX_FIFO_Overflow := To_Boolean (Reg.ffovfl); + end Get_Device_Status; + + -------------------------------------- + -- Set_Microcontroller_Output_Clock -- + -------------------------------------- + + procedure Set_Microcontroller_Output_Clock + (This : Si4432_Driver; + Clock : Microcontroller_Clock; + Low_Frequency_Clock : Boolean; + Tail : Clock_Tail) + is + Reg : constant Microcontroller_Output_Clock_Register := + (mclk => Clock, + enlfc => From_Boolean (Low_Frequency_Clock), + clkt => (if Tail = 0 then 2#00# + elsif Tail = 128 then 2#01# + elsif Tail = 256 then 2#10# + else 2#11#), + Reserved => 0); + + Value : Register with Import, Address => Reg'Address; + begin + Write_Register (This, Microcontroller_Output_Clock_Name, Value); + end Set_Microcontroller_Output_Clock; + + -------------------------------------- + -- Get_Microcontroller_Output_Clock -- + -------------------------------------- + + procedure Get_Microcontroller_Output_Clock + (This : Si4432_Driver; + Clock : out Microcontroller_Clock; + Low_Frequency_Clock : out Boolean; + Tail : out Clock_Tail) + is + Value : constant Register := Read_Register + (This, Microcontroller_Output_Clock_Name); + Reg : Microcontroller_Output_Clock_Register with Import, + Address => Value'Address; + begin + Clock := Reg.mclk; + Low_Frequency_Clock := To_Boolean (Reg.enlfc); + Tail := (if Reg.clkt = 2#00# then 0 + elsif Reg.clkt = 2#01# then 128 + elsif Reg.clkt = 2#10# then 256 + else 512); + end Get_Microcontroller_Output_Clock; + + ------------------------------- + -- Set_IO_Port_Configuration -- + ------------------------------- + + procedure Set_IO_Port_Configuration + (This : Si4432_Driver; + Direct_GPIO0 : Boolean; + Direct_GPIO1 : Boolean; + Direct_GPIO2 : Boolean; + Interrupt_Output_SDO : Boolean) + is + Reg : constant IO_Port_Configuration_Register := + (dio0 => From_Boolean (Direct_GPIO0), + dio1 => From_Boolean (Direct_GPIO1), + dio2 => From_Boolean (Direct_GPIO2), + itsdo => From_Boolean (Interrupt_Output_SDO), + extitst0 => 0, + extitst1 => 0, + extitst2 => 0, + Reserved => 0); + + Value : Register with Import, Address => Reg'Address; + begin + Write_Register (This, IO_Port_Configuration_Name, Value); + end Set_IO_Port_Configuration; + + ------------------------------- + -- Get_IO_Port_Configuration -- + ------------------------------- + + procedure Get_IO_Port_Configuration + (This : Si4432_Driver; + Direct_GPIO0 : out Boolean; + Direct_GPIO1 : out Boolean; + Direct_GPIO2 : out Boolean; + Interrupt_Output_SDO : out Boolean; + External_0_Interrupt : out Boolean; + External_1_Interrupt : out Boolean; + External_2_Interrupt : out Boolean) + is + Value : constant Register := Read_Register + (This, IO_Port_Configuration_Name); + + Reg : IO_Port_Configuration_Register with Import, + Address => Value'Address; + begin + Direct_GPIO0 := To_Boolean (Reg.dio0); + Direct_GPIO1 := To_Boolean (Reg.dio1); + Direct_GPIO2 := To_Boolean (Reg.dio2); + Interrupt_Output_SDO := To_Boolean (Reg.itsdo); + External_0_Interrupt := To_Boolean (Reg.extitst0); + External_1_Interrupt := To_Boolean (Reg.extitst1); + External_2_Interrupt := To_Boolean (Reg.extitst2); + end Get_IO_Port_Configuration; + + --------------------------- + -- Set_ADC_Configuration -- + --------------------------- + + procedure Set_ADC_Configuration + (This : Si4432_Driver; + Sensor_Amplifier_Gain : UInt2; + Reference_Voltage : UInt2; + Input_Source : ADC_Input_Source; + Measurement_Start : Boolean) + is + Reg : constant ADC_Configuration_Register := + (adcgain => Sensor_Amplifier_Gain, + adcref => Reference_Voltage, + adcsel => Input_Source, + adcstart => From_Boolean (Measurement_Start)); + + Value : Register with Import, Address => Reg'Address; + begin + Write_Register (This, ADC_Configuration_Name, Value); + end Set_ADC_Configuration; + + --------------------------- + -- Get_ADC_Configuration -- + --------------------------- + + procedure Get_ADC_Configuration + (This : Si4432_Driver; + Sensor_Amplifier_Gain : out UInt2; + Reference_Voltage : out UInt2; + Input_Source : out ADC_Input_Source; + Measurement_Start : out Boolean) + is + Value : constant Register := Read_Register + (This, ADC_Configuration_Name); + + Reg : ADC_Configuration_Register with Import, + Address => Value'Address; + begin + Sensor_Amplifier_Gain := Reg.adcgain; + Reference_Voltage := Reg.adcref; + Input_Source := Reg.adcsel; + Measurement_Start := To_Boolean (Reg.adcstart); + end Get_ADC_Configuration; + + ------------------------------------- + -- Set_ADC_Sensor_Amplifier_Offset -- + ------------------------------------- + + procedure Set_ADC_Sensor_Amplifier_Offset + (This : Si4432_Driver; + Amplifier_Offset : ADC_Sensor_Amplifier_Offset) + is + Local : constant ADC_Sensor_Amplifier_Offset := Amplifier_Offset; + Data : UInt4 with Import, Address => Local'Address; + Reg : constant ADC_Sensor_Amplifier_Offset_Register := + (adcoffs => Data, + Reserved => 0); + Value : Register with Import, Address => Reg'Address; + begin + Write_Register (This, ADC_Sensor_Amplifier_Offset_Name, Value); + end Set_ADC_Sensor_Amplifier_Offset; + + ------------------------------------- + -- Get_ADC_Sensor_Amplifier_Offset -- + ------------------------------------- + + function Get_ADC_Sensor_Amplifier_Offset + (This : Si4432_Driver) + return ADC_Sensor_Amplifier_Offset + is + Value : constant Register := Read_Register + (This, ADC_Sensor_Amplifier_Offset_Name); + Reg : ADC_Sensor_Amplifier_Offset_Register with Import, + Address => Value'Address; + Data : ADC_Sensor_Amplifier_Offset with Import, + Address => Reg.adcoffs'Address; + begin + return Data; + end Get_ADC_Sensor_Amplifier_Offset; + + ------------------- + -- Get_ADC_Value -- + ------------------- + + function Get_ADC_Value + (This : Si4432_Driver) + return UInt8 is + begin + return UInt8 (Read_Register (This, ADC_Value_Name)); + end Get_ADC_Value; + + ---------------------------------------- + -- Set_Temperature_Sensor_Calibration -- + ---------------------------------------- + + procedure Set_Temperature_Sensor_Calibration + (This : Si4432_Driver; + Trim_Value : UInt4; + Trim : Boolean; + Offset : Boolean; + Sensor_Range : Temperature_Sensor_Range) + is + Reg : constant Temperature_Sensor_Calibration_Register := + (tstrim => Trim_Value, + entstrim => From_Boolean (Trim), + entsoffs => From_Boolean (Offset), + tsrange => Sensor_Range); + + Value : Register with Import, Address => Reg'Address; + begin + Write_Register (This, Temperature_Sensor_Calibration_Name, Value); + end Set_Temperature_Sensor_Calibration; + + ---------------------------------------- + -- Get_Temperature_Sensor_Calibration -- + ---------------------------------------- + + procedure Get_Temperature_Sensor_Calibration + (This : Si4432_Driver; + Trim_Value : out UInt4; + Trim : out Boolean; + Offset : out Boolean; + Sensor_Range : out Temperature_Sensor_Range) + is + Value : constant Register := Read_Register + (This, Temperature_Sensor_Calibration_Name); + + Reg : Temperature_Sensor_Calibration_Register with Import, + Address => Value'Address; + begin + Trim_Value := Reg.tstrim; + Trim := To_Boolean (Reg.entstrim); + Offset := To_Boolean (Reg.entsoffs); + Sensor_Range := Reg.tsrange; + end Get_Temperature_Sensor_Calibration; + + ---------------------------------- + -- Set_Temperature_Value_Offset -- + ---------------------------------- + + procedure Set_Temperature_Value_Offset + (This : Si4432_Driver; + Value : UInt8) is + begin + Write_Register (This, Temperature_Value_Offset_Name, Register (Value)); + end Set_Temperature_Value_Offset; + + ---------------------------------- + -- Get_Temperature_Value_Offset -- + ---------------------------------- + + function Get_Temperature_Value_Offset + (This : Si4432_Driver) + return UInt8 is + begin + return UInt8 (Read_Register (This, Temperature_Value_Offset_Name)); + end Get_Temperature_Value_Offset; + + ------------------------------ + -- Set_Wake_Up_Timer_Period -- + ------------------------------ + + procedure Set_Wake_Up_Timer_Period + (This : Si4432_Driver; + Value : Wake_Up_Timer_Period) + is + Local : constant Unsigned_16 := Unsigned_16 (Value); + Data : HAL.SPI.SPI_Data_8b (1 .. 2); + begin + Data (1) := UInt8 (Shift_Right (Local, 8)); + Data (2) := UInt8 (Local and 16#FF#); + + Write_Register (This, Wake_Up_Timer_Period_2_Name, Data); + end Set_Wake_Up_Timer_Period; + + ------------------------------ + -- Get_Wake_Up_Timer_Period -- + ------------------------------ + + function Get_Wake_Up_Timer_Period + (This : Si4432_Driver) + return Wake_Up_Timer_Period + is + Data : HAL.SPI.SPI_Data_8b (1 .. 2); + begin + Read_Register (This, Wake_Up_Timer_Period_2_Name, Data); + + return Wake_Up_Timer_Period + (Shift_Left (Unsigned_16 (Data (1)), 8) + Unsigned_16 (Data (2))); + end Get_Wake_Up_Timer_Period; + + ------------------------------------- + -- Get_Wake_Up_Timer_Current_Value -- + ------------------------------------- + + function Get_Wake_Up_Timer_Current_Value + (This : Si4432_Driver) + return UInt16 + is + Data : HAL.SPI.SPI_Data_8b (1 .. 2); + begin + Read_Register (This, Wake_Up_Timer_Value_1_Name, Data); + + return UInt16 + (Shift_Left (Unsigned_16 (Data (1)), 8) + Unsigned_16 (Data (2))); + end Get_Wake_Up_Timer_Current_Value; + + -------------------------------- + -- Set_Wake_Up_Timer_Exponent -- + -------------------------------- + + procedure Set_Wake_Up_Timer_Exponent + (This : Si4432_Driver; + Value : Wake_Up_Timer_Exponent) + is + Reg : constant Wake_Up_Timer_Period_1_Register := + (wtr => UInt4 (Value), + Reserved => 0); + + Data : Register with Import, Address => Reg'Address; + begin + Write_Register (This, Wake_Up_Timer_Period_1_Name, Data); + end Set_Wake_Up_Timer_Exponent; + + -------------------------------- + -- Get_Wake_Up_Timer_Exponent -- + -------------------------------- + + function Get_Wake_Up_Timer_Exponent + (This : Si4432_Driver) + return Wake_Up_Timer_Exponent + is + Value : constant Register := Read_Register + (This, Wake_Up_Timer_Period_1_Name); + + Reg : Wake_Up_Timer_Period_1_Register with Import, + Address => Value'Address; + begin + return Wake_Up_Timer_Exponent (Reg.wtr); + end Get_Wake_Up_Timer_Exponent; + + -------------------------------------- + -- Set_Low_Duty_Cycle_Mode_Duration -- + -------------------------------------- + + procedure Set_Low_Duty_Cycle_Mode_Duration + (This : Si4432_Driver; + Value : Low_Duty_Cycle_Mode_Duration) is + begin + Write_Register + (This, Low_Duty_Cycle_Mode_Duration_Name, Register (Value)); + end Set_Low_Duty_Cycle_Mode_Duration; + + -------------------------------------- + -- Get_Low_Duty_Cycle_Mode_Duration -- + -------------------------------------- + + function Get_Low_Duty_Cycle_Mode_Duration + (This : Si4432_Driver) + return Low_Duty_Cycle_Mode_Duration is + begin + return Low_Duty_Cycle_Mode_Duration + (Read_Register (This, Low_Duty_Cycle_Mode_Duration_Name)); + end Get_Low_Duty_Cycle_Mode_Duration; + + ---------------------------------------- + -- Set_Low_Battery_Detector_Threshold -- + ---------------------------------------- + + procedure Set_Low_Battery_Detector_Threshold + (This : Si4432_Driver; + Value : UInt5) + is + Reg : constant Low_Battery_Detector_Threshold_Register := + (lbdt => Value, + Reserved => 0); + + Data : Register with Import, Address => Reg'Address; + begin + Write_Register (This, Low_Battery_Detector_Threshold_Name, Data); + end Set_Low_Battery_Detector_Threshold; + + ---------------------------------------- + -- Get_Low_Battery_Detector_Threshold -- + ---------------------------------------- + + function Get_Low_Battery_Detector_Threshold + (This : Si4432_Driver) + return UInt5 + is + Value : constant Register := Read_Register + (This, Low_Battery_Detector_Threshold_Name); + + Reg : Low_Battery_Detector_Threshold_Register with Import, + Address => Value'Address; + begin + return Reg.lbdt; + end Get_Low_Battery_Detector_Threshold; + + ------------------------------- + -- Get_Battery_Voltage_Level -- + ------------------------------- + + function Get_Battery_Voltage_Level + (This : Si4432_Driver) + return UInt5 + is + Value : constant Register := Read_Register + (This, Battery_Voltage_Level_Name); + + Reg : Battery_Voltage_Level_Register with Import, + Address => Value'Address; + begin + return Reg.vbat; + end Get_Battery_Voltage_Level; + + ---------------------------- + -- Set_AFC_Timing_Control -- + ---------------------------- + + procedure Set_AFC_Timing_Control + (This : Si4432_Driver; + Anwait : UInt3; + Shwait : UInt3; + Swant_Timer : UInt2) + is + Reg : constant AFC_Timing_Control_Register := + (anwait => Anwait, + shwait => Shwait, + swant_timer => Swant_Timer); + + Data : Register with Import, Address => Reg'Address; + begin + Write_Register (This, AFC_Timing_Control_Name, Data); + end Set_AFC_Timing_Control; + + ---------------------------- + -- Get_AFC_Timing_Control -- + ---------------------------- + + procedure Get_AFC_Timing_Control + (This : Si4432_Driver; + Anwait : out UInt3; + Shwait : out UInt3; + Swant_Timer : out UInt2) + is + Data : constant Register := Read_Register + (This, AFC_Timing_Control_Name); + Reg : AFC_Timing_Control_Register with Import, Address => Data'Address; + begin + Anwait := Reg.anwait; + Shwait := Reg.shwait; + Swant_Timer := Reg.swant_timer; + end Get_AFC_Timing_Control; + + ------------------------------------------- + -- Set_Clock_Recovery_Gearshift_Override -- + ------------------------------------------- + + procedure Set_Clock_Recovery_Gearshift_Override + (This : Si4432_Driver; + Slow : UInt3; + Fast : UInt3) + is + Reg : constant Clock_Recovery_Gearshift_Override_Register := + (crslow => Slow, + crfast => Fast, + Reserved => 0); + + Data : Register with Import, Address => Reg'Address; + begin + Write_Register (This, Clock_Recovery_Gearshift_Override_Name, Data); + end Set_Clock_Recovery_Gearshift_Override; + + ------------------------------------------- + -- Get_Clock_Recovery_Gearshift_Override -- + ------------------------------------------- + + procedure Get_Clock_Recovery_Gearshift_Override + (This : Si4432_Driver; + Slow : out UInt3; + Fast : out UInt3) + is + Data : constant Register := Read_Register + (This, Clock_Recovery_Gearshift_Override_Name); + + Reg : Clock_Recovery_Gearshift_Override_Register with Import, + Address => Data'Address; + begin + Slow := Reg.crslow; + Fast := Reg.crfast; + end Get_Clock_Recovery_Gearshift_Override; + + -------------------------------------------- + -- Get_Received_Signal_Strength_Indicator -- + -------------------------------------------- + + function Get_Received_Signal_Strength_Indicator + (This : Si4432_Driver) + return UInt8 is + begin + return UInt8 + (Read_Register (This, Received_Signal_Strength_Indicator_Name)); + end Get_Received_Signal_Strength_Indicator; + + ---------------------------------------------------- + -- Set_RSSI_Threshold_For_Clear_Channel_Indicator -- + ---------------------------------------------------- + + procedure Set_RSSI_Threshold_For_Clear_Channel_Indicator + (This : Si4432_Driver; + Value : UInt8) is + begin + Write_Register + (This, + RSSI_Threshold_For_Clear_Channel_Indicator_Name, + Register (Value)); + end Set_RSSI_Threshold_For_Clear_Channel_Indicator; + + ---------------------------------------------------- + -- Get_RSSI_Threshold_For_Clear_Channel_Indicator -- + ---------------------------------------------------- + + function Get_RSSI_Threshold_For_Clear_Channel_Indicator + (This : Si4432_Driver) + return UInt8 is + begin + return UInt8 + (Read_Register + (This, RSSI_Threshold_For_Clear_Channel_Indicator_Name)); + end Get_RSSI_Threshold_For_Clear_Channel_Indicator; + + ----------------------------- + -- Get_Antenna_Diversity_1 -- + ----------------------------- + + function Get_Antenna_Diversity_1 + (This : Si4432_Driver) + return UInt8 is + begin + return UInt8 (Read_Register (This, Antenna_Diversity_1_Name)); + end Get_Antenna_Diversity_1; + + ----------------------------- + -- Get_Antenna_Diversity_2 -- + ----------------------------- + + function Get_Antenna_Diversity_2 + (This : Si4432_Driver) + return UInt8 is + begin + return UInt8 (Read_Register (This, Antenna_Diversity_2_Name)); + end Get_Antenna_Diversity_2; + + ------------------------ + -- Get_AFC_Correction -- + ------------------------ + + function Get_AFC_Correction + (This : Si4432_Driver) + return AFC_Correction + is + Data : HAL.SPI.SPI_Data_8b (1 .. 2); + Reg : OOK_Counter_Value_1_Register with Import, + Address => Data (2)'Address; + + begin + Read_Register (This, AFC_Correction_Name, Data); + + return AFC_Correction + (Shift_Left (Unsigned_16 (Data (1)), 2) + Unsigned_16 (Reg.afc_corr)); + end Get_AFC_Correction; + + --------------------- + -- Set_OOK_Counter -- + --------------------- + + procedure Set_OOK_Counter + (This : Si4432_Driver; + Value : OOK_Counter; + MA : Boolean; + Peak_Detector : Boolean; + OOK_Freeze : Boolean) + is + Local : constant Unsigned_16 := Unsigned_16 (Value); + Data : HAL.SPI.SPI_Data_8b (1 .. 2); + Reg : OOK_Counter_Value_1_Register with Import, + Address => Data (1)'Address; + begin + Data (1) := UInt8 (Read_Register (This, OOK_Counter_Value_1_Name)); + Reg.ookcnt := UInt3 (Shift_Right (Local, 8)); + Reg.madeten := From_Boolean (MA); + Reg.peakdeten := From_Boolean (Peak_Detector); + Reg.ookfrzen := From_Boolean (OOK_Freeze); + Data (2) := UInt8 (Local and 16#FF#); + + Write_Register (This, OOK_Counter_Value_1_Name, Data); + end Set_OOK_Counter; + + --------------------- + -- Get_OOK_Counter -- + --------------------- + + procedure Get_OOK_Counter + (This : Si4432_Driver; + Value : out OOK_Counter; + MA : out Boolean; + Peak_Detector : out Boolean; + OOK_Freeze : out Boolean) + is + Data : HAL.SPI.SPI_Data_8b (1 .. 2); + Reg : OOK_Counter_Value_1_Register with Import, + Address => Data (1)'Address; + begin + Read_Register (This, OOK_Counter_Value_1_Name, Data); + + Value := OOK_Counter + (Shift_Left (Unsigned_16 (Reg.ookcnt), 8) + Unsigned_16 (Data (2))); + MA := To_Boolean (Reg.madeten); + Peak_Detector := To_Boolean (Reg.peakdeten); + OOK_Freeze := To_Boolean (Reg.ookfrzen); + end Get_OOK_Counter; + + ---------------------------- + -- Set_Slicer_Peak_Holder -- + ---------------------------- + + procedure Set_Slicer_Peak_Holder + (This : Si4432_Driver; + Decay : UInt4; + Attack : UInt3) + is + Reg : constant Slicer_Peak_Holder_Register := + (decay => Decay, + attack => Attack, + Reserved => 0); + + Data : Register with Import, Address => Reg'Address; + begin + Write_Register (This, Slicer_Peak_Holder_Name, Data); + end Set_Slicer_Peak_Holder; + + ---------------------------- + -- Get_Slicer_Peak_Holder -- + ---------------------------- + + procedure Get_Slicer_Peak_Holder + (This : Si4432_Driver; + Decay : out UInt4; + Attack : out UInt3) + is + Data : constant Register := Read_Register + (This, Slicer_Peak_Holder_Name); + Reg : Slicer_Peak_Holder_Register with Import, Address => Data'Address; + begin + Decay := Reg.decay; + Attack := Reg.attack; + end Get_Slicer_Peak_Holder; + + ---------------------- + -- Get_EZMAC_Status -- + ---------------------- + + procedure Get_EZMAC_Status + (This : Si4432_Driver; + Packet_Sent : out Boolean; + Packet_Transmitting : out Boolean; + CRC_Error : out Boolean; + Valid_Packet_Received : out Boolean; + Packet_Receiving : out Boolean; + Packet_Searching : out Boolean; + Underflow_CRC : out Boolean) + is + Data : constant Register := Read_Register (This, EZMAC_Status_Name); + Reg : EZMAC_Status_Register with Import, Address => Data'Address; + begin + Packet_Sent := To_Boolean (Reg.pksent); + Packet_Transmitting := To_Boolean (Reg.pktx); + CRC_Error := To_Boolean (Reg.crcerror); + Valid_Packet_Received := To_Boolean (Reg.pkvalid); + Packet_Receiving := To_Boolean (Reg.pkrx); + Packet_Searching := To_Boolean (Reg.pksrch); + Underflow_CRC := To_Boolean (Reg.rxcrc1); + end Get_EZMAC_Status; + + ------------------------- + -- Set_Transmit_Header -- + ------------------------- + + procedure Set_Transmit_Header + (This : Si4432_Driver; + Index : UInt2; + Value : UInt8) is + begin + Write_Register + (This, To_Transmit_Header_Index (Index), Register (Value)); + end Set_Transmit_Header; + + ------------------------- + -- Get_Transmit_Header -- + ------------------------- + + function Get_Transmit_Header + (This : Si4432_Driver; + Index : UInt2) + return UInt8 is + begin + return UInt8 (Read_Register (This, To_Transmit_Header_Index (Index))); + end Get_Transmit_Header; + + ---------------------- + -- Set_Check_Header -- + ---------------------- + + procedure Set_Check_Header + (This : Si4432_Driver; + Index : UInt2; + Value : UInt8) is + begin + Write_Register (This, To_Check_Header_Index (Index), Register (Value)); + end Set_Check_Header; + + ---------------------- + -- Get_Check_Header -- + ---------------------- + + function Get_Check_Header + (This : Si4432_Driver; + Index : UInt2) + return UInt8 is + begin + return UInt8 (Read_Register (This, To_Check_Header_Index (Index))); + end Get_Check_Header; + + ----------------------- + -- Set_Header_Enable -- + ----------------------- + + procedure Set_Header_Enable + (This : Si4432_Driver; + Index : UInt2; + Value : UInt8) is + begin + Write_Register (This, To_Header_Enable_Index (Index), Register (Value)); + end Set_Header_Enable; + + ----------------------- + -- Get_Header_Enable -- + ----------------------- + + function Get_Header_Enable + (This : Si4432_Driver; + Index : UInt2) + return UInt8 is + begin + return UInt8 (Read_Register (This, To_Header_Enable_Index (Index))); + end Get_Header_Enable; + + ------------------------- + -- Get_Received_Header -- + ------------------------- + + function Get_Received_Header + (This : Si4432_Driver; + Index : UInt2) + return UInt8 + is + function To_Name + (Index : UInt2) + return Register_Name; + + function To_Name + (Index : UInt2) + return Register_Name is + begin + case Index is + when 0 => + return Received_Header_0_Name; + when 1 => + return Received_Header_1_Name; + when 2 => + return Received_Header_2_Name; + when 3 => + return Received_Header_3_Name; + end case; + end To_Name; + + begin + return UInt8 (Read_Register (This, To_Name (Index))); + end Get_Received_Header; + + ---------------------- + -- Set_ADC8_Control -- + ---------------------- + + procedure Set_ADC8_Control + (This : Si4432_Driver; + Value : ADC8_Control) + is + Reg : constant ADC8_Control_Register := + (adc8 => UInt6 (Value), + Reserved => 0); + + Data : Register with Import, Address => Reg'Address; + begin + Write_Register (This, ADC8_Control_Name, Data); + end Set_ADC8_Control; + + ---------------------- + -- Get_ADC8_Control -- + ---------------------- + + function Get_ADC8_Control + (This : Si4432_Driver) + return ADC8_Control + is + Data : constant Register := Read_Register (This, ADC8_Control_Name); + Reg : ADC8_Control_Register with Import, Address => Data'Address; + begin + return ADC8_Control (Reg.adc8); + end Get_ADC8_Control; + + -------------------------------------------- + -- Set_Channel_Filter_Coefficient_Address -- + -------------------------------------------- + + procedure Set_Channel_Filter_Coefficient_Address + (This : Si4432_Driver; + Value : UInt4) + is + Reg : constant Channel_Filter_Coefficient_Address_Register := + (Reserved => 0, + invalid_preamble_threshold => Value); + + Data : Register with Import, Address => Reg'Address; + begin + Write_Register (This, Channel_Filter_Coefficient_Address_Name, Data); + end Set_Channel_Filter_Coefficient_Address; + + -------------------------------------------- + -- Get_Channel_Filter_Coefficient_Address -- + -------------------------------------------- + + function Get_Channel_Filter_Coefficient_Address + (This : Si4432_Driver) + return UInt4 + is + Data : constant Register := Read_Register + (This, Channel_Filter_Coefficient_Address_Name); + Reg : Channel_Filter_Coefficient_Address_Register with Import, + Address => Data'Address; + begin + return Reg.invalid_preamble_threshold; + end Get_Channel_Filter_Coefficient_Address; + + ---------------------------- + -- Set_Crystal_Oscillator -- + ---------------------------- + + procedure Set_Crystal_Oscillator + (This : Si4432_Driver; + Output_Buffer : Boolean; + Output_Buffer_Override : Boolean; + Two_Times_Higher_Amplification : Boolean; + Two_Times_Higher_Bias_Current : Boolean; + Clock_Hysteresis : Boolean) + is + Reg : constant Crystal_Oscillator_Register := + (enbuf => From_Boolean (Output_Buffer), + bufovr => From_Boolean (Output_Buffer_Override), + enamp2x => From_Boolean (Two_Times_Higher_Amplification), + enbias2x => From_Boolean (Two_Times_Higher_Bias_Current), + clkhyst => From_Boolean (Clock_Hysteresis), + pwst => LP); + + Data : Register with Import, Address => Reg'Address; + begin + Write_Register (This, Crystal_Oscillator_Name, Data); + end Set_Crystal_Oscillator; + + ---------------------------- + -- Get_Crystal_Oscillator -- + ---------------------------- + + procedure Get_Crystal_Oscillator + (This : Si4432_Driver; + Output_Buffer : out Boolean; + Output_Buffer_Override : out Boolean; + Two_Times_Higher_Amplification : out Boolean; + Two_Times_Higher_Bias_Current : out Boolean; + Clock_Hysteresis : out Boolean; + Internal_Power_State : out Internal_Chip_State) + is + Data : constant Register := Read_Register + (This, Crystal_Oscillator_Name); + Reg : Crystal_Oscillator_Register with Import, Address => Data'Address; + begin + Output_Buffer := To_Boolean (Reg.enbuf); + Output_Buffer_Override := To_Boolean (Reg.bufovr); + Two_Times_Higher_Amplification := To_Boolean (Reg.enamp2x); + Two_Times_Higher_Bias_Current := To_Boolean (Reg.enbias2x); + Clock_Hysteresis := To_Boolean (Reg.clkhyst); + Internal_Power_State := Reg.pwst; + end Get_Crystal_Oscillator; + + ----------------------------- + -- Set_TX_FIFO_Almost_Full -- + ----------------------------- + + procedure Set_TX_FIFO_Almost_Full + (This : Si4432_Driver; + Value : FIFO_Threshold) + is + Reg : constant TX_FIFO_Control_1_Register := + (txafthr => UInt6 (Value), + Reserved => 0); + + Data : Register with Import, Address => Reg'Address; + begin + Write_Register (This, TX_FIFO_Control_1_Name, Data); + end Set_TX_FIFO_Almost_Full; + + ----------------------------- + -- Get_TX_FIFO_Almost_Full -- + ----------------------------- + + function Get_TX_FIFO_Almost_Full + (This : Si4432_Driver) + return FIFO_Threshold + is + Data : constant Register := Read_Register (This, TX_FIFO_Control_1_Name); + Reg : TX_FIFO_Control_1_Register with Import, Address => Data'Address; + begin + return FIFO_Threshold (Reg.txafthr); + end Get_TX_FIFO_Almost_Full; + + ------------------------------ + -- Set_TX_FIFO_Almost_Empty -- + ------------------------------ + + procedure Set_TX_FIFO_Almost_Empty + (This : Si4432_Driver; + Value : FIFO_Threshold) + is + Reg : constant TX_FIFO_Control_2_Register := + (txfaethr => UInt6 (Value), + Reserved => 0); + + Data : Register with Import, Address => Reg'Address; + begin + Write_Register (This, TX_FIFO_Control_2_Name, Data); + end Set_TX_FIFO_Almost_Empty; + + ------------------------------ + -- Get_TX_FIFO_Almost_Empty -- + ------------------------------ + + function Get_TX_FIFO_Almost_Empty + (This : Si4432_Driver) + return FIFO_Threshold + is + Data : constant Register := Read_Register (This, TX_FIFO_Control_2_Name); + Reg : TX_FIFO_Control_2_Register with Import, Address => Data'Address; + begin + return FIFO_Threshold (Reg.txfaethr); + end Get_TX_FIFO_Almost_Empty; + + ----------------------------- + -- Set_RX_FIFO_Almost_Full -- + ----------------------------- + + procedure Set_RX_FIFO_Almost_Full + (This : Si4432_Driver; + Value : FIFO_Threshold) + is + Reg : constant RX_FIFO_Control_Register := + (rxafthr => UInt6 (Value), + Reserved => 0); + + Data : Register with Import, Address => Reg'Address; + begin + Write_Register (This, RX_FIFO_Control_Name, Data); + end Set_RX_FIFO_Almost_Full; + + ----------------------------- + -- Get_RX_FIFO_Almost_Full -- + ----------------------------- + + function Get_RX_FIFO_Almost_Full + (This : Si4432_Driver) + return FIFO_Threshold + is + Data : constant Register := Read_Register (This, RX_FIFO_Control_Name); + Reg : RX_FIFO_Control_Register with Import, Address => Data'Address; + begin + return FIFO_Threshold (Reg.rxafthr); + end Get_RX_FIFO_Almost_Full; + + ---------- + -- Send -- + ---------- + + procedure Send + (This : Si4432_Driver; + Data : SPI_Data_8b) is + begin + Set_Packet_Length (This, Data'Length); + Write_Register (This, FIFO_Access_Name, Data); + Set_State (This, TX); + end Send; + + ------------------ + -- Get_Received -- + ------------------ + + procedure Get_Received + (This : Si4432_Driver; + Data : out SPI_Data_8b) + is + Received : constant Natural := Natural + (Get_Received_Packet_Length (This)); + Length : constant Natural := Natural'Min (Received, Data'Length); + begin + Read_Register + (This, FIFO_Access_Name, Data (Data'First .. Data'First + Length - 1)); + + if Received <= Data'Length then + Clear_RX_FIFO (This); + end if; + end Get_Received; + + ------------------- + -- Clear_RX_FIFO -- + ------------------- + + procedure Clear_RX_FIFO (This : Si4432_Driver) + is + Value : Register := Read_Register + (This, Operating_Mode_And_Function_Control_2_Name); + + Reg : Operating_Mode_And_Function_Control_2_Register with Import, + Address => Value'Address; + begin + Reg.ffclrrx := 1; + Write_Register (This, Operating_Mode_And_Function_Control_2_Name, Value); + Reg.ffclrrx := 0; + Write_Register (This, Operating_Mode_And_Function_Control_2_Name, Value); + end Clear_RX_FIFO; + + ------------------- + -- Clear_TX_FIFO -- + ------------------- + + procedure Clear_TX_FIFO (This : Si4432_Driver) + is + Value : Register := Read_Register + (This, Operating_Mode_And_Function_Control_2_Name); + + Reg : Operating_Mode_And_Function_Control_2_Register with Import, + Address => Value'Address; + begin + Reg.ffclrtx := 1; + Write_Register (This, Operating_Mode_And_Function_Control_2_Name, Value); + Reg.ffclrtx := 0; + Write_Register (This, Operating_Mode_And_Function_Control_2_Name, Value); + end Clear_TX_FIFO; + + -------------- + -- CSN_High -- + -------------- + + procedure CSN_High (This : Si4432_Driver) is + begin + if This.Holder.Kind = Software then + This.Holder.CSN_Pin.Set; + end if; + end CSN_High; + + ------------- + -- CSN_Low -- + ------------- + + procedure CSN_Low (This : Si4432_Driver) is + begin + if This.Holder.Kind = Software then + This.Holder.CSN_Pin.Clear; + end if; + end CSN_Low; + + ------------------- + -- Read_Register -- + ------------------- + + function Read_Register + (This : Si4432_Driver; + Name : Register_Name) + return Register + is + Command : constant Command_Register := + (Address => Registers_Addressses (Name), + Operation => Read); + Cmd : HAL.SPI.SPI_Data_8b (1 .. 1) with Import, + Address => Command'Address; + + Data : HAL.SPI.SPI_Data_8b (1 .. 1); + Result : Register + with Import, Address => Data (Data'First)'Address; + begin + Write_And_Read (This, Cmd, Data); + return Result; + end Read_Register; + + ------------------- + -- Read_Register -- + ------------------- + + procedure Read_Register + (This : Si4432_Driver; + Name : Register_Name; + Data : out HAL.SPI.SPI_Data_8b) + is + Command : constant Command_Register := + (Address => Registers_Addressses (Name), + Operation => Read); + Cmd : HAL.SPI.SPI_Data_8b (1 .. 1) with Import, + Address => Command'Address; + + begin + Write_And_Read (This, Cmd, Data); + end Read_Register; + + -------------------- + -- Write_Register -- + -------------------- + + procedure Write_Register + (This : Si4432_Driver; + Name : Register_Name; + Data : Register) + is + Buff : HAL.SPI.SPI_Data_8b (1 .. 2); + Command : Command_Register := + (Address => Registers_Addressses (Name), + Operation => Write) with Address => Buff (1)'Address; + begin + Buff (2) := UInt8 (Data); + Write (This, Buff); + end Write_Register; + + -------------------- + -- Write_Register -- + -------------------- + + procedure Write_Register + (This : Si4432_Driver; + Name : Register_Name; + Data : HAL.SPI.SPI_Data_8b) + is + Buff : HAL.SPI.SPI_Data_8b (1 .. Data'Length + 1); + Command : Command_Register := + (Address => Registers_Addressses (Name), + Operation => Write) with Address => Buff (1)'Address; + begin + Buff (2 .. Buff'Last) := Data; + Write (This, Buff); + end Write_Register; + + ----------- + -- Write -- + ----------- + + procedure Write + (This : Si4432_Driver; + Data : HAL.SPI.SPI_Data_8b) + is + Status : HAL.SPI.SPI_Status; + begin + CSN_Low (This); + This.Holder.SPI.Transmit (Data, Status); + CSN_High (This); + + if Status /= HAL.SPI.Ok then + raise Program_Error; + end if; + end Write; + + -------------------- + -- Write_And_Read -- + -------------------- + + procedure Write_And_Read + (This : Si4432_Driver; + Command : HAL.SPI.SPI_Data_8b; + Data : out HAL.SPI.SPI_Data_8b) + is + Status : HAL.SPI.SPI_Status; + begin + CSN_Low (This); + This.Holder.SPI.Transmit (Command, Status); + if Status /= HAL.SPI.Ok then + CSN_High (This); + raise Program_Error; + end if; + + This.Holder.SPI.Receive (Data, Status); + CSN_High (This); + + if Status /= HAL.SPI.Ok then + raise Program_Error; + end if; + end Write_And_Read; + + ------------------ + -- From_Boolean -- + ------------------ + + function From_Boolean (Value : Boolean) return Bit is + begin + return (if Value then 1 else 0); + end From_Boolean; + + ---------------- + -- To_Boolean -- + ---------------- + + function To_Boolean (Value : Bit) return Boolean is + begin + return (if Value = 1 then True else False); + end To_Boolean; + + ----------------------------------- + -- To_Synchronization_Word_Index -- + ----------------------------------- + + function To_Synchronization_Word_Index + (Index : UInt2) + return Register_Name is + begin + case Index is + when 0 => + return Synchronization_Word_0_Name; + when 1 => + return Synchronization_Word_1_Name; + when 2 => + return Synchronization_Word_2_Name; + when 3 => + return Synchronization_Word_3_Name; + end case; + end To_Synchronization_Word_Index; + + ------------------------------ + -- To_Transmit_Header_Index -- + ------------------------------ + + function To_Transmit_Header_Index + (Index : UInt2) + return Register_Name is + begin + case Index is + when 0 => + return Transmit_Header_0_Name; + when 1 => + return Transmit_Header_1_Name; + when 2 => + return Transmit_Header_2_Name; + when 3 => + return Transmit_Header_3_Name; + end case; + end To_Transmit_Header_Index; + + --------------------------- + -- To_Check_Header_Index -- + --------------------------- + + function To_Check_Header_Index + (Index : UInt2) + return Register_Name is + begin + case Index is + when 0 => + return Check_Header_0_Name; + when 1 => + return Check_Header_1_Name; + when 2 => + return Check_Header_2_Name; + when 3 => + return Check_Header_3_Name; + end case; + end To_Check_Header_Index; + + ---------------------------- + -- To_Header_Enable_Index -- + ---------------------------- + + function To_Header_Enable_Index + (Index : UInt2) + return Register_Name is + begin + case Index is + when 0 => + return Header_Enable_0_Name; + when 1 => + return Header_Enable_1_Name; + when 2 => + return Header_Enable_2_Name; + when 3 => + return Header_Enable_3_Name; + end case; + end To_Header_Enable_Index; + +end Si4432; diff --git a/components/src/radio/si4432/si4432.ads b/components/src/radio/si4432/si4432.ads new file mode 100644 index 000000000..3101bb45a --- /dev/null +++ b/components/src/radio/si4432/si4432.ads @@ -0,0 +1,3959 @@ +------------------------------------------------------------------------------ +-- -- +-- Copyright (C) 2025, AdaCore -- +-- -- +-- Redistribution and use in source and binary forms, with or without -- +-- modification, are permitted provided that the following conditions are -- +-- met: -- +-- 1. Redistributions of source code must retain the above copyright -- +-- notice, this list of conditions and the following disclaimer. -- +-- 2. Redistributions in binary form must reproduce the above copyright -- +-- notice, this list of conditions and the following disclaimer in -- +-- the documentation and/or other materials provided with the -- +-- distribution. -- +-- 3. Neither the name of the copyright holder nor the names of its -- +-- contributors may be used to endorse or promote products derived -- +-- from this software without specific prior written permission. -- +-- -- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -- +-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -- +-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -- +-- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -- +-- HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -- +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -- +-- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -- +-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -- +-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -- +-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -- +-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- +-- -- +------------------------------------------------------------------------------ + +-- Driver for Si4432 chip, actualy on Si4430/31/32 Rev B1 + +with HAL; use HAL; +with HAL.GPIO; use HAL.GPIO; +with HAL.SPI; use HAL.SPI; + +package Si4432 is + pragma Extensions_Allowed (On); + + type Register is new UInt8; + + type On_Off is (Off, On); + type Chip_State is (Idle, RX, TX) with Size => UInt2'Size; + + type Frequency is delta 0.1 range 240.0 .. 960.0 + with Small => 0.1; -- in MHz + + type Frequency_Offset is range -16#1FF# .. 16#1FF#; + type Frequency_Deviation_Hz is range 0 .. 319375 + with Dynamic_Predicate => Frequency_Deviation_Hz rem 625 = 0; -- in Hz + type Wake_Up_Timer_Period is range 1 .. 16#FFFF#; + type Clock_Recovery_Offset is range 0 .. 16#FF7FF#; + type Clock_Recovery_Oversampling is range 0 .. 16#7FF#; + type Clock_Recovery_Timing_Loop_Gain is range 0 .. 16#7FF#; + type OOK_Counter is range 0 .. 16#7FF#; + type AFC_Correction is range 0 .. 16#3FF#; + type FIFO_Threshold is range 0 .. 16#3F#; + type Low_Duty_Cycle_Mode_Duration is range 1 .. 16#FF#; + type ADC8_Control is range 0 .. 16#20#; + type ADC_Sensor_Amplifier_Offset is range -7 .. 7; + type Wake_Up_Timer_Exponent is range 0 .. 20; + + type Modulation_Mode is + (Unmodulated_Carrier, + OOK, + FSK, + GFSK -- (enable TX Data CLK (TX_Data_Clock_Configuration) when direct + -- mode is used) + ) with Size => UInt2'Size; + + type Modulation_Source is + (Direct_GPIO, + -- Direct Mode using TX_Data function via the GPIO pin (one of the + -- GPIO's should be programmed accordingly as well) + Direct_SDI, + -- Direct Mode using TX_Data function via the SDI pin (only + -- when nSEL is high) + FIFO, + -- FIFO Mode + PN9 + -- PN9 (internally generated) + ) with Size => UInt2'Size; + + type Modulation_TX_Data_Clock is + (No_CLK, + -- No TX Data CLK is available (asynchronous mode - Can only work + -- with modulations FSK or OOK). + CLK_GPIO, + -- TX Data CLK is available via the GPIO (one of the GPIO-s should + -- be programmed as well). + CLK_SDO, + -- TX Data CLK is available via the SDO pin. + CLK_nIRQ + -- TX Data CLK is available via the nIRQ pin. + ) with Size => UInt2'Size; + + type Synchronization_Word_Length is + (Word_3, Word_3_2, Word_3_2_1, Word_3_2_1_0) with Size => UInt2'Size; + + for Synchronization_Word_Length use + (Word_3 => 2#00#, + Word_3_2 => 2#01#, + Word_3_2_1 => 2#10#, + Word_3_2_1_0 => 2#11#); + + type Header_Length is + (No_Header, Header_3, Header_3_2, Header_3_2_1, Header_3_2_1_0) + with Size => UInt3'Size; + + for Header_Length use + (No_Header => 2#000#, + Header_3 => 2#001#, + Header_3_2 => 2#010#, + Header_3_2_1 => 2#011#, + Header_3_2_1_0 => 2#100#); + + type CRC_Polynomial is + (CCITT, + CRC_16, -- (IBM) + IEC_16, + Biacheva) with Size => UInt2'Size; + + type GPIO_0_Function is + (Power_On_Reset, + Wake_Up_Timer, + Low_Battery_Detect, + Direct_Digital_Input, + Interrupt_Falling_Edge, + Interrupt_Rising_Edge, + Interrupt_State_Change, + ADC_Analog_Input, + Reserved_Analog_Test_N_Input, + Reserved_Analog_Test_P_Input, + Direct_Digital_Output, + Reserved_Digital_Test_Output, + Reserved_Analog_Test_N_Output, + Reserved_Analog_Test_P_Output, + Reference_Voltage, + Data_CLK_Output, + TX_Data_Input, + External_Retransmission_Request, + TX_State, + TX_FIFO_Almost_Full, + RX_Data, + RX_State, + RX_FIFO_Almost_Full, + Antenna_1_Switch, + Antenna_2_Switch, + Valid_Preamble_Detected, + Invalid_Preamble_Detected, + Sync_Word_Detected, + Clear_Channel_Assessment, + VDD, + GND0, GND1 + ) with Size => UInt5'Size; + + type GPIO_1_Function is + (Inverted_Power_On_Reset, + Wake_Up_Timer, + Low_Battery_Detect, + Direct_Digital_Input, + Interrupt_Falling_Edge, + Interrupt_Rising_Edge, + Interrupt_State_Change, + ADC_Analog_Input, + Reserved_Analog_Test_N_Input, + Reserved_Analog_Test_P_Input, + Direct_Digital_Output, + Reserved_Digital_Test_Output, + Reserved_Analog_Test_N_Output, + Reserved_Analog_Test_P_Output, + Reference_Voltage, + Data_CLK_Output, + TX_Data_Input, + External_Retransmission_Request, + TX_State, + TX_FIFO_Almost_Full, + RX_Data, + RX_State, + RX_FIFO_Almost_Full, + Antenna_1_Switch, + Antenna_2_Switch, + Valid_Preamble_Detected, + Invalid_Preamble_Detected, + Sync_Word_Detected, + Clear_Channel_Assessment, + VDD, + GND0, GND1 + ) with Size => UInt5'Size; + + type GPIO_2_Function is + (Microcontroller_Clocks, + Wake_Up_Timer, + Low_Battery_Detect, + Direct_Digital_Input, + Interrupt_Falling_Edge, + Interrupt_Rising_Edge, + Interrupt_State_Change, + ADC_Analog_Input, + Reserved_Analog_Test_N_Input, + Reserved_Analog_Test_P_Input, + Direct_Digital_Output, + Reserved_Digital_Test_Output, + Reserved_Analog_Test_N_Output, + Reserved_Analog_Test_P_Output, + Reference_Voltage, + Data_CLK_Output, + TX_Data_Input, + External_Retransmission_Request, + TX_State, + TX_FIFO_Almost_Full, + RX_Data, + RX_State, + RX_FIFO_Almost_Full, + Antenna_1_Switch, + Antenna_2_Switch, + Valid_Preamble_Detected, + Invalid_Preamble_Detected, + Sync_Word_Detected, + Clear_Channel_Assessment, + VDD, + GND0, GND1 + ) with Size => UInt5'Size; + + type AGC_Override_Gain is range 0 .. 24 with + Static_Predicate => AGC_Override_Gain in 0 | 3 | 6 | 12 | 24; + + type Crystal_Oscillator is (RC_Oscillator, Crystal_32kHz) + with Size => Bit'Size; + for Crystal_Oscillator use + (RC_Oscillator => 0, Crystal_32kHz => 1); + + type Microcontroller_Clock is + (c30MHz, c15MHz, c10MHz, c4MHz, c3MHz, c2MHz, c1MHz, c32kHz) + with Size => UInt3'Size; + + type Clock_Tail is range 0 .. 512 with + Static_Predicate => Clock_Tail in 0 | 128 | 256 | 512; + + type ADC_Input_Source is + (Internal_Temperature_Sensor, + GPIO0_Single_Ended, + GPIO1_Single_Ended, + GPIO2_Single_Ended, + GPIO0_GPIO1_differential, -- GPIO0(+) - GPIO1(-), differential + GPIO1_GPIO2_differential, -- GPIO1(+) - GPIO2(-), differential + GPIO0_GPIO2_differential, -- GPIO0(+) - GPIO2(-), differential + GND) with Size => UInt3'Size; + + type Temperature_Sensor_Range is + (From_Minus_64_To_64C, + -- -64 to 64C (full operating range), with 0.5C resolution + -- (1 LSB in the 8-bit ADC) + From_Minus_64_To_192C, + -- -64 to 192C, with 1C resolution (1 LSB in the 8-bit ADC) + From_Minus_40_To_216F, + -- -40 to 216F, with 1F resolution (1 LSB in the 8-bit ADC) + From_0_To_12C + -- 0 to 12C, with 0.5C resolution (1 LSB in the 8-bit ADC) + ) with Size => UInt2'Size; + + type Internal_Chip_State is (LP, RDY, TX, Tune, RX) + with Size => UInt3'Size; + + subtype Interrupt_Statuses is HAL.SPI.SPI_Data_8b (1 .. 2); + + ------------------- + -- Si4432_Driver -- + ------------------- + + type Si4432_Driver is limited private; + + procedure Initialize + (This : out Si4432_Driver; + CSN_Pin : HAL.GPIO.Any_GPIO_Point; + SDN_Pin : HAL.GPIO.Any_GPIO_Point; + SPI : HAL.SPI.Any_SPI_Port); + + function Device_Type_Code (This : Si4432_Driver) return UInt8; + -- Default 16#8# + + function Version_Code (This : Si4432_Driver) return UInt8; + -- Code indicating the version of the chip. + -- Si4430/31/32 Rev B1: 16#6#. + -- Si100x Rev C, Si101x Rev A, Si102x/3x Rev A: 16#6#. + -- Si100x Rev E, Si101x Rev B: Si102x/3x Rev B: 16#7#. + + procedure Set_Power + (This : Si4432_Driver; + Mode : On_Off); + + procedure Set_State + (This : Si4432_Driver; + State : Chip_State); + + procedure Set_TX_Power + (This : Si4432_Driver; + Output_Power : UInt3; + -- Default 0 + -- The output power is configurable from +13 dBm to -8 dBm (Si4430/31), + -- and from +20 dBM to -1 dBM (Si4432) in ~3 dB steps. 0 corresponds to + -- min output power, while 7 corresponds to max output power. + + LNA_Switch : Boolean); + -- Default True + -- This determines when internal MOS switches at the LNA input(s) are + -- invoked. When False, these switches open. When True, these switches + -- are closed in TX mode and open at all other times. This bit MUST + -- be set for proper operation in any Direct Tie application. + + procedure Get_TX_Power + (This : Si4432_Driver; + Output_Power : out UInt3; + LNA_Switch : out Boolean); + + procedure Get_Device_Status + (This : Si4432_Driver; + Power : out Chip_State; + Frequency_Error : out Boolean; + -- The programmed frequency is outside of the operating range. The actual frequency is + -- saturated to the max/min value. + + Header_Error : out Boolean; + -- Indicates if the received packet has a header check error. + + RX_FIFO_Empty : out Boolean; + RX_TX_FIFO_Underflow : out Boolean; + RX_TX_FIFO_Overflow : out Boolean); + + procedure Get_EZMAC_Status + (This : Si4432_Driver; + Packet_Sent : out Boolean; + -- When True a packet has been sent by the radio. (Same bit as in + -- Interrupt_Status_1, but reading it does not reset the IRQ) + + Packet_Transmitting : out Boolean; + -- When True the radio is currently transmitting a packet. + + CRC_Error : out Boolean; + -- When True a Cyclic Redundancy Check error has been detected. (Same + -- bit as in Interrupt_Status_1, but reading it does not reset the IRQ) + + Valid_Packet_Received : out Boolean; + -- When True a valid packet has been received by the receiver. (Same + -- bit as in Interrupt_Status_1, but reading it does not reset the IRQ) + + Packet_Receiving : out Boolean; + -- When True the radio is currently receiving a valid packet. + + Packet_Searching : out Boolean; + -- When True the radio is searching for a valid packet. + + Underflow_CRC : out Boolean); + -- May indicated Transmitter underflow in case of CRC error. + + procedure Software_Reset (This : Si4432_Driver); + -- The user should wait until the CHIPRDY status flag/interrupt is issued + -- before sending further SPI commands to the chip. + + ---------------- + -- Interrupts -- + ---------------- + + function Get_Interrupt_Statuses + (This : Si4432_Driver) + return Interrupt_Statuses; + -- Returns Interrupt_Statuses + -- (1 => Interrupt_Status_1, 2 => Interrupt_Status_2) + + function Get_Interrupt_Status_1 + (This : Si4432_Driver) + return UInt8; + -- Reading statuses clears the interrupt flags and resets the NIRQ output + -- When any of the Interrupt/Status 1 register bits change state from 0 + -- to 1 the device will notify the microcontroller by setting the nIRQ pin + -- LOW = 0 if the corresponding enable bit is set in the Interrupt Enable 1 + -- register. The nIRQ pin will go to HIGH and all the enabled interrupt + -- bits will be cleared when the microcontroller reads this address. If any + -- of these bits are not enabled in the Interrupt Enable 1 register, they + -- then become status signals that can be read at any time. They WILL NOT + -- be cleared by reading the register. + + Status_CRC_Error : constant := 2#00000001#; + -- When set to 1 the cyclic redundancy check is failed. + Status_Valid_Packet_Received : constant := 2#00000010#; + -- When set to 1 a valid packet has been received. + Status_Packet_Sent : constant := 2#00000100#; + -- When set to1 a valid packet has been transmitted. + Status_External_Interrupt : constant := 2#00001000#; + -- When set to 1 an interrupt occurred on one of the GPIO's if it is + -- programmed so. The status can be checked in register 0Eh. See + -- GPIOx Configuration section for the details. + Status_RX_FIFO_Almost_Full : constant := 2#00010000#; + -- When set to 1 the RX FIFO has met its almost full threshold and needs + -- to be read by the microcontroller. + Status_TX_FIFO_Almost_Empty : constant := 2#00100000#; + -- When set to 1 the TX FIFO is almost empty and needs to be filled. + Status_TX_FIFO_Almost_Full : constant := 2#01000000#; + -- When set to 1 the TX FIFO has met its almost full threshold and + -- needs to be transmitted. + Status_FIFO_Underflow_Overflow : constant := 2#10000000#; + -- When set to 1 the TX or RX FIFO has overflowed or underflowed. + + function Get_Interrupt_Status_2 + (This : Si4432_Driver) + return UInt8; + -- Reading statuses clears the interrupt flags and resets the NIRQ output + + Status_Power_On_Reset : constant := 2#00000001#; + -- When the chip detects a Power on Reset above the desired setting + -- this bit will be set to 1. + Status_Chip_Ready : constant := 2#00000010#; + -- When a chip ready event has been detected this bit will be set to 1. + Status_Low_Battery_Detect : constant := 2#00000100#; + -- When a low battery event has been detected this bit will be set to 1. + -- This interrupt event is saved even if it is not enabled by the mask + -- register bit and causes an interrupt after it is enabled. + Status_Wake_Up_Timer : constant := 2#00001000#; + -- On the expiration of programmed wake-up timer this bit will be set + -- to 1. + Status_RSSI : constant := 2#00010000#; + -- When RSSI level exceeds the programmed threshold this bit will be + -- set to 1. + Status_Invalid_Preamble_Detected : constant := 2#00100000#; + -- When the preamble is not found within a period of time set by the + -- invalid preamble detection threshold in Register 60h, this bit will + -- be set to 1. + Status_Valid_Preamble_Detected : constant := 2#01000000#; + -- When a preamble is detected this bit will be set to 1. + Status_Sync_Word_Detected : constant := 2#10000000#; + -- When a sync word is detected this bit will be set to 1. + + procedure Clear_Interrupts (This : Si4432_Driver); + + procedure Set_Interrupt_Enable + (This : Si4432_Driver; + CRC_Error : Boolean := False; + Valid_Packet_Received : Boolean := False; + Packet_Sent : Boolean := False; + External_Interrupt : Boolean := False; + RX_FIFO_Almost_Full : Boolean := False; + TX_FIFO_Almost_Empty : Boolean := False; + TX_FIFO_Almost_Full : Boolean := False; + FIFO_Underflow_Overflow : Boolean := False; + POR : Boolean := True; + Chip_Ready : Boolean := True; + Low_Battery : Boolean := False; + Wake_Up_Timer : Boolean := False; + RSSI : Boolean := False; + Invalid_Preamble : Boolean := False; + Valid_Preamble : Boolean := False; + Sync_Word : Boolean := False); + -- Uses Set_Interrupt_Enable_1 and Set_Interrupt_Enable_2. See below. + + procedure Set_Interrupt_Enable_1 + (This : Si4432_Driver; + CRC_Error : Boolean; + -- When set to True the CRC Error interrupt will be enabled. + Valid_Packet_Received : Boolean; + -- When True the Valid Packet Received Interrupt will be enabled. + Packet_Sent : Boolean; + -- When True the Packet Sense Interrupt will be enabled. + External_Interrupt : Boolean; + -- When set to True the External Interrupt will be enabled. + RX_FIFO_Almost_Full : Boolean; + -- When set to True the RX FIFO Almost Full interrupt will be enabled. + TX_FIFO_Almost_Empty : Boolean; + -- When set to True the TX FIFO Almost Empty interrupt will be enabled. + TX_FIFO_Almost_Full : Boolean; + -- When set to True the TX FIFO Almost Full interrupt will be enabled. + FIFO_Underflow_Overflow : Boolean); + -- When set to True the FIFO Underflow/Overflow interrupt will be + -- enabled. + -- Default: False all + + procedure Get_Interrupt_Enable_1 + (This : Si4432_Driver; + CRC_Error : out Boolean; + Valid_Packet_Received : out Boolean; + Packet_Sent : out Boolean; + External_Interrupt : out Boolean; + RX_FIFO_Almost_Full : out Boolean; + TX_FIFO_Almost_Empty : out Boolean; + TX_FIFO_Almost_Full : out Boolean; + FIFO_Underflow_Overflow : out Boolean); + + procedure Set_Interrupt_Enable_2 + (This : Si4432_Driver; + POR : Boolean; + -- When set to True the POR interrupt will be enabled. + Chip_Ready : Boolean; + -- When set to True the Chip Ready interrupt will be enabled. + Low_Battery : Boolean; + -- When set to True the Low Battery Detect interrupt will be enabled. + Wake_Up_Timer : Boolean; + -- When set to True the Wake-Up Timer interrupt will be enabled. + RSSI : Boolean; + -- When set to True the RSSI Interrupt will be enabled. + Invalid_Preamble : Boolean; + -- When set to True the Invalid Preamble Detected Interrupt will be + -- enabled. + Valid_Preamble : Boolean; + -- When set to True the Valid Preamble Detected Interrupt will be + -- enabled. + Sync_Word : Boolean); + -- When set to True the Syn Word Detected Interrupt will be enabled. + -- Default: POR & Chip Read are True + + procedure Get_Interrupt_Enable_2 + (This : Si4432_Driver; + POR : out Boolean; + Chip_Ready : out Boolean; + Low_Battery : out Boolean; + Wake_Up_Timer : out Boolean; + RSSI : out Boolean; + Invalid_Preamble : out Boolean; + Valid_Preamble : out Boolean; + Sync_Word : out Boolean); + + ------------------------------- + -- The RF carrier frequency -- + ------------------------------- + + procedure Set_Frequency + (This : Si4432_Driver; + Value : Frequency); + -- Calculate (formula below) and set frequency by setting Frequency_Band + -- and Nominal_Carrier_Frequency. + -- Assumes that Frequency_Hopping_Channel_Select = 0. + + -- The RF carrier frequency can be calculated as follows: + -- fcarrier = (Frequency_Band.Band + 24 + + -- (Nominal_Carrier_Frequency + Frequency_Offset) / 64000) x + -- 10000 x (Frequency_Band.High_Band + 1) + + -- (Frequency_Hopping_Channel_Select x Frequency_Hopping_Step_Size x 10) + -- [kHz] + + procedure Set_Frequency_Band + (This : Si4432_Driver; + Band : UInt5; + -- Default 16#15# + -- Every increment corresponds to a 10 MHz increase in frequency + -- (when not High_Band) or a 20 MHz increase in frequency + -- (when High_Band). + -- Example: Setting Band=0 will result in tuning within the 240-250 MHz + -- frequency range (for not High_Band) or within the 480-500 MHz + -- frequency range (for High_Band). Setting Band=1 will result in tuning + -- within the 250-260 MHz frequency range (not High_Band) or 500-520 MHz + -- range (High_Band), and so on. + + High_Band : Boolean; + -- Default True + -- Setting High_Band will choose the frequency range from 480-960 MHz + -- (high bands). Setting High_Band=False will choose the frequency range + -- from 240-479.9 MHz (low bands). + + Side_Band : Boolean); + -- Default True + -- Setting Side_Band (recommended setting) will result in tuning the + -- RX LO below the desired channel frequency in RX mode (low-side + -- injection) such that the high-side sideband is selected. Note that + -- setting Side_Band = False will result in positioning the RX LO above + -- the desired tuned frequency (high-side injection), but will NOT + -- additionally flip the processing of the complex (I + jQ) signals in + -- the IF chain necessary to select the lower sideband as the desired + -- signal. + + procedure Get_Frequency_Band + (This : Si4432_Driver; + Band : out UInt5; + High_Band : out Boolean; + Side_Band : out Boolean); + + procedure Set_Nominal_Carrier_Frequency + (This : Si4432_Driver; + Value : UInt16); + -- See formula above. + -- Default 16#BB80# + + function Get_Nominal_Carrier_Frequency + (This : Si4432_Driver) + return UInt16; + + procedure Set_Frequency_Offset + (This : Si4432_Driver; + Value : Frequency_Offset); + -- The frequency offset can be calculated as + -- Offset = 156.25 Hz x (Frequency_Band.High_Band + 1) x Frequency_Offset + -- Default 16#0# + + function Get_Frequency_Offset + (This : Si4432_Driver) + return Frequency_Offset; + + procedure Set_Frequency_Hopping_Channel_Select + (This : Si4432_Driver; + Value : UInt8); + -- Frequency Hopping Step Size in 10 kHz Increments. + -- See formula for the nominal carrier frequency - fcarrier. + -- Important: The EZHop method of frequency programming only works while + -- remaining entirely within one of the following defined frequency + -- sub-bands: 240-320 MHz, 320-480 MHz, 480-640 MHz, and 640-960 MHz. + -- It is not allowed to define a base frequency that falls in one + -- sub-band while the selected channel number falls in another sub-band. + -- Default 16#0# + + function Get_Frequency_Hopping_Channel_Select + (This : Si4432_Driver) + return UInt8; + + procedure Set_Frequency_Hopping_Step_Size + (This : Si4432_Driver; + Value : UInt8); + -- Frequency Hopping Step Size in 10 kHz Increments. + -- See formula for the nominal carrier frequency - fcarrier. + -- Important: The EZHop method of frequency programming only works while + -- remaining entirely within one of the following defined frequency + -- sub-bands: 240-320 MHz, 320-480 MHz, 480-640 MHz, and 640-960 MHz. + -- It is not allowed to define a base frequency that falls in one sub-band + -- while the selected channel number falls in another sub-band. + -- Default 16#0# + + function Get_Frequency_Hopping_Step_Size + (This : Si4432_Driver) + return UInt8; + + procedure Set_Frequency_Deviation_Hz + (This : Si4432_Driver; + Value : Frequency_Deviation_Hz); + -- Calculate (formula below) and set frequency deviation + + procedure Set_Frequency_Deviation + (This : Si4432_Driver; + Value : UInt9); + -- Default: 16#20# + -- The frequency deviation can be calculated: + -- FD = 625 Hz x Frequency_Deviation. + -- Note: It's recommended to use modulation index of 1 or higher + -- (maximum allowable modulation index is 32). The modulation index + -- is defined by 2FD/RB were FD is the deviation and RB is the data + -- rate. When Manchester coding is enabled the modulation index is + -- defined by FD/RB. + + function Get_Frequency_Deviation + (This : Si4432_Driver) + return UInt9; + + --------------- + -- Data_Rate -- + --------------- + + procedure Set_TX_Data_Rate + (This : Si4432_Driver; + Value : UInt16); + -- The data rate can be calculated as: + -- 106 x TX_Data_Rate/2^16 [bps] (if Data_Rates_Below is False) or + -- 106 x TX_Data_Rate/2^21 [bps] (if Data_Rates_Below is True) + -- Defaults = 16#A3D# (40 kbps) + + function Get_TX_Data_Rate + (This : Si4432_Driver) + return UInt16; + + procedure Set_Data_Rates_Below + (This : Si4432_Driver; + Value : Boolean); + -- See Modulation_Mode_Control_1.Data_Rates_Below + + -------------- + -- Preamble -- + -------------- + + procedure Set_Preamble_Length + (This : Si4432_Driver; + Value : UInt9); + -- Preamble Length. Default 16#8# + -- The value corresponds to the number of nibbles (4 bits) in the packet. + -- For example '000001000' corresponds to a preamble length of 32 bits + -- (8 x 4bits) or 4 bytes. The maximum preamble length is '111111111' + -- which corresponds to a 255 bytes Preamble. Writing 0 will have the + -- same result as if writing 1, which corresponds to one single nibble + -- of preamble. + + function Get_Preamble_Length + (This : Si4432_Driver) + return UInt9; + + procedure Set_Preamble_Detection_Control + (This : Si4432_Driver; + RSSI_Offset : UInt3; + -- Default 16#2# + -- Value added as offset to RSSI calculation. Every increment in this + -- register results in an increment of +4 dB in the RSSI. + + Detection_Threshold : UInt5); + -- Default 16#5# + -- Preamble Detection Threshold. The value corresponds to the number + -- of nibbles (4 bits) of preamble pattern (i.e., 01010...) that must + -- be received correctly, before a PREAMBLE_VALID signal is issued. + -- This threshold helps guard against false preamble detection upon + -- noise. + + procedure Get_Preamble_Detection_Control + (This : Si4432_Driver; + RSSI_Offset : out UInt3; + Detection_Threshold : out UInt5); + + -------------------------- + -- Synchronization_Word -- + -------------------------- + + procedure Set_Synchronization_Word + (This : Si4432_Driver; + Index : UInt2; + Value : UInt8); + -- Default: + -- 3 : 16#2D# + -- 2 : 16#D4# + -- 1 : 16#00# + -- 0 : 16#00# + + function Get_Synchronization_Word + (This : Si4432_Driver; + Index : UInt2) + return UInt8; + + procedure Set_Data_Access_Control + (This : Si4432_Driver; + CRC_Selection : CRC_Polynomial; + -- Default CRC_16 + + CRC_Enable : Boolean; + -- Default True + -- Cyclic Redundancy Check generation is enabled if this bit is set. + + Enable_Packet_TX_Handling : Boolean; + -- Default True + -- If FIFO Mode (Modulation_Mode_Control_2.Modulation_Source = FIFO) + -- is being used automatic packet handling may be enabled. Setting + -- True will enable automatic packet handling in the TX path. + -- Register 30-4D allow for various configurations of the packet + -- structure. Setting False will not do any packet handling in the + -- TX path. It will only transmit what is loaded to the FIFO. + + Skip_2nd_Phase_Preamble_Detection : Boolean; + -- Default False + -- If set, we skip the second phase of the preamble detection (under + -- certain conditions) if antenna diversity is enabled. + + CRC_Data_Only_Enable : Boolean; + -- Default False + -- When this bit is set to 1 the CRC is calculated on and checked + -- against the packet data fields only. + + LSB_First_Enable : Boolean; + -- Default False + -- The LSB of the data will be transmitted/received first if this bit + -- is set. + + Enable_Packet_RX_Handling : Boolean); + -- Default True + -- If FIFO Mode (Modulation_Mode_Control_2.Modulation_Source = FIFO) + -- is being used automatic packet handling may be enabled. Setting + -- True will enable automatic packet handling in the RX path. Register + -- 30-4D allow for various configurations of the packet structure. + -- Setting False will not do any packet handling in the RX path. It + -- will only receive everything after the sync word and fill up the + -- RX FIFO. + + procedure Get_Data_Access_Control + (This : Si4432_Driver; + CRC_Selection : out CRC_Polynomial; + CRC_Enable : out Boolean; + Enable_Packet_TX_Handling : out Boolean; + Skip_2nd_Phase_Preamble_Detection : out Boolean; + CRC_Data_Only_Enable : out Boolean; + LSB_First_Enable : out Boolean; + Enable_Packet_RX_Handling : out Boolean); + + ------------- + -- Headers -- + ------------- + + procedure Set_Transmit_Header + (This : Si4432_Driver; + Index : UInt2; + Value : UInt8); + -- Default: + -- 3 : 16#00# + -- 2 : 16#00# + -- 1 : 16#00# + -- 0 : 16#00# + + function Get_Transmit_Header + (This : Si4432_Driver; + Index : UInt2) + return UInt8; + + procedure Set_Check_Header + (This : Si4432_Driver; + Index : UInt2; + Value : UInt8); + -- Check Header bytes 3 to 0 are checked against the corresponding bytes + -- in the Received Header if the check is enabled. + -- Default: + -- 3 : 16#00# + -- 2 : 16#00# + -- 1 : 16#00# + -- 0 : 16#00# + + function Get_Check_Header + (This : Si4432_Driver; + Index : UInt2) + return UInt8; + + procedure Set_Header_Enable + (This : Si4432_Driver; + Index : UInt2; + Value : UInt8); + -- Header Enable bytes 3 to 0 control which bits of the Check Header bytes + -- are checked against the corresponding bits in the Received Header. + -- Only those bits are compared where the enable bits are set to 1. + -- Default: + -- 3 : 16#FF# + -- 2 : 16#FF# + -- 1 : 16#FF# + -- 0 : 16#FF# + + function Get_Header_Enable + (This : Si4432_Driver; + Index : UInt2) + return UInt8; + + function Get_Received_Header + (This : Si4432_Driver; + Index : UInt2) + return UInt8; + + ---------- + -- GPIO -- + ---------- + + procedure Set_GPIO0_Configuration + (This : Si4432_Driver; + Pin_Function : GPIO_0_Function; + -- Default Power_On_Reset + + Pullup_Resistor_Enable : Boolean; + -- Default False + -- When set to 1 a 200 kOm resistor is connected internally between + -- VDD and the pin if the GPIO is configured as a digital input. + + Driving_Capability : UInt2); + -- Default 16#0# + + procedure Get_GPIO0_Configuration + (This : Si4432_Driver; + Pin_Function : out GPIO_0_Function; + Pullup_Resistor_Enable : out Boolean; + Driving_Capability : out UInt2); + + procedure Set_GPIO1_Configuration + (This : Si4432_Driver; + Pin_Function : GPIO_1_Function; + -- Default Inverted_Power_On_Reset + + Pullup_Resistor_Enable : Boolean; + -- Default False + -- When set to 1 a 200 kOm resistor is connected internally between + -- VDD and the pin if the GPIO is configured as a digital input. + + Driving_Capability : UInt2); + -- Default 16#0# + + procedure Get_GPIO1_Configuration + (This : Si4432_Driver; + Pin_Function : out GPIO_1_Function; + Pullup_Resistor_Enable : out Boolean; + Driving_Capability : out UInt2); + + procedure Set_GPIO2_Configuration + (This : Si4432_Driver; + Pin_Function : GPIO_2_Function; + -- Default Microcontroller_Clocks + + Pullup_Resistor_Enable : Boolean; + -- Default False + -- When set to 1 a 200 kOm resistor is connected internally between + -- VDD and the pin if the GPIO is configured as a digital input. + + Driving_Capability : UInt2); + -- Default 16#0# + + procedure Get_GPIO2_Configuration + (This : Si4432_Driver; + Pin_Function : out GPIO_2_Function; + Pullup_Resistor_Enable : out Boolean; + Driving_Capability : out UInt2); + + --------------- + -- Settings -- + --------------- + + procedure Set_Modulation_Mode_Control_1 + (This : Si4432_Driver; + Data_Whitening : Boolean; + -- Default False + + Manchester_Coding : Boolean; + -- Default False + -- What Manchester coding does is to replace a single + -- high bit (1) with two bits starting with low followed by high (01) + -- and a low bit (0) with a high bit followed by a low bit (10). When + -- Manchester is enabled, please configure as well the + -- Manchester_Data_Inversion since it influences the Manchester + -- encoding/decoding process. + + Manchester_Data_Inversion : Boolean; + -- Default True + -- When False a 10 pair is considered a Manchester 0, and a + -- 01 pair as a Manchester 1. By setting this, do the opposite: every + -- 10 will be considered as a 1, and every 01 will be considered as + -- a 0. This function is relevant only if the Manchester mode is + -- enabled. + + Manchester_Preamble_Polarity : Boolean; + -- Default True + -- Will transmit a series of 1 if set, or series of 0 if reset. This + -- bit affects only the transmitter side, not the receiver. This is + -- valid only if Manchester Mode is enabled. + + Packet_Handler_Down : Boolean; + -- Default False + -- If set, the Packet Handler will be powered down when chip is in + -- low power mode. + + Data_Rates_Below : Boolean); + -- Default False + -- This bit should be set for TX_Data_Rate below 30 kbps. + + procedure Get_Modulation_Mode_Control_1 + (This : Si4432_Driver; + Data_Whitening : out Boolean; + Manchester_Coding : out Boolean; + Manchester_Data_Inversion : out Boolean; + Manchester_Preamble_Polarity : out Boolean; + Packet_Handler_Down : out Boolean; + Data_Rates_Below : out Boolean); + + procedure Set_Modulation_Mode_Control_2 + (This : Si4432_Driver; + Modulation : Modulation_Mode; + -- Default Unmodulated carrier + + Invert_TX_RX : Boolean; + -- Default False + -- Invert TX and RX Data. + + Source : Modulation_Source; + -- Default Direct_GPIO + + TX_Data_Clock : Modulation_TX_Data_Clock); + -- Default No_CLK + + procedure Get_Modulation_Mode_Control_2 + (This : Si4432_Driver; + Modulation : out Modulation_Mode; + Invert_TX_RX : out Boolean; + Source : out Modulation_Source; + TX_Data_Clock : out Modulation_TX_Data_Clock); + + procedure Set_Header_Control + (This : Si4432_Driver; + Header_Bytes_Check : UInt4 := 16#C#; + Broadcast_Address_Check : UInt4 := 0; + Synchronization : Synchronization_Word_Length := Word_3_2; + Fix_TR_Packet_Length : Boolean := False; + Header : Header_Length := Header_3_2; + Skipsyn : Boolean := False); + -- Uses Set_Header_Control_1 and Set_Header_Control_2 + + procedure Set_Header_Control_1 + (This : Si4432_Driver; + Header_Bytes_Check : UInt4; + -- Default 16#C# + -- Received Header Bytes to be Checked Against the Check Header Bytes. + -- One hot encoding. The receiver will use Header to know the position + -- of the Header Bytes. + -- 0:No Received Header check + -- 1:Received Header check for byte 0. + -- 2:Received Header check for bytes 1. + -- 3:Received header check for bytes 0 & 1 and so on. + + Broadcast_Address_Check : UInt4); + -- Default 16#0# + -- Broadcast Address (FFh) Check Enable. + -- If it is enabled together with Header Byte Check then the header + -- check is OK if the incoming header byte equals with the appropriate + -- check byte or FFh). One hot encoding. + -- 0:No broadcast address enable. + -- 1:Broadcast address enable for header byte 0. + -- 2:Broadcast address enable for header byte 1. + -- 3:Broadcast address enable for header bytes 0 & 1 and so on. + + procedure Get_Header_Control_1 + (This : Si4432_Driver; + Header_Bytes_Check : out UInt4; + Broadcast_Address_Check : out UInt4); + + procedure Set_Header_Control_2 + (This : Si4432_Driver; + Synchronization : Synchronization_Word_Length; + -- Default Word_3_2 + -- The value in this register corresponds to the number of bytes used + -- in the Synchronization Word. The synchronization word bytes are + -- transmitted in descending order. + + Fix_TR_Packet_Length : Boolean; + -- Default False + -- When True the packet length (Packet_Length) is not included in the + -- transmit header. When False the packet length is included in the + -- transmit header. In receive mode, if this bit is set the packet + -- length is obtained from the Packet_Length; otherwise the packet + -- length is obtained from the received header packet length byte. + + Header : Header_Length; + -- Default Header_3_2 + -- Transmit/Receive Header Length. Length of header used if packet + -- handler is enabled for TX/RX (enpactx/rx). Headers are + -- transmitted/received in descending order. + + Skipsyn : Boolean); + -- Default False + -- Skip Sync Word search timeout. If high, the system will ignore the + -- search timeout period when failing to find Sync Word and will not + -- return to searching for Preamble. Setting this bit does not + -- eliminate the search for Sync Word. Proper detection of Sync Word + -- remains necessary in FIFO mode in order to determine the start of + -- the Payload field and to thus store the correct bytes in the RX + -- FIFO. + + procedure Get_Header_Control_2 + (This : Si4432_Driver; + Synchronization : out Synchronization_Word_Length; + Fix_TR_Packet_Length : out Boolean; + Header : out Header_Length; + Skipsyn : out Boolean); + + procedure Set_Operating_Mode_And_Function_Control + (This : Si4432_Driver; + READY_Mode : Boolean := True; + TUNE_Mode : Boolean := False; + RX_On : Boolean := False; + TX_On : Boolean := False; + Oscillator_Select : Crystal_Oscillator := RC_Oscillator; + Wake_Up_Timer : Boolean := False; + Low_Battery_Detect : Boolean := False; + TX_FIFO_Reset : Boolean := False; + RX_FIFO_Reset : Boolean := False; + Low_Duty_Cycle_Mode : Boolean := False; + Automatic_Transmission : Boolean := False; + RX_Multi_Packet : Boolean := False; + Antenna_Diversity : UInt3 := 0); + -- Uses Set_Operating_Mode_And_Function_Control_1 and + -- Set_Operating_Mode_And_Function_Control_2. See below. + + procedure Set_Operating_Mode_And_Function_Control_1 + (This : Si4432_Driver; + READY_Mode : Boolean; + -- Default True + -- READY Mode (Xtal is ON). + + TUNE_Mode : Boolean; + -- Default False + -- TUNE Mode (PLL is ON). + -- When True the PLL will remain enabled in Idle State. This allows for + -- faster turn-around time at the cost of increased current consumption + -- in Idle State. + + RX_On : Boolean; + -- Default False + -- RX on in Manual Receiver Mode. + -- Automatically cleared if Multiple Packets config. is disabled and + -- a valid packet received. + + TX_On : Boolean; + -- Default False + -- TX on in Manual Transmit Mode. + -- Automatically cleared in FIFO mode once the packet is sent. + + Oscillator_Select : Crystal_Oscillator; + -- Default RC_Oscillator + + Wake_Up_Timer : Boolean; + -- Default False + -- Enable Wake-Up-Timer. + -- Enabled when True. If the Wake-up-Timer function is enabled it will + -- operate in any mode and notify the microcontroller through the + -- GPIO interrupt when the timer expires. + + Low_Battery_Detect : Boolean; + -- Default False + -- Enable Low Battery Detect. + -- When this bit is set to True the Low Battery Detector circuit and + -- threshold comparison will be enabled. + + Software_Reset : Boolean); + -- Software Register Reset Bit. + -- This bit may be used to reset all registers simultaneously to a + -- DEFAULT state, without the need for sequentially writing to each + -- individual register. The RESET is accomplished by setting True. This + -- bit will be automatically cleared. The user should wait until the + -- CHIPRDY status flag/interrupt is issued before sending further SPI + -- commands to the chip. + + procedure Get_Operating_Mode_And_Function_Control_1 + (This : Si4432_Driver; + READY_Mode : out Boolean; + TUNE_Mode : out Boolean; + RX_On : out Boolean; + TX_On : out Boolean; + Oscillator_Select : out Crystal_Oscillator; + Wake_Up_Timer : out Boolean; + Low_Battery_Detect : out Boolean); + + procedure Set_Operating_Mode_And_Function_Control_2 + (This : Si4432_Driver; + TX_FIFO_Reset : Boolean; + -- Default False + -- TX FIFO Reset/Clear. + -- This has to be a two writes operation: Setting True followed by + -- False will clear the contents of the TX FIFO. + + RX_FIFO_Reset : Boolean; + -- Default False + -- RX FIFO Reset/Clear. + -- This has to be a two writes operation: Setting True followed by + -- False will clear the contents of the RX FIFO. + + Low_Duty_Cycle_Mode : Boolean; + -- Default False + -- Enable Low Duty Cycle Mode. + -- If this bit is set to True then the chip turns on the RX regularly. + -- The frequency should be set in the Wake-Up Timer Period register, + -- while the minimum ON time should be set in the Low-Duty Cycle Mode + -- Duration register. The FIFO mode should be enabled also. + + Automatic_Transmission : Boolean; + -- Default False + -- Automatic Transmission. + -- When True the transceiver will enter automatically TX State when + -- the FIFO is almost full. When the FIFO is empty it will automatically + -- return to the Idle State. + + RX_Multi_Packet : Boolean; + -- Default False + -- RX Multi Packet. + -- When the chip is selected to use FIFO Mode + -- (Modulation_Mode_Control_2.Modulation Source) and RX Packet Handling + -- (Data_Access_Control.Packet_RX_Handling) then it will fill up the + -- FIFO with multiple valid packets if this bit is set, otherwise the + -- transceiver will automatically leave the RX State after the first + -- valid packet has been received. + + Antenna_Diversity : UInt3); + -- Default 0 + -- Enable Antenna Diversity. + -- The GPIO must be configured for Antenna Diversity for the algorithm to + -- work properly. + + procedure Get_Operating_Mode_And_Function_Control_2 + (This : Si4432_Driver; + TX_FIFO_Reset : out Boolean; + RX_FIFO_Reset : out Boolean; + Low_Duty_Cycle_Mode : out Boolean; + Automatic_Transmission : out Boolean; + RX_Multi_Packet : out Boolean; + Antenna_Diversity : out UInt3); + + procedure Clear_RX_FIFO (This : Si4432_Driver); + procedure Clear_TX_FIFO (This : Si4432_Driver); + -- Set TX_FIFO_Reset or RX_FIFO_Reset + + procedure Set_Crystal_Oscillator_Load_Capacitance + (This : Si4432_Driver; + Tuning_Capacitance : UInt7; + -- Default 16#7F# + -- Tuning Capacitance for the 30 MHz XTAL. + + Shft : Bit); + -- Default 16#0# + -- Additional capacitance to coarse shift the frequency if + -- Tuning_Capacitance is not sufficient. Not binary with + -- Tuning_Capacitance. + + procedure Get_Crystal_Oscillator_Load_Capacitance + (This : Si4432_Driver; + Tuning_Capacitance : out UInt7; + Shft : out Bit); + + procedure Set_IF_Filter_Bandwidth + (This : Si4432_Driver; + Coefficient : UInt4; + -- Default: 1 + -- Selects one of 15 pre-calculated sets of digital FIR filter tap + -- coefficients. Along with the decimation ratios selected by + -- Bypass_Decimate and Decimation_Rates, the filter coefficients + -- determine the bandwidth of the IF filter. + + Decimation_Rates : UInt3; + -- Default: 0 + -- The oversampled data in the receive data path is decimated by a + -- factor of 2^Decimation_Rates. A higher decimation factor (i.e., + -- larger value of ndec_exp) results in a lower IF filter bandwidth. + + Bypass_Decimate : Boolean); + -- Default: False + -- If set, results in bypassing a decimate-by-3 stage in the path of + -- the oversampled data path for the digital filter for the IF + -- bandwidth. + + procedure Get_IF_Filter_Bandwidth + (This : Si4432_Driver; + Coefficient : out UInt4; + Decimation_Rates : out UInt3; + Bypass_Decimate : out Boolean); + + procedure Set_Clock_Recovery_Oversampling_Rate + (This : Si4432_Driver; + Value : Clock_Recovery_Oversampling); + -- 3 LSBs are the fraction, default = 16#64# = 12.5 clock cycles per + -- data bit. + -- The oversampling rate can be calculated as Oversampling = + -- 500 kHz/(2 IF_Filter_Bandwidth.Decimation_Rates x RX_DR). The + -- IF_Filter_Bandwidth.Decimation_Rates and the Bypass_Decimate values + -- together with the receive data rate (Rb) are the parameters needed + -- to calculate Oversampling: + -- + -- Oversampling = (500 x (1 + 2xBypass_Decimate)) / + -- (2^Decimation_Rates-3 x Rb x (1 + Manchester_Coding)) + -- + -- The Rb unit used in this equation is in kbps. + -- The Manchester_Coding is the Manchester_Coding parameter + -- (see Modulation_Mode_Control_1.Manchester_Coding is 1 when enabled and + -- 0 when disabled). The number found in the equation should be rounded to + -- an integer. The integer can be translated to a hexadecimal. For optimal + -- modem performance it is recommended to set the Oversampling to at + -- least 8. A higher Oversampling can be obtained by choosing a lower + -- value for IF_Filter_Bandwidth.Decimation_Rates or enable + -- IF_Filter_Bandwidth.Bypass_Decimate. A correction in filset might be + -- needed to correct the channel select bandwidth to the desired value. + -- Note that when Decimation_Rates or Bypass_Decimate are changed the + -- related parameters (Oversampling, + -- Clock_Recovery_Offset.NCO_Offset and + -- Clock_Recovery_Timing_Loop_Gain.Gain) need to be updated. + + function Get_Clock_Recovery_Oversampling_Rate + (This : Si4432_Driver) + return Clock_Recovery_Oversampling; + + procedure Set_Clock_Recovery_Offset + (This : Si4432_Driver; + NCO_Offset : Clock_Recovery_Offset; + -- Default 16#147AE# + -- See formula above. + + Skip_2nd_Phase : Boolean); + -- Default False + -- Skip 2nd Phase Ant Div Threshold. Threshold for skipping the 2nd + -- phase of RSSI detection during antenna diversity algorithm. + -- False=16 dB (default), True=11 dB. + -- NOT RECOMMENDED FOR USER CONFIGURATION. + + -- The offset can be calculated as follows: + -- NCO_Offset = + -- (Rb x (1 + Modulation_Mode_Control_1.Manchester_Coding) x + -- 2^IF_Filter_Bandwidth.Decimation_Rates) / + -- (500 x (1 + 2 x IF_Filter_Bandwidth.Bypass_Decimate)) + + -- The default values for Clock_Recovery_Oversampling_Rate and + -- Clock_Recovery_Offset gives 40 kbps RX_DR with Manchester coding is + -- disabled. + + procedure Get_Clock_Recovery_Offset + (This : Si4432_Driver; + NCO_Offset : out Clock_Recovery_Offset; + Skip_2nd_Phase : out Boolean); + + procedure Set_Clock_Recovery_Timing_Loop_Gain + (This : Si4432_Driver; + Gain : Clock_Recovery_Timing_Loop_Gain; + -- Default 16#28F# + -- Clock Recovery Timing Loop Gain. + + Multiplying_By_2 : Boolean; + -- Default False + -- Multiplying the CR Gain by 2. + + Compensation_Enable : Boolean); + -- Default False + -- Receive Compensation Enable for High Data Rate Offset. + + -- The loop gain can be calculated as follows: + -- Gain = 2 + + -- ((2^16 x (1 + Modulation_Mode_Control_1.Manchester Coding) x Rb) / + -- (Clock_Recovery_Oversampling_Rate x Fd)) + + procedure Get_Clock_Recovery_Timing_Loop_Gain + (This : Si4432_Driver; + Gain : out Clock_Recovery_Timing_Loop_Gain; + Multiplying_By_2 : out Boolean; + Compensation_Enable : out Boolean); + + procedure Set_AFC_Loop_Gearshift_Override + (This : Si4432_Driver; + Reset_Preamble : Boolean; + -- If False (default), we will reset the Preamble detector if there + -- are 5 consecutive zero phases. If True, the reset will happen after + -- 3 consecutive zero phases. + + Taps : Boolean; + -- Number of taps for moving average filter during Antenna Diversity + -- RSSI evaluation. Allows for reduced noise variation on measured + -- RSSI value but with slower update rate. If True, filter tap + -- length = 8*Tb. If False (default), filter tap length = 8*Tb prior + -- to first PREAMBLE_VALID, and 4*Tb thereafter. + + Bypass : Boolean; + -- If True, select 0dB bias for the second phase antenna selection, + -- if False, select 1.5 dB. The default is True, selecting 0 dB. + + AFC_High_Gear : UInt3; + -- AFC High Gear Setting. Feedback loop gain during AFC setting + -- process is proportional to 2^(-AFC_High_Gear). + AFC : Boolean; + -- AFC Enable. + + AFC_Wideband : Boolean); + -- AFC Wideband Enable (active True). If set, the IF filter bandwidth + -- is reduced after preamble detection, in order to optimize RX + -- sensitivity. The IF filter bandwidth used during preamble detection + -- is programmed by the FILSET, NDEC, and DWN3BYPASS parameters in + -- IF_Filter_Bandwidth. After preamble detection, the chip automatically + -- selects the next lower IF filter bandwidth by internally decreasing + -- the FILSET parameter by 1. The resulting filter bandwidth may be + -- determined from the bandwidth table provided under the description + -- for IF_Filter_Bandwidth. + + procedure Get_AFC_Loop_Gearshift_Override + (This : Si4432_Driver; + Reset_Preamble : out Boolean; + Taps : out Boolean; + Bypass : out Boolean; + AFC_High_Gear : out UInt3; + AFC : out Boolean; + AFC_Wideband : out Boolean); + + procedure Set_AFC_Limiter + (This : Si4432_Driver; + Value : UInt8); + -- Default 16#0# + -- AFC limiter value. + + function Get_AFC_Limiter + (This : Si4432_Driver) + return UInt8; + + procedure Set_AGC_Override + (This : Si4432_Driver; + Gain_Override : AGC_Override_Gain; + -- Default 0 + + LNA_Gain_Select : Boolean; + -- Default False + -- Inagain=LNA Gain select. + -- False - min. gain = 5 dB + -- True - max. gain = 25 dB + + Automatic_Gain_Control : Boolean; + -- Default True + -- Automatic Gain Control enable. When is set then the result of the + -- control can be read out from Gain_Override, otherwise the gain can + -- be controlled manually by writing into Gain_Override. + Sgin : Boolean); + -- AGC stop increasing gain override bit (active low). When False + -- (default), AGC gain increases during signal reductions are prevented. + -- When True, AGC gain increases during signal reductions are allowed. + -- Only effective during Preamble, prior to detection of + -- PREAMBLE_VALID signal. + + procedure Get_AGC_Override + (This : Si4432_Driver; + Gain_Override : out AGC_Override_Gain; + LNA_Gain_Select : out Boolean; + Automatic_Gain_Control : out Boolean; + Sgin : out Boolean); + + procedure Set_Microcontroller_Output_Clock + (This : Si4432_Driver; + Clock : Microcontroller_Clock; + -- Different clock frequencies may be selected for configurable GPIO + -- clock output. All clock frequencies are created by dividing the XTAL + -- except for the 32 kHz clock which comes directly from the 32 kHz + -- RC Oscillator. The setting is only valid when + -- Operating_Mode_And_Function_Control_1.READY_Mode except the 32 kHz. + + Low_Frequency_Clock : Boolean; + -- When True and the chip is in Sleep mode then the 32.768 kHz clock + -- will be provided to the microcontroller no matter what the selection + -- of Microcontroller_Clock is. For example if + -- Microcontroller_Clock = 30 MHz will be available through the GPIO + -- to output to the microcontroller in all Idle, TX, or RX states. + -- When the chip is commanded to Sleep mode the 30 MHz clock will + -- become 32.768 kHz. + + Tail : Clock_Tail); + -- If Low_Frequency_Clock = False then it can be useful to provide a + -- few extra cycles for the microcontroller to complete its operation. + -- Setting the value will provide the addition cycles of the clock + -- before it shuts off. + + procedure Get_Microcontroller_Output_Clock + (This : Si4432_Driver; + Clock : out Microcontroller_Clock; + Low_Frequency_Clock : out Boolean; + Tail : out Clock_Tail); + + procedure Set_IO_Port_Configuration + (This : Si4432_Driver; + Direct_GPIO0 : Boolean; + -- Default False + -- Direct I/O for GPIO0. + -- If the GPIO0 is configured to be a direct output then the value on + -- the GPIO pin can be set here. If the GPIO0 is configured to be a + -- direct input then the value of the pin can be read here. + + Direct_GPIO1 : Boolean; + -- Default False + -- Direct I/O for GPIO1. + -- If the GPIO1 is configured to be a direct output then the value on + -- the GPIO pin can be set here. If the GPIO1 is configured to be a + -- direct input then the value of the pin can be read here. + + Direct_GPIO2 : Boolean; + -- Default False + -- Direct I/O for GPIO2. + -- If the GPIO2 is configured to be a direct output then the value on + -- the GPIO pin can be set here. If the GPIO2 is configured to be a + -- direct input then the value of the pin can be read here. + + Interrupt_Output_SDO : Boolean); + -- Default False + -- Interrupt Request Output on the SDO Pin. + -- nIRQ output is present on the SDO pin if this bit is set and the + -- nSEL input is inactive (high). + + procedure Get_IO_Port_Configuration + (This : Si4432_Driver; + Direct_GPIO0 : out Boolean; + Direct_GPIO1 : out Boolean; + Direct_GPIO2 : out Boolean; + Interrupt_Output_SDO : out Boolean; + External_0_Interrupt : out Boolean; + -- External Interrupt Status. + -- If the GPIO0 is programmed to be an external interrupt source then + -- the status can be read here. + + External_1_Interrupt : out Boolean; + -- External Interrupt Status. + -- If the GPIO1 is programmed to be an external interrupt source then + -- the status can be read here. + + External_2_Interrupt : out Boolean); + -- External Interrupt Status. + -- If the GPIO2 is programmed to be an external interrupt source then + -- the status can be read here. + + procedure Set_ADC_Configuration + (This : Si4432_Driver; + Sensor_Amplifier_Gain : UInt2; + -- Default 0 + -- The full scale range of the internal 8-bit ADC in differential mode + -- (see Input_Source) + + Reference_Voltage : UInt2; + -- Default 0 + -- The reference voltage of the internal 8-bit ADC can be selected + -- as follows: + -- 0X:bandgap voltage (1.2 V) + -- 10:VDD/3 + -- 11:VDD/2 + + Input_Source : ADC_Input_Source; + -- Default 0 + -- The internal 8-bit ADC input source can be selected + + Measurement_Start : Boolean); + -- Default False + -- Set this True starts the ADC measurement process. This bit + -- self-clears during the measurement cycle and returns high when the + -- measurement is complete. The conversion process is fast; reading + -- this bit may always appear to return a True. + + -- Reference_Voltage[00] = FS=0.014 x (Sensor_Amplifier_Gain + 1) x VDD + -- Reference_Voltage[01] = FS=0.021 x (Sensor_Amplifier_Gain + 1) x VDD + + procedure Get_ADC_Configuration + (This : Si4432_Driver; + Sensor_Amplifier_Gain : out UInt2; + Reference_Voltage : out UInt2; + Input_Source : out ADC_Input_Source; + Measurement_Start : out Boolean); + + procedure Set_ADC_Sensor_Amplifier_Offset + (This : Si4432_Driver; + Amplifier_Offset : ADC_Sensor_Amplifier_Offset); + -- *Note: The offset can be calculated as + -- Offset = Amplifier_Offset x VDD/1000; + + function Get_ADC_Sensor_Amplifier_Offset + (This : Si4432_Driver) + return ADC_Sensor_Amplifier_Offset; + + function Get_ADC_Value + (This : Si4432_Driver) + return UInt8; + -- Internal 8 bit ADC Output Value + + procedure Set_Temperature_Sensor_Calibration + (This : Si4432_Driver; + Trim_Value : UInt4; + -- Temperature Sensor Trim Value. + + Trim : Boolean; + -- Temperature Sensor Trim Enable. + + Offset : Boolean; + -- Temperature Sensor Offset to Convert from K to C. Default is True. + -- Test mode only, to use set Sensor_Range = From_Minus_64_To_64C and + -- Offset to False. + + Sensor_Range : Temperature_Sensor_Range); + -- Temperature Sensor Range Selection. (FS range is 0-1024 mV) + + procedure Get_Temperature_Sensor_Calibration + (This : Si4432_Driver; + Trim_Value : out UInt4; + Trim : out Boolean; + Offset : out Boolean; + Sensor_Range : out Temperature_Sensor_Range); + + procedure Set_Temperature_Value_Offset + (This : Si4432_Driver; + Value : UInt8); + -- Default 0 + -- This value is added to the measured temperature value. + + function Get_Temperature_Value_Offset + (This : Si4432_Driver) + return UInt8; + + procedure Set_Low_Battery_Detector_Threshold + (This : Si4432_Driver; + Value : UInt5); + -- This threshold is compared to Battery Voltage Level. If the Battery + -- Voltage is less than the threshold the Low Battery Interrupt is set. + -- Default = 2.7 V. Note: The threshold can be calculated as: + -- Vthreshold = 1.7 + Value x 50 mV. + + function Get_Low_Battery_Detector_Threshold + (This : Si4432_Driver) + return UInt5; + + function Get_Battery_Voltage_Level + (This : Si4432_Driver) + return UInt5; + -- The battery voltage is converted by a 5 bit ADC if the + -- Operating_Mode_And_Function_Control_1.Low_Battery_Detect is also set. + -- In Sleep Mode the register is updated in every 1 s. In other states + -- it measures continuously. The measured voltage is calculated by the + -- following formula: + -- Vbat_meas=1.7V + Battery_Voltage_Level x 50 mV + + procedure Set_AFC_Timing_Control + (This : Si4432_Driver; + Anwait : UInt3; + -- Antenna switching wait time. Number of bit periods between toggling + -- selection of antennas in AntDiv mode, prior to reception of first + -- PREAMBLE_VALID. + -- Number of bit periods = ( Anwait + 2 ) x 4 +3 (when AFC = enabled) + -- Number of bit periods = ( Anwait + 2 ) x 2 +3 (when AFC = disabled) + -- Default value = 2#010# = 19 bit periods (AFC = enabled). + + Shwait : UInt3; + -- Shwait wait periods after AFC correction used before preamble is + -- detected. Short wait=(RegValue+1) x 2Tb. If set to 0 then no AFC + -- correction will occur before preamble detect, i.e., AFC will be + -- disabled. Default value = 2#001# + + Swant_Timer : UInt2); + -- Additional number of bit periods to wait for RSSI value to stabilize + -- during Antenna Diversity 2nd phase antenna evaluation. If + -- AFC_Loop_Gearshift_Override.Taps = False, total wait time = + -- 8 x Tb + Swant_Timer. If AFC_Loop_Gearshift_Override.Taps = True, + -- total wait time = 12 * Tb + Swant_Timer. + -- Effective only during Antenna Diversity. + + procedure Get_AFC_Timing_Control + (This : Si4432_Driver; + Anwait : out UInt3; + Shwait : out UInt3; + Swant_Timer : out UInt2); + + procedure Set_Clock_Recovery_Gearshift_Override + (This : Si4432_Driver; + Slow : UInt3; + Fast : UInt3); + -- The gear-shift register controls BCR loop gain. Before the preamble + -- is detected, BCR loop gain is as follows: + -- BCRLoopGain = crgain / 2^Fast + -- + -- Once the preamble is detected, internal state machine automatically + -- shift BCR loop gain to the following: + -- BCRLoopGain = crgain / 2^Slow + -- + -- Fast = 0 and Slow = 2#101# are recommended for most applications. + -- The value of "slow" should be greater than "fast". + + procedure Get_Clock_Recovery_Gearshift_Override + (This : Si4432_Driver; + Slow : out UInt3; + Fast : out UInt3); + + function Get_AFC_Correction + (This : Si4432_Driver) + return AFC_Correction; + -- AFC loop correction values. Values are updated once, after sync word + -- is found during receiving. + + procedure Set_OOK_Counter + (This : Si4432_Driver; + Value : OOK_Counter; + -- OOK counter value. This counter value will affect the + -- OOK AGC's decay time. Use the following equation: + -- ook_cnt_val = 3 x 500[kHz] / + -- Rb x (Modulation_Mode_Control_1.Manchester_Coding) + -- Where Rb's unit is in kHz. Therefore, the minimal data rate that this + -- register can support without Manchester is 0.366 kbps. + + MA : Boolean; + -- When True (default), Moving Average Detector for OOK Modem is + -- enabled. Provides best sensitivity, but requires DC-balanced data + -- (e.g., Manchester data) and is more sensitive to co-channel + -- interference. Peak Detector output is logically AND'ed with Moving + -- Average Detector output. + + Peak_Detector : Boolean; + -- When True (default), Peak Detector for OOK Modem is enabled. Provides + -- improved performance in presence of co-channel interferers, at slight + -- reduction of sensitivity. Peak Detector output is logically AND'ed + -- with Moving Average Detector output. + + OOK_Freeze : Boolean); + -- when False (default), AGC and OOK Moving Average Detector threshold + -- operate continuously. When True, AGC and OOK MA Detector threshold + -- operate until PREAMBLE_VALID signal is detected; values are frozen + -- thereafter. Recommended for use with non-Manchestered payload data. + + procedure Get_OOK_Counter + (This : Si4432_Driver; + Value : out OOK_Counter; + MA : out Boolean; + Peak_Detector : out Boolean; + OOK_Freeze : out Boolean); + + procedure Set_Slicer_Peak_Holder + (This : Si4432_Driver; + Decay : UInt4; + -- OOK Peak Detector decay time. Peak detector value discharges at + -- rate proportional to 2^Decay. OOK slicing threshold is set 6 dB + -- below peak detector value. Effective only when OOK Peak Detector + -- is enabled. + + Attack : UInt3); + -- OOK Peak Detector attack time. Peak detector value charges up at + -- rate proportional to 2^Attack. OOK slicing threshold is set 6 dB + -- below peak detector value. Effective only when OOK Peak Detector + -- is enabled. + + procedure Get_Slicer_Peak_Holder + (This : Si4432_Driver; + Decay : out UInt4; + Attack : out UInt3); + + procedure Set_ADC8_Control + (This : Si4432_Driver; + Value : ADC8_Control); + -- Default: 16#10# + + function Get_ADC8_Control + (This : Si4432_Driver) + return ADC8_Control; + + procedure Set_Channel_Filter_Coefficient_Address + (This : Si4432_Driver; + Value : UInt4); + -- Default: 16#0# + -- This configures (in nibbles) for how long we will search for preamble. + -- If during this time the preamble is not detected, we will send a signal + -- (which can be configured as interrupt) and restart looking for the + -- preamble again. + + function Get_Channel_Filter_Coefficient_Address + (This : Si4432_Driver) + return UInt4; + + procedure Set_Crystal_Oscillator + (This : Si4432_Driver; + Output_Buffer : Boolean; + -- Default: False + -- This bit is active only if the Output_Buffer_Override is set to True. + + Output_Buffer_Override : Boolean; + -- Default: False + -- If set to True then the Output_Buffer controls the output buffer. + -- False: output buffer is controlled by the state machine. + -- True: output buffer is controlled by the Output_Buffer. + + Two_Times_Higher_Amplification : Boolean; + -- Default: True + + Two_Times_Higher_Bias_Current : Boolean; + -- Default: False + + Clock_Hysteresis : Boolean); + -- Default: False + + procedure Get_Crystal_Oscillator + (This : Si4432_Driver; + Output_Buffer : out Boolean; + Output_Buffer_Override : out Boolean; + Two_Times_Higher_Amplification : out Boolean; + Two_Times_Higher_Bias_Current : out Boolean; + Clock_Hysteresis : out Boolean; + Internal_Power_State : out Internal_Chip_State); + + ------------------- + -- Wake Up Timer -- + ------------------- + + -- Note: If a new configuration is needed (e.g., for the WUT or the LDC), + -- proper functionality is required. The function must first be disabled, + -- then the settings changed, then enabled back on. + + procedure Set_Wake_Up_Timer_Period + (This : Si4432_Driver; + Value : Wake_Up_Timer_Period); + -- Default 1 + + function Get_Wake_Up_Timer_Period + (This : Si4432_Driver) + return Wake_Up_Timer_Period; + + procedure Set_Wake_Up_Timer_Exponent + (This : Si4432_Driver; + Value : Wake_Up_Timer_Exponent); + -- Default 3 + -- The period of the wake-up timer can be calculated as + -- TWUT = (4 x M x 2^Wake_Up_Timer_Exponent)/32.768 ms. + -- Wake_Up_Timer_Exponent = 0 is allowed, and the maximum is decimal 20. + + function Get_Wake_Up_Timer_Exponent + (This : Si4432_Driver) + return Wake_Up_Timer_Exponent; + + function Get_Wake_Up_Timer_Current_Value + (This : Si4432_Driver) + return UInt16; + -- The value reflects the current count value of the timer. + + procedure Set_Low_Duty_Cycle_Mode_Duration + (This : Si4432_Driver; + Value : Low_Duty_Cycle_Mode_Duration); + -- If enabled, the LDC will start together when the WUT is supposed to + -- start, and the duration of the LDC is specified by the value and the + -- equation that goes with it. In order for the LDC to work, the LDC value + -- has to be smaller than the value specified in Wake_Up_Timer_Period. + + -- *Note: The period of the low-duty cycle ON time can be calculated as + -- TLDC_ON = (4 x LDC x 2^R)/32.768 ms. R is the Wake_Up_Timer_Exponent. + -- The LDC works in conjunction with the WUT. The LDC period must be + -- specified to be smaller than the WUT period. (i.e., the LDC register + -- must be smaller than the Wake_Up_Timer_Period). + + function Get_Low_Duty_Cycle_Mode_Duration + (This : Si4432_Driver) + return Low_Duty_Cycle_Mode_Duration; + + ------------------- + -- Packet_Length -- + ------------------- + + procedure Set_Packet_Length + (This : Si4432_Driver; + Length : UInt8); + -- Default 0 + -- The value in this register corresponds directly to the number of bytes + -- in the Packet. For example '00001000' corresponds to a packet length of + -- 8 bytes. The maximum packet length is '11111111', a 255 byte packet. + -- Writing 0 is possible, in this case we do not send any data in the + -- packet. During RX, if Header_Control_2.Fix_TR_Packet_Length = True, this + -- will specify also the Packet_Length for RX mode. + -- Use Get_Received_Packet_Length if Header_Control_2. + -- Fix_TR_Packet_Length = False to get received length. + + function Get_Packet_Length + (This : Si4432_Driver) + return UInt8; + + function Get_Received_Packet_Length + (This : Si4432_Driver) + return UInt8; + -- Length Byte of the Received Packet during Header_Control_2. + -- Fix_TR_Packet_Length = False. This register specifies the number of + -- Data bytes in the last received packet, and reflects the value of the + -- packet length byte in the received header. This is relevant ONLY if the + -- Fix_TR_Packet_Length is False. If the Fix_TR_Packet_Length is set, + -- then the expected number of received Data bytes must be programmed + -- into the Packet_Length. + + ---------- + -- RSSI -- + ---------- + + function Get_Received_Signal_Strength_Indicator + (This : Si4432_Driver) + return UInt8; + + procedure Set_RSSI_Threshold_For_Clear_Channel_Indicator + (This : Si4432_Driver; + Value : UInt8); + -- Interrupt is set if the RSSI value is above this threshold. + + function Get_RSSI_Threshold_For_Clear_Channel_Indicator + (This : Si4432_Driver) + return UInt8; + + function Get_Antenna_Diversity_1 + (This : Si4432_Driver) + return UInt8; + -- Measured RSSI Value on Antenna 1. + + function Get_Antenna_Diversity_2 + (This : Si4432_Driver) + return UInt8; + -- Measured RSSI Value on Antenna 2. + + ---------- + -- FIFO -- + ---------- + + procedure Send + (This : Si4432_Driver; + Data : SPI_Data_8b); + -- Send data as a variable-length packet. It set count of bytes by + -- Packet_Length, fill data with Set_FIFO_Data and turn TX on by + -- Set_TX_Mode. + + procedure Get_Received + (This : Si4432_Driver; + Data : out SPI_Data_8b); + -- Get received data. Lenght of the data can be get by + -- Get_Received_Packet_Length. Also clears the RX FIFO with + -- Clear_RX_FIFO if all data was copied to the Data + + procedure Set_TX_FIFO_Almost_Full + (This : Si4432_Driver; + Value : FIFO_Threshold); + -- Default 16#37# + -- This specifies the threshold value at which the TXFFAFULL status + -- bit/interrupt will be generated, as data bytes are stored into the + -- TX FIFO for later transmission. This value should be programmed to + -- 1 byte less than the desired threshold value. Example: A value of + -- 0x3C=60d will not generate an interrupt if 60 bytes (or less) are + -- written to the TX FIFO, but will generate an interrupt when 61 bytes + -- (or more) are written to the TX FIFO. + + function Get_TX_FIFO_Almost_Full + (This : Si4432_Driver) + return FIFO_Threshold; + + procedure Set_TX_FIFO_Almost_Empty + (This : Si4432_Driver; + Value : FIFO_Threshold); + -- Default 16#4# + -- This register specifies the threshold value at which the TXFFAEM status + -- bit/interrupt will be generated, as data bytes are pulled from the + -- TX FIFO and transmitted. This value should be programmed to 1 byte less + -- than the desired threshold value. Example: A value of 0x05 will generate + -- an interrupt when 6 bytes remain in the TX FIFO. + + function Get_TX_FIFO_Almost_Empty + (This : Si4432_Driver) + return FIFO_Threshold; + + procedure Set_RX_FIFO_Almost_Full + (This : Si4432_Driver; + Value : FIFO_Threshold); + -- Default 16#37# + -- This register specifies the threshold value at which the RXFFAFULL + -- status bit/interrupt will be generated, as data bytes are received and + -- stored into the RX FIFO for later retrieval. This value should be + -- programmed to 1 byte less than the desired threshold value. + -- Example: A value of 0x3C=60d will not generate an interrupt if 60 + -- bytes (or less) are received and stored to the RX FIFO, but will + -- generate an interrupt when 61 bytes (or more) are received and stored + -- to the RX FIFO. + + function Get_RX_FIFO_Almost_Full + (This : Si4432_Driver) + return FIFO_Threshold; + +private + + type Register_Address is range 16#00# .. 16#7F# with Size => UInt7'Size; + + type Operation_Type is (Read, Write) with Size => Bit'Size; + for Operation_Type use (Read => 0, Write => 1); + + ---------------- + -- Registers -- + ---------------- + + type Device_Type_Code_Register is record + dt : UInt5; -- R + Reserved_R : UInt3 := 0; -- R + end record with Size => Register'Size; + -- Reset value = 00001000 + + for Device_Type_Code_Register use record + dt at 0 range 0 .. 4; + Reserved_R at 0 range 5 .. 7; + end record; + + type Version_Code_Register is record + vc : UInt5; -- R + Reserved_R : UInt3 := 0; -- R + end record with Size => Register'Size; + + for Version_Code_Register use record + vc at 0 range 0 .. 4; + Reserved_R at 0 range 5 .. 7; + end record; + + for Chip_State use (Idle => 0, RX => 1, TX => 2); + + type Device_Status_Register is record + cps : Chip_State; -- R + Reserved_R : Bit; -- R + freqerr : Bit; -- R + -- Frequency Error Status. + -- The programmed frequency is outside of the operating range. + -- The actual frequency is saturated to the max/min value. + + headerr : Bit; -- R + -- Header Error Status. + -- Indicates if the received packet has a header check error. + + rxffem : Bit; -- R + -- RX FIFO Empty Status. + + ffunfl : Bit; -- R + -- RX/TX FIFO Underflow Status. + + ffovfl : Bit; -- R + -- RX/TX FIFO Overflow Status. + end record with Size => Register'Size; + -- Reset value = xxxxxxxx + + for Device_Status_Register use record + cps at 0 range 0 .. 1; + Reserved_R at 0 range 2 .. 2; + freqerr at 0 range 3 .. 3; + headerr at 0 range 4 .. 4; + rxffem at 0 range 5 .. 5; + ffunfl at 0 range 6 .. 6; + ffovfl at 0 range 7 .. 7; + end record; + + type Interrupt_Status_1_Register is record + icrerror : Bit; -- R + -- CRC Error. + -- When set to 1 the cyclic redundancy check is failed. + + ipkvalid : Bit; -- R + -- Valid Packet Received. When set to 1 a valid packet has + -- been received. + + ipksent : Bit; -- R + -- Packet Sent Interrupt. + -- When set to1 a valid packet has been transmitted. + + iext : Bit; -- R + -- External Interrupt. + -- When set to 1 an interrupt occurred on one of the GPIO's if it is + -- programmed so. The status can be checked in register 0Eh. See + -- GPIOx Configuration section for the details. + + irxffafull : Bit; -- R + -- RX FIFO Almost Full.When set to 1 the RX FIFO has met its almost + -- full threshold and needs to be read by the microcontroller. + + ixtffaem : Bit; -- R + -- TX FIFO Almost Empty. + -- When set to 1 the TX FIFO is almost empty and needs to be filled. + + itxffafull : Bit; -- R + -- TX FIFO Almost Full. + -- When set to 1 the TX FIFO has met its almost full threshold and + -- needs to be transmitted. + + ifferr : Bit; -- R + -- FIFO Underflow/Overflow Error. + -- When set to 1 the TX or RX FIFO has overflowed or underflowed. + end record with Size => Register'Size; + -- Reset value = xxxxxxxx + + for Interrupt_Status_1_Register use record + icrerror at 0 range 0 .. 0; + ipkvalid at 0 range 1 .. 1; + ipksent at 0 range 2 .. 2; + iext at 0 range 3 .. 3; + irxffafull at 0 range 4 .. 4; + ixtffaem at 0 range 5 .. 5; + itxffafull at 0 range 6 .. 6; + ifferr at 0 range 7 .. 7; + end record; + + type Interrupt_Status_2_Register is record + ipor : Bit; -- R + -- Power-on-Reset (POR). + -- When the chip detects a Power on Reset above the desired setting + -- this bit will be set to 1. + + ichiprdy : Bit; -- R + -- Chip Ready (XTAL). + -- When a chip ready event has been detected this bit will be set to 1. + + ilbd : Bit; -- R + -- Low Battery Detect. + -- When a low battery event has been detected this bit will be set to 1. + -- This interrupt event is saved even if it is not enabled by the mask + -- register bit and causes an interrupt after it is enabled. + + iwut : Bit; -- R + -- Wake-Up-Timer. + -- On the expiration of programmed wake-up timer this bit will be set + -- to 1. + + irssi : Bit; -- R + -- RSSI. + -- When RSSI level exceeds the programmed threshold this bit will be + -- set to 1. + + ipreainval : Bit; -- R + -- Invalid Preamble Detected. + -- When the preamble is not found within a period of time set by the + -- invalid preamble detection threshold in Register 60h, this bit will + -- be set to 1. + + ipreaval : Bit; -- R + -- Valid Preamble Detected. + -- When a preamble is detected this bit will be set to 1. + + iswdet : Bit; -- R + -- Sync Word Detected. + -- When a sync word is detected this bit will be set to 1. + end record with Size => Register'Size; + -- Reset value = xxxxxxxx + + for Interrupt_Status_2_Register use record + ipor at 0 range 0 .. 0; + ichiprdy at 0 range 1 .. 1; + ilbd at 0 range 2 .. 2; + iwut at 0 range 3 .. 3; + irssi at 0 range 4 .. 4; + ipreainval at 0 range 5 .. 5; + ipreaval at 0 range 6 .. 6; + iswdet at 0 range 7 .. 7; + end record; + + type Interrupt_Enable_1_Register is record + encrcerror : Bit; -- R/W + -- Enable CRC Error. + -- When set to 1 the CRC Error interrupt will be enabled. + + enpkvalid : Bit; -- R/W + -- Enable Valid Packet Received. + -- When ipkvalid = 1 the Valid Packet Received Interrupt will be enabled. + + enpksent : Bit; -- R/W + -- Enable Packet Sent. + -- When ipksent =1 the Packet Sense Interrupt will be enabled. + + enext : Bit; -- R/W + -- Enable External Interrupt. + -- When set to 1 the External Interrupt will be enabled. + + enrxffafull : Bit; -- R/W + -- Enable RX FIFO Almost Full. + -- When set to 1 the RX FIFO Almost Full interrupt will be enabled. + + entxffaem : Bit; -- R/W + -- Enable TX FIFO Almost Empty. + -- When set to 1 the TX FIFO Almost Empty interrupt will be enabled. + + entxffafull : Bit; -- R/W + -- Enable TX FIFO Almost Full. + -- When set to 1 the TX FIFO Almost Full interrupt will be enabled. + + enfferr : Bit; -- R/W + -- Enable FIFO Underflow/Overflow. + -- When set to 1 the FIFO Underflow/Overflow interrupt will be enabled. + end record with Size => Register'Size; + -- Reset value = 00000000 + + for Interrupt_Enable_1_Register use record + encrcerror at 0 range 0 .. 0; + enpkvalid at 0 range 1 .. 1; + enpksent at 0 range 2 .. 2; + enext at 0 range 3 .. 3; + enrxffafull at 0 range 4 .. 4; + entxffaem at 0 range 5 .. 5; + entxffafull at 0 range 6 .. 6; + enfferr at 0 range 7 .. 7; + end record; + + type Interrupt_Enable_2_Register is record + enpor : Bit; -- R/W + -- Enable POR. + -- When set to 1 the POR interrupt will be enabled. + + enchiprdy : Bit; -- R/W + -- Enable Chip Ready (XTAL). + -- When set to 1 the Chip Ready interrupt will be enabled. + + enlbd : Bit; -- R/W + -- Enable Low Battery Detect. + -- When set to 1 the Low Battery Detect interrupt will be enabled. + + enwut : Bit; -- R/W + -- Enable Wake-Up Timer. + -- When set to 1 the Wake-Up Timer interrupt will be enabled. + + enrssi : Bit; -- R/W + -- Enable RSSI. + -- When set to 1 the RSSI Interrupt will be enabled. + + enpreainval : Bit; -- R/W + -- Enable Invalid Preamble Detected. + -- When set to 1 the Invalid Preamble Detected Interrupt will be enabled. + + enpreaval : Bit; -- R/W + -- Enable Valid Preamble Detected. + -- When set to 1 the Valid Preamble Detected Interrupt will be enabled. + + enswdet : Bit; -- R/W + -- Enable Sync Word Detected. + -- When set to 1 the Syn Word Detected Interrupt will be enabled. + end record with Size => Register'Size; + -- Reset value = 00000011 + + for Interrupt_Enable_2_Register use record + enpor at 0 range 0 .. 0; + enchiprdy at 0 range 1 .. 1; + enlbd at 0 range 2 .. 2; + enwut at 0 range 3 .. 3; + enrssi at 0 range 4 .. 4; + enpreainval at 0 range 5 .. 5; + enpreaval at 0 range 6 .. 6; + enswdet at 0 range 7 .. 7; + end record; + + type Operating_Mode_And_Function_Control_1_Register is record + xton : Bit; -- R/W + -- READY Mode (Xtal is ON). + + pllon : Bit; -- R/W + -- TUNE Mode (PLL is ON). + -- When pllon = 1 the PLL will remain enabled in Idle State. This allows + -- for faster turn-around time at the cost of increased current + -- consumption in Idle State. + + rxon : Bit; -- R/W + -- RX on in Manual Receiver Mode. + -- Automatically cleared if Multiple Packets config. is disabled and + -- a valid packet received. + + txon : Bit; -- R/W + -- TX on in Manual Transmit Mode. + -- Automatically cleared in FIFO mode once the packet is sent. + + x32ksel : Crystal_Oscillator; -- R/W + -- 32,768 kHz Crystal Oscillator Select. + -- 0: RC oscillator + -- 1: 32 kHz crystal + + enwt : Bit; -- R/W + -- Enable Wake-Up-Timer. + -- Enabled when enwt = 1. If the Wake-up-Timer function is enabled it + -- will operate in any mode and notify the microcontroller through the + -- GPIO interrupt when the timer expires. + + enlbd : Bit; -- R/W + -- Enable Low Battery Detect. + -- When this bit is set to 1 the Low Battery Detector circuit and + -- threshold comparison will be enabled. + + swres : Bit; -- R/W + -- Software Register Reset Bit. + -- This bit may be used to reset all registers simultaneously to + -- a DEFAULT state, without the need for sequentially writing to each + -- individual register. The RESET is accomplished by setting swres = 1. + -- This bit will be automatically cleared. The user should wait until + -- the CHIPRDY status flag/interrupt is issued before sending further + -- SPI commands to the chip. + end record with Size => Register'Size; + -- Reset value = 00000001 + + for Operating_Mode_And_Function_Control_1_Register use record + xton at 0 range 0 .. 0; + pllon at 0 range 1 .. 1; + rxon at 0 range 2 .. 2; + txon at 0 range 3 .. 3; + x32ksel at 0 range 4 .. 4; + enwt at 0 range 5 .. 5; + enlbd at 0 range 6 .. 6; + swres at 0 range 7 .. 7; + end record; + + type Operating_Mode_And_Function_Control_2_Register is record + ffclrtx : Bit; -- R/W + -- TX FIFO Reset/Clear. + -- This has to be a two writes operation: Setting ffclrtx =1 followed + -- by ffclrtx = 0 will clear the contents of the TX FIFO. + + ffclrrx : Bit; -- R/W + -- RX FIFO Reset/Clear. + -- This has to be a two writes operation: Setting ffclrrx =1 followed + -- by ffclrrx = 0 will clear the contents of the RX FIFO. + + enldm : Bit; -- R/W + -- Enable Low Duty Cycle Mode. + -- If this bit is set to 1 then the chip turns on the RX regularly. + -- The frequency should be set in the Wake-Up Timer Period register, + -- while the minimum ON time should be set in the Low-Duty Cycle Mode + -- Duration register. The FIFO mode should be enabled also. + + autotx : Bit; -- R/W + -- Automatic Transmission. + -- When autotx = 1 the transceiver will enter automatically TX State + -- when the FIFO is almost full. When the FIFO is empty it will + -- automatically return to the Idle State. + + rxmpk : Bit; -- R/W + -- RX Multi Packet. + -- When the chip is selected to use FIFO Mode (dtmod[1:0]) and RX Packet + -- Handling (enpacrx) then it will fill up the FIFO with multiple valid + -- packets if this bit is set, otherwise the transceiver will + -- automatically leave the RX State after the first valid packet has + -- been received. + + antdiv : UInt3; -- R/W + -- Enable Antenna Diversity. + -- The GPIO must be configured for Antenna Diversity for the algorithm + -- to work properly. + end record with Size => Register'Size; + -- Reset value = 00000000 + + for Operating_Mode_And_Function_Control_2_Register use record + ffclrtx at 0 range 0 .. 0; + ffclrrx at 0 range 1 .. 1; + enldm at 0 range 2 .. 2; + autotx at 0 range 3 .. 3; + rxmpk at 0 range 4 .. 4; + antdiv at 0 range 5 .. 7; + end record; + + type Crystal_Oscillator_Load_Capacitance_Register is record + xlc : UInt7; -- R/W + -- Tuning Capacitance for the 30 MHz XTAL. + + xtalshft : Bit; -- R/W + -- Additional capacitance to coarse shift the frequency if xlc is not + -- sufficient. Not binary with xlc + end record with Size => Register'Size; + -- Reset value = 01111111 + + for Crystal_Oscillator_Load_Capacitance_Register use record + xlc at 0 range 0 .. 6; + xtalshft at 0 range 7 .. 7; + end record; + + for Microcontroller_Clock use + (c30MHz => 0, c15MHz => 2#001#, c10MHz => 2#010#, c4MHz => 2#011#, + c3MHz => 2#100#, c2MHz => 2#101#, c1MHz => 2#110#, c32kHz => 2#111#); + + type Microcontroller_Output_Clock_Register is record + mclk : Microcontroller_Clock; -- R/W + -- Microcontroller Clock. + -- Different clock frequencies may be selected for configurable GPIO + -- clock output. All clock frequencies are created by dividing the XTAL + -- except for the 32 kHz clock which comes directly from the 32 kHz + -- RC Oscillator. The mclk[2:0] setting is only valid when xton = 1 + -- except the 111. + + enlfc : Bit; -- R/W + -- Enable Low Frequency Clock. + -- When enlfc = 1 and the chip is in Sleep mode then the 32.768 kHz + -- clock will be provided to the microcontroller no matter what the + -- selection of mclk[2:0] is. For example if mclk = 000, 30 MHz will + -- be available through the GPIO to output to the microcontroller in + -- all Idle, TX, or RX states. When the chip is commanded to Sleep mode + -- the 30 MHz clock will become 32.768 kHz. + + clkt : UInt2; -- R/W + -- Clock Tail. + -- If enlfc = 0 then it can be useful to provide a few extra cycles for + -- the microcontroller to complete its operation. Setting the clkt + -- register will provide the addition cycles of the clock before it + -- shuts off. + + Reserved : UInt2; -- R + end record with Size => Register'Size; + -- Reset value = xx000110 + + for Microcontroller_Output_Clock_Register use record + mclk at 0 range 0 .. 2; + enlfc at 0 range 3 .. 3; + clkt at 0 range 4 .. 5; + Reserved at 0 range 6 .. 7; + end record; + + for GPIO_0_Function use + (Power_On_Reset => 2#00000#, -- (output) + Wake_Up_Timer => 2#00001#, + -- 1 when WUT has expired (output) + Low_Battery_Detect => 2#00010#, + -- 1 when battery is below threshold setting (output) + Direct_Digital_Input => 2#00011#, + Interrupt_Falling_Edge => 2#00100#, -- (input) + Interrupt_Rising_Edge => 2#00101#, -- (input) + Interrupt_State_Change => 2#00110#, -- (input) + ADC_Analog_Input => 2#00111#, + Reserved_Analog_Test_N_Input => 2#01000#, + Reserved_Analog_Test_P_Input => 2#01001#, + Direct_Digital_Output => 2#01010#, + Reserved_Digital_Test_Output => 2#01011#, + Reserved_Analog_Test_N_Output => 2#01100#, + Reserved_Analog_Test_P_Output => 2#01101#, + Reference_Voltage => 2#01110#, -- (output) + Data_CLK_Output => 2#01111#, + -- TX/RX Data CLK output to be used in conjunction with TX/RX + -- Data pin (output) + TX_Data_Input => 2#10000#, + -- TX Data input for direct modulation (input) + External_Retransmission_Request => 2#10001#, -- (input) + TX_State => 2#10010#, -- (output) + TX_FIFO_Almost_Full => 2#10011#, -- (output) + RX_Data => 2#10100#, -- (output) + RX_State => 2#10101#, -- (output) + RX_FIFO_Almost_Full => 2#10110#, -- (output) + Antenna_1_Switch => 2#10111#, + -- Antenna 1 Switch used for antenna diversity (output) + Antenna_2_Switch => 2#11000#, + -- Antenna 2 Switch used for antenna diversity (output) + Valid_Preamble_Detected => 2#11001#, -- (output) + Invalid_Preamble_Detected => 2#11010#, -- (output) + Sync_Word_Detected => 2#11011#, -- (output) + Clear_Channel_Assessment => 2#11100#, -- (output) + VDD => 2#11101#, + GND0 => 2#11110#, + GND1 => 2#11111#); + + type GPIO0_Configuration_Register is record + gpio : GPIO_0_Function; -- R/W + -- Pin Function Select, see below + + pup : Bit; -- R/W + -- Pullup Resistor Enable on GPIO0. + -- When set to 1 a 200 kOm resistor is connected internally between + -- VDD and the pin if the GPIO is configured as a digital input. + + gpiodrv : UInt2; -- R/W + -- GPIO Driving Capability Setting. + end record with Size => Register'Size; + -- Reset value = 00000000 + + for GPIO0_Configuration_Register use record + gpio at 0 range 0 .. 4; + pup at 0 range 5 .. 5; + gpiodrv at 0 range 6 .. 7; + end record; + + for GPIO_1_Function use + (Inverted_Power_On_Reset => 2#00000#, -- (output) + Wake_Up_Timer => 2#00001#, + -- 1 when WUT has expired (output) + Low_Battery_Detect => 2#00010#, + -- 1 when battery is below threshold setting (output) + Direct_Digital_Input => 2#00011#, + Interrupt_Falling_Edge => 2#00100#, -- (input) + Interrupt_Rising_Edge => 2#00101#, -- (input) + Interrupt_State_Change => 2#00110#, -- (input) + ADC_Analog_Input => 2#00111#, -- (input) + Reserved_Analog_Test_N_Input => 2#01000#, + Reserved_Analog_Test_P_Input => 2#01001#, + Direct_Digital_Output => 2#01010#, + Reserved_Digital_Test_Output => 2#01011#, + Reserved_Analog_Test_N_Output => 2#01100#, + Reserved_Analog_Test_P_Output => 2#01101#, + Reference_Voltage => 2#01110#, -- (output) + Data_CLK_Output => 2#01111#, + -- TX/RX Data CLK output to be used in conjunction with TX/RX + -- Data pin (output) + TX_Data_Input => 2#10000#, + -- TX Data input for direct modulation (input) + External_Retransmission_Request => 2#10001#, -- (input) + TX_State => 2#10010#, -- (output) + TX_FIFO_Almost_Full => 2#10011#, -- (output) + RX_Data => 2#10100#, -- (output) + RX_State => 2#10101#, -- (output) + RX_FIFO_Almost_Full => 2#10110#, -- (output) + Antenna_1_Switch => 2#10111#, + -- Antenna 1 Switch used for antenna diversity (output) + Antenna_2_Switch => 2#11000#, + -- Antenna 2 Switch used for antenna diversity (output) + Valid_Preamble_Detected => 2#11001#, -- (output) + Invalid_Preamble_Detected => 2#11010#, -- (output) + Sync_Word_Detected => 2#11011#, -- (output) + Clear_Channel_Assessment => 2#11100#, -- (output) + VDD => 2#11101#, + GND0 => 2#11110#, + GND1 => 2#11111#); + + type GPIO1_Configuration_Register is record + gpio : GPIO_1_Function; -- R/W + -- Pin Function Select, see below + + pup : Bit; -- R/W + -- Pullup Resistor Enable on GPIO0. + -- When set to 1 a 200 kOm resistor is connected internally between + -- VDD and the pin if the GPIO is configured as a digital input. + + gpiodrv : UInt2; -- R/W + -- GPIO Driving Capability Setting. + end record with Size => Register'Size; + -- Reset value = 00000000 + + for GPIO1_Configuration_Register use record + gpio at 0 range 0 .. 4; + pup at 0 range 5 .. 5; + gpiodrv at 0 range 6 .. 7; + end record; + + for GPIO_2_Function use + (Microcontroller_Clocks => 2#00000#, + Wake_Up_Timer => 2#00001#, + -- 1 when WUT has expired (output) + Low_Battery_Detect => 2#00010#, + -- 1 when battery is below threshold setting (output) + Direct_Digital_Input => 2#00011#, + Interrupt_Falling_Edge => 2#00100#, -- (input) + Interrupt_Rising_Edge => 2#00101#, -- (input) + Interrupt_State_Change => 2#00110#, -- (input) + ADC_Analog_Input => 2#00111#, -- (input) + Reserved_Analog_Test_N_Input => 2#01000#, + Reserved_Analog_Test_P_Input => 2#01001#, + Direct_Digital_Output => 2#01010#, + Reserved_Digital_Test_Output => 2#01011#, + Reserved_Analog_Test_N_Output => 2#01100#, + Reserved_Analog_Test_P_Output => 2#01101#, + Reference_Voltage => 2#01110#, -- (output) + Data_CLK_Output => 2#01111#, + -- TX/RX Data CLK output to be used in conjunction with TX/RX + -- Data pin (output) + TX_Data_Input => 2#10000#, + -- TX Data input for direct modulation (input) + External_Retransmission_Request => 2#10001#, -- (input) + TX_State => 2#10010#, -- (output) + TX_FIFO_Almost_Full => 2#10011#, -- (output) + RX_Data => 2#10100#, -- (output) + RX_State => 2#10101#, -- (output) + RX_FIFO_Almost_Full => 2#10110#, -- (output) + Antenna_1_Switch => 2#10111#, + -- Antenna 1 Switch used for antenna diversity (output) + Antenna_2_Switch => 2#11000#, + -- Antenna 2 Switch used for antenna diversity (output) + Valid_Preamble_Detected => 2#11001#, -- (output) + Invalid_Preamble_Detected => 2#11010#, -- (output) + Sync_Word_Detected => 2#11011#, -- (output) + Clear_Channel_Assessment => 2#11100#, -- (output) + VDD => 2#11101#, + GND0 => 2#11110#, + GND1 => 2#11111#); + + type GPIO2_Configuration_Register is record + gpio : GPIO_2_Function; -- R/W + -- Pin Function Select, see below + + pup : Bit; -- R/W + -- Pullup Resistor Enable on GPIO0. + -- When set to 1 a 200 kOm resistor is connected internally between + -- VDD and the pin if the GPIO is configured as a digital input. + + gpiodrv : UInt2; -- R/W + -- GPIO Driving Capability Setting. + end record with Size => Register'Size; + -- Reset value = 00000000 + + for GPIO2_Configuration_Register use record + gpio at 0 range 0 .. 4; + pup at 0 range 5 .. 5; + gpiodrv at 0 range 6 .. 7; + end record; + + type IO_Port_Configuration_Register is record + dio0 : Bit; -- R/W + -- Direct I/O for GPIO0. + -- If the GPIO0 is configured to be a direct output then the value on + -- the GPIO pin can be set here. If the GPIO0 is configured to be a + -- direct input then the value of the pin can be read here. + + dio1 : Bit; -- R/W + -- Direct I/O for GPIO1. + -- If the GPIO1 is configured to be a direct output then the value on + -- the GPIO pin can be set here. If the GPIO1 is configured to be a + -- direct input then the value of the pin can be read here. + + dio2 : Bit; -- R/W + -- Direct I/O for GPIO2. + -- If the GPIO2 is configured to be a direct output then the value on + -- the GPIO pin can be set here. If the GPIO2 is configured to be a + -- direct input then the value of the pin can be read here. + + itsdo : Bit; -- R/W + -- Interrupt Request Output on the SDO Pin. + -- nIRQ output is present on the SDO pin if this bit is set and the + -- nSEL input is inactive (high). + + extitst0 : Bit; -- R + -- External Interrupt Status. + -- If the GPIO0 is programmed to be an external interrupt source then + -- the status can be read here. + + extitst1 : Bit; -- R + -- External Interrupt Status. + -- If the GPIO1 is programmed to be an external interrupt source then + -- the status can be read here. + + extitst2 : Bit; -- R + -- External Interrupt Status. + -- If the GPIO2 is programmed to be an external interrupt source then + -- the status can be read here. + Reserved : Bit; -- R + end record with Size => Register'Size; + -- Reset value = 00000000 + + for IO_Port_Configuration_Register use record + dio0 at 0 range 0 .. 0; + dio1 at 0 range 1 .. 1; + dio2 at 0 range 2 .. 2; + itsdo at 0 range 3 .. 3; + extitst0 at 0 range 4 .. 4; + extitst1 at 0 range 5 .. 5; + extitst2 at 0 range 6 .. 6; + Reserved at 0 range 7 .. 7; + end record; + + for ADC_Input_Source use + (Internal_Temperature_Sensor => 2#000#, + GPIO0_Single_Ended => 2#001#, + GPIO1_Single_Ended => 2#010#, + GPIO2_Single_Ended => 2#011#, + GPIO0_GPIO1_differential => 2#100#, + GPIO1_GPIO2_differential => 2#101#, + GPIO0_GPIO2_differential => 2#110#, + GND => 2#111#); + + type ADC_Configuration_Register is record + adcgain : UInt2; -- R/W + -- ADC Sensor Amplifier Gain Selection. + -- The full scale range of the internal 8-bit ADC in differential mode + -- (see adcsel) + + adcref : UInt2; -- R/W + -- ADC Reference Voltage Selection. + -- The reference voltage of the internal 8-bit ADC can be selected + + adcsel : ADC_Input_Source; -- R/W + -- ADC Input Source Selection. + -- The internal 8-bit ADC input source can be selected + + adcstart : Bit; -- R/W + -- ADC Measurement Start Bit. + -- Set this bit=1 starts the ADC measurement process. This bit self- + -- clears during the measurement cycle and returns high when the + -- measurement is complete. The conversion process is fast; reading + -- this bit may always appear to return a 1. + end record with Size => Register'Size; + -- Reset value = 00000000 + + for ADC_Configuration_Register use record + adcgain at 0 range 0 .. 1; + adcref at 0 range 2 .. 3; + adcsel at 0 range 4 .. 6; + adcstart at 0 range 7 .. 7; + end record; + + type ADC_Sensor_Amplifier_Offset_Register is record + adcoffs : UInt4; -- R/W + -- *Note: The offset can be calculated as + -- Offset = adcoffs[2:0] x VDD/1000; MSB = adcoffs[3] = Sign bit. + Reserved : UInt4; -- R + end record; + + for ADC_Sensor_Amplifier_Offset_Register use record + adcoffs at 0 range 0 .. 3; + Reserved at 0 range 4 .. 7; + end record; + + subtype ADC_Value_Register is UInt8; -- R + -- Internal 8 bit ADC Output Value. + -- Reset value = xxxxxxxx + + for Temperature_Sensor_Range use + (From_Minus_64_To_64C => 2#00#, + From_Minus_64_To_192C => 2#01#, + From_Minus_40_To_216F => 2#10#, + From_0_To_12C => 2#11#); + + type Temperature_Sensor_Calibration_Register is record + tstrim : UInt4; -- R/W + -- Temperature Sensor Trim Value. + + entstrim : Bit; -- R/W + -- Temperature Sensor Trim Enable. + + entsoffs : Bit; -- R/W + -- Temperature Sensor Offset to Convert from K to ºC. Default is 1. + -- Test mode only, to use set tsrange and entsoffs to 0. + + tsrange : Temperature_Sensor_Range; -- R/W + -- Temperature Sensor Range Selection (FS range is 0-1024 mV) + end record with Size => Register'Size; + -- Reset value = 00100000 + + for Temperature_Sensor_Calibration_Register use record + tstrim at 0 range 0 .. 3; + entstrim at 0 range 4 .. 4; + entsoffs at 0 range 5 .. 5; + tsrange at 0 range 6 .. 7; + end record; + + subtype Temperature_Value_Offset_Register is UInt8; -- R/W + -- This value is added to the measured temperature value. + -- (MSB, tvoffs[8]: sign bit). + -- Reset value = 00000000 + + type Wake_Up_Timer_Period_1_Register is record + wtr : UInt4; -- R/W + -- Wake Up Timer Exponent (R) Value*. + -- Maximum value for R is decimal 20. A value greater than 20 will + -- yield a result as if 20 were written. R Value = 0 can be written + -- here. + -- *Note: The period of the wake-up timer can be calculated as + -- TWUT = (4 x M x 2R)/32.768 ms. R = 0 is allowed, and the maximum + -- value for R is decimal 20. A value greater than 20 will result in + -- the same as if 20 was written. + + Reserved : UInt3; -- R/W + end record with Size => Register'Size; + -- Reset value = xxx00011 + + -- Note: If a new configuration is needed (e.g., for the WUT or the LDC), + -- proper functionality is required. The function must first be disabled, + -- then the settings changed, then enabled back on. + + for Wake_Up_Timer_Period_1_Register use record + wtr at 0 range 0 .. 3; + Reserved at 0 range 4 .. 7; + end record; + + subtype Wake_Up_Timer_Period_Register is UInt8; -- R/W + -- wtm2[15:8] wtm3[7:0] + -- *Note: The period of the wake-up timer can be calculated as + -- TWUT = (4 x M x 2R)/32.768 ms. + -- Reset value = 00000000 00000001 + + subtype Wake_Up_Timer_Value_Register is UInt8; -- R + -- wtv1[15:8] wtv2[7:0] + -- Wake Up Timer Current Mantissa (M) Value. The value in wtv[15:0] + -- reflects the current count value of the timer. + -- Reset value = xxxxxxxx + + subtype Low_Duty_Cycle_Mode_Duration_Register is UInt8; -- R/W + -- Low-Duty Cycle Mode Duration (LDC)*. + -- If enabled, the LDC will start together when the WUT is supposed to + -- start, and the duration of the LDC is specified by the address 19h and + -- the equation that goes with it. In order for the LDC to work, the LDC + -- value has to be smaller than the M value specified in registers 15h + -- and 16h. + -- LDC = 0 is not allowed here. Write at least decimal 1. + -- *Note: The period of the low-duty cycle ON time can be calculated as + -- TLDC_ON = (4 x LDC x 2R)/32.768 ms. R is the same as in the wake-up + -- timer setting in "Register 14h. Wake-Up Timer Period 1". The LDC works + -- in conjunction with the WUT. The LDC period must be specified to be + -- smaller than the WUT period. (i.e., the LDC register must be smaller + -- than the M register). The LDC may not be programmed to 0. + -- Reset value = 00000001 + + type Low_Battery_Detector_Threshold_Register is record + lbdt : UInt5; -- R/W + -- Low Battery Detector Threshold. + -- This threshold is compared to Battery Voltage Level. If the Battery + -- Voltage is less than the threshold the Low Battery Interrupt is set. + -- Default = 2.7 V.* + Reserved : UInt3; -- R + end record with Size => Register'Size; + -- Reset value = xxx10100 + -- *Note: The threshold can be calculated as Vthreshold = + -- 1.7 + lbdt x 50 mV. + + for Low_Battery_Detector_Threshold_Register use record + lbdt at 0 range 0 .. 4; + Reserved at 0 range 5 .. 7; + end record; + + type Battery_Voltage_Level_Register is record + vbat : UInt5; -- R + -- Battery Voltage Level. + -- The battery voltage is converted by a 5 bit ADC if the LBD bit D6 of + -- Reg 07h is also set. In Sleep Mode the register is updated in every + -- 1 s. In other states it measures continuously. The measured voltage + -- is calculated by the following formula: + -- Vbat_meas=1.7V + vbat[4:0] x 50 mV + Reserved : UInt3; -- R + end record with Size => Register'Size; + -- Reset value = xxxxxxxx + + for Battery_Voltage_Level_Register use record + vbat at 0 range 0 .. 4; + Reserved at 0 range 5 .. 7; + end record; + + type IF_Filter_Bandwidth_Register is record + filset : UInt4; -- R/W + -- IF Filter Coefficient Sets. + -- Selects one of 15 pre-calculated sets of digital FIR filter tap + -- coefficients. Along with the decimation ratios selected by + -- dwn3_bypass and ndec_exp, the filter coefficients determine the + -- bandwidth of the IF filter. + + ndec_exp : UInt3; -- R/W + -- IF Filter Decimation Rates. + -- The oversampled data in the receive data path is decimated by a + -- factor of 2^ndec_exp. A higher decimation factor (i.e., larger value + -- of ndec_exp) results in a lower IF filter bandwidth. + + dwn3_bypass : Bit; -- R/W + -- Bypass Decimate-by-3 Stage. + -- If set, results in bypassing a decimate-by-3 stage in the path of + -- the oversampled data path for the digital filter for the IF + -- bandwidth. + end record with Size => Register'Size; + -- Reset value = 00000001 + + for IF_Filter_Bandwidth_Register use record + filset at 0 range 0 .. 3; + ndec_exp at 0 range 4 .. 6; + dwn3_bypass at 0 range 7 .. 7; + end record; + + type AFC_Loop_Gearshift_Override_Register is record + ph0size : Bit; -- R/W + -- If low, we will reset the Preamble detector if there are 5 + -- consecutive zero phases. If high, the reset will happen after 3 + -- consecutive zero phases. + + matap : Bit; -- R/W + -- Number of taps for moving average filter during Antenna Diversity + -- RSSI evaluation. Allows for reduced noise variation on measured RSSI + -- value but with slower update rate. If high (1), filter tap + -- length = 8*Tb. If low (0=default), filter tap length = 8*Tb prior to + -- first PREAMBLE_VALID, and 4*Tb thereafter. + + p5bypass : Bit; -- R/W + -- If high (1), select 0dB bias for the second phase antenna selection, + -- if low (0), select 1.5 dB. The default is (1), selecting 0 dB. + + afcgearh : UInt3; -- R/W + -- AFC High Gear Setting. Feedback loop gain during AFC setting process + -- is proportional to 2^(-afcgearh[2:0]). + + enafc : Bit; -- R/W + -- AFC Enable. + + afcbd : Bit; -- R/W + -- AFC Wideband Enable (active high). If set, the IF filter bandwidth + -- is reduced after preamble detection, in order to optimize RX + -- sensitivity. The IF filter bandwidth used during preamble detection + -- is programmed by the FILSET, NDEC, and DWN3BYPASS parameters in SPI + -- Register 1CH. After preamble detection, the chip automatically + -- selects the next lower IF filter bandwidth by internally decreasing + -- the FILSET parameter by 1. The resulting filter bandwidth may be + -- determined from the bandwidth table provided under the description + -- for SPI Register 1CH. + end record with Size => Register'Size; + -- Reset value = 01000100 + + for AFC_Loop_Gearshift_Override_Register use record + ph0size at 0 range 0 .. 0; + matap at 0 range 1 .. 1; + p5bypass at 0 range 2 .. 2; + afcgearh at 0 range 3 .. 5; + enafc at 0 range 6 .. 6; + afcbd at 0 range 7 .. 7; + end record; + + type AFC_Timing_Control_Register is record + anwait : UInt3; -- R/W + -- Antenna switching wait time. Number of bit periods between toggling + -- selection of antennas in AntDiv mode, prior to reception of first + -- PREAMBLE_VALID. + -- Number of bit periods = (anwait + 2) x 4 + 3 (when AFC = enabled) + -- Number of bit periods = (anwait + 2) x 2 + 3 (when AFC = disabled) + -- Default value = 3'b010 = 19 bit periods (AFC = enabled). + + shwait : UInt3; -- R/W + -- Short wait periods after AFC correction used before preamble is + -- detected. Short wait=(RegValue+1) x 2Tb. If set to 0 then no AFC + -- correction will occur before preamble detect, i.e., AFC will be + -- disabled. + + swant_timer : UInt2; -- R/W + -- Additional number of bit periods to wait for RSSI value to stabilize + -- during Antenna Diversity 2nd phase antenna evaluation. If matap=0, + -- total wait time=8 x Tb+swant_timer[1:0]. If matap=1, total wait + -- time=12*Tb+swant_timer{1:0]. Effective only during Antenna Diversity. + end record with Size => Register'Size; + -- Reset value = xx001010 + + for AFC_Timing_Control_Register use record + anwait at 0 range 0 .. 2; + shwait at 0 range 3 .. 5; + swant_timer at 0 range 6 .. 7; + end record; + + type Clock_Recovery_Gearshift_Override_Register is record + crslow : UInt3; -- R/W + -- Clock Recovery Slow Gearshift Value. + + crfast : UInt3; -- R/W + -- Clock Recovery Fast Gearshift Value. + + Reserved : UInt2; -- R/W + end record with Size => Register'Size; + -- Reset value = 00000011 + + for Clock_Recovery_Gearshift_Override_Register use record + crslow at 0 range 0 .. 2; + crfast at 0 range 3 .. 5; + Reserved at 0 range 6 .. 7; + end record; + + subtype Clock_Recovery_Oversampling_Rate_Register is UInt8; -- R/W + -- Oversampling Rate. + -- 3 LSBs are the fraction, default = 0110 0100 = 12.5 clock cycles + -- per data bit + -- Reset value = 01100100 + + type Clock_Recovery_Offset_2_Register is record + ncoff : UInt4; -- R/W + -- ncoff[19:16] + -- NCO Offset. + + skip2phth : Bit; -- R/W + -- Skip 2nd Phase Ant Div Threshold. Threshold for skipping the 2nd + -- phase of RSSI detection during antenna diversity algorithm. 0=16 dB + -- (default), 1=11 dB. NOT RECOMMENDED FOR USER CONFIGURATION. + + rxosr : UInt3; -- R/W + -- rxosr[10:8] + -- Oversampling Rate. Upper bits. + end record with Size => Register'Size; + -- Reset value = 00000011 + + for Clock_Recovery_Offset_2_Register use record + ncoff at 0 range 0 .. 3; + skip2phth at 0 range 4 .. 4; + rxosr at 0 range 5 .. 7; + end record; + + subtype Clock_Recovery_Offset_Register is UInt8; -- R/W + -- ncoff1[15:8] ncoff0[7:0] + -- Reset value = 01000111 10101110 + + type Clock_Recovery_Timing_Loop_Gain_1_Register is record + crgain : UInt3; -- R/W + -- crgain[10:8] + -- Clock Recovery Timing Loop Gain. + + cgainx2 : Bit; -- R/W + -- Multiplying the CR Gain by 2. + + rxncocomp : Bit; -- R/W + -- Receive Compensation Enable for High Data Rate Offset. + + Reserved : UInt3; -- R/W + end record with Size => Register'Size; + -- Reset value = 00000010 + + for Clock_Recovery_Timing_Loop_Gain_1_Register use record + crgain at 0 range 0 .. 2; + cgainx2 at 0 range 3 .. 3; + rxncocomp at 0 range 4 .. 4; + Reserved at 0 range 5 .. 7; + end record; + + subtype Clock_Recovery_Timing_Loop_Gain_0_Register is UInt8; -- R/W + -- crgain[7:0] + -- Clock Recovery Timing Loop Gain. + -- Reset value = 10001111 + + subtype Received_Signal_Strength_Indicator_Register is UInt8; -- R + -- Reset value = xxxxxxxx + + subtype RSSI_Threshold_for_Clear_Channel_Indicator_Register is UInt8; + -- R/W + -- Interrupt is set if the RSSI value is above this threshold. + -- Reset value = 00011110 + + subtype Antenna_Diversity_Register is UInt8; -- R + -- Measured RSSI Value on Antenna 1 and 2. + -- Reset value = xxxxxxxx + + subtype AFC_Limiter_Register is UInt8; -- R/W + -- AFC limiter value. + -- Reset value = 00000000 + + subtype AFC_Correction_Register is UInt8; -- R + -- afc_corr[9:2] + -- AFC loop correction values [9:2] (MSBs only). Values are updated once, + -- after sync word is found during receiving. See also address 2Ch. + -- Reset value = xxxxxxxx + + type OOK_Counter_Value_1_Register is record + ookcnt : UInt3; -- R/W + -- ookcnt[10:8] + -- OOK counter [10:8] =OOK counter Value MSBs. This counter value will + -- affect the OOK AGC's decay time. + + madeten : Bit; -- R/W + -- MA_Enable. + -- madeten= when '1' (default), Moving Average Detector for OOK Modem + -- is enabled. Provides best sensitivity, but requires DC-balanced data + -- (e.g., Manchester data) and is more sensitive to co-channel + -- interference. Peak Detector output is logically AND'ed with Moving + -- Average Detector output. + + peakdeten : Bit; -- R/W + -- Peak Detector Enable. + -- peakdeten= when '1' (default), Peak Detector for OOK Modem is + -- enabled. Provides improved performance in presence of co-channel + -- interferers, at slight reduction of sensitivity. Peak Detector output + -- is logically AND'ed with Moving Average Detector output. + + ookfrzen : Bit; -- R/W + -- OOK Freeze. + -- ookfrzen= when '0' (default), AGC and OOK Moving Average Detector + -- threshold operate continuously. When '1', AGC and OOK MA Detector + -- threshold operate until PREAMBLE_VALID signal is detected; values + -- are frozen thereafter. Recommended for use with non-Manchestered + -- payload data. + + afc_corr : UInt2; -- R + -- afc_corr[1:0] + -- AFC Correction Values. + -- AFC loop correction values [1:0] (LSBs). Values are updated once, + -- after sync word is found during receiving. See also address 2Bh. + end record with Size => Register'Size; + -- Reset value = 00011000 + + for OOK_Counter_Value_1_Register use record + ookcnt at 0 range 0 .. 2; + madeten at 0 range 3 .. 3; + peakdeten at 0 range 4 .. 4; + ookfrzen at 0 range 5 .. 5; + afc_corr at 0 range 6 .. 7; + end record; + + subtype OOK_Counter_Value_2_Register is UInt8; -- R/W + -- ookcnt[7:0] + -- OOK counter value LSBs. This counter value will affect the OOK AGC's + -- decay time. + -- Reset value = 10111100 + + type Slicer_Peak_Holder_Register is record + decay : UInt4; -- R/W + -- Decay. decay[3:0]=OOK Peak Detector decay time. Peak detector value + -- discharges at rate proportional to 2^(-decay[3:0]). OOK slicing + -- threshold is set 6 dB below peak detector value. Effective only when + -- OOK Peak Detector is enabled. + + attack : UInt3; -- R/W + -- Attack. attack [2:0}=OOK Peak Detector attack time. Peak detector + -- value charges up at rate proportional to 2^(-attack[2:0]). OOK + -- slicing threshold is set 6 dB below peak detector value. Effective + -- only when OOK Peak Detector is enabled. + + Reserved : Bit; -- R/W + end record with Size => Register'Size; + -- Reset value = 00101100 + + for Slicer_Peak_Holder_Register use record + decay at 0 range 0 .. 3; + attack at 0 range 4 .. 6; + Reserved at 0 range 7 .. 7; + end record; + + for CRC_Polynomial use + (CCITT => 2#00#, + CRC_16 => 2#01#, + IEC_16 => 2#10#, + Biacheva => 2#11#); + + type Data_Access_Control_Register is record + crc : CRC_Polynomial; -- R/W + + encrc : Bit; -- R/W + -- CRC Enable. + -- Cyclic Redundancy Check generation is enabled if this bit is set. + + enpactx : Bit; -- R/W + -- Enable Packet TX Handling. + -- If FIFO Mode (dtmod = 10) is being used automatic packet handling + -- may be enabled. Setting enpactx = 1 will enable automatic packet + -- handling in the TX path. Register 30-4D allow for various + -- configurations of the packet structure. Setting enpactx = 0 will + -- not do any packet handling in the TX path. It will only transmit + -- what is loaded to the FIFO. + + skip2ph : Bit; -- R/W + -- Skip 2nd Phase of Preamble Detection. + -- If set, we skip the second phase of the preamble detection + -- (under certain conditions) if antenna diversity is enabled. + + crcdonly : Bit; -- R/W + -- CRC Data Only Enable. + -- When this bit is set to 1 the CRC is calculated on and checked + -- against the packet data fields only. + + lsbfrst : Bit; -- R/W + -- LSB First Enable. + -- The LSB of the data will be transmitted/received first if this + -- bit is set. + + enpacrx : Bit; -- R/W + -- Enable Packet RX Handling. + -- If FIFO Mode (dtmod = 10) is being used automatic packet handling + -- may be enabled. Setting enpacrx = 1 will enable automatic packet + -- handling in the RX path. Register 30-4D allow for various + -- configurations of the packet structure. Setting enpacrx = 0 will + -- not do any packet handling in the RX path. It will only receive + -- everything after the sync word and fill up the RX FIFO. + end record with Size => Register'Size; + -- Reset value = 10001101 + + for Data_Access_Control_Register use record + crc at 0 range 0 .. 1; + encrc at 0 range 2 .. 2; + enpactx at 0 range 3 .. 3; + skip2ph at 0 range 4 .. 4; + crcdonly at 0 range 5 .. 5; + lsbfrst at 0 range 6 .. 6; + enpacrx at 0 range 7 .. 7; + end record; + + type EZMAC_Status_Register is record + pksent : Bit; -- R + -- Packet Sent. + -- A pksent = 1 a packet has been sent by the radio. (Same bit as in + -- register 03, but reading it does not reset the IRQ) + + pktx : Bit; -- R + -- Packet Transmitting. + -- When pktx = 1 the radio is currently transmitting a packet. + + crcerror : Bit; -- R + -- CRC Error. + -- When crcerror = 1 a Cyclic Redundancy Check error has been detected. + -- (Same bit as in register 03, but reading it does not reset the IRQ) + + pkvalid : Bit; -- R + -- Valid Packet Received. + -- When a pkvalid = 1 a valid packet has been received by the receiver. + -- (Same bit as in register 03, but reading it does not reset the IRQ) + + pkrx : Bit; -- R + -- Packet Receiving. + -- When pkrx = 1 the radio is currently receiving a valid packet. + + pksrch : Bit; -- R + -- Packet Searching. + -- When pksrch = 1 the radio is searching for a valid packet. + + rxcrc1 : Bit; -- R + -- If high, it indicates the last CRC received is all ones. + -- May indicated Transmitter underflow in case of CRC error. + + Reserved : Bit; + end record with Size => Register'Size; + -- Reset value = 00000000 + + for EZMAC_Status_Register use record + pksent at 0 range 0 .. 0; + pktx at 0 range 1 .. 1; + crcerror at 0 range 2 .. 2; + pkvalid at 0 range 3 .. 3; + pkrx at 0 range 4 .. 4; + pksrch at 0 range 5 .. 5; + rxcrc1 at 0 range 6 .. 6; + Reserved at 0 range 7 .. 7; + end record; + + type Header_Control_1_Register is record + hdch : UInt4; -- R/W + -- Received Header Bytes to be Checked Against the Check Header Bytes. + -- One hot encoding. The receiver will use hdch[2:0] to know the + -- position of the Header Bytes. + -- 0000:No Received Header check + -- 0001:Received Header check for byte 0. + -- 0010:Received Header check for bytes 1. + -- 0011:Received header check for bytes 0 & 1. + -- 0100:... + bcen : UInt4; -- R/W + -- Broadcast Address (FFh) Check Enable. + -- If it is enabled together with Header Byte Check then the header + -- check is OK if the incoming header byte equals with the appropriate + -- check byte or FFh). One hot encoding. + -- 0000:No broadcast address enable. + -- 0001:Broadcast address enable for header byte 0. + -- 0010:Broadcast address enable for header byte 1. + -- 0011:Broadcast address enable for header bytes 0 & 1. + -- 0100:... + end record with Size => Register'Size; + -- Reset value = 00001100 + + for Header_Control_1_Register use record + hdch at 0 range 0 .. 3; + bcen at 0 range 4 .. 7; + end record; + + type Header_Control_2_Register is record + prealen : Bit; -- R/W + -- prealen[8] + -- MSB of Preamble Length. + -- See register Preamble Length. + + synclen : Synchronization_Word_Length; -- R/W + -- Synchronization Word Length. + -- The value in this register corresponds to the number of bytes used + -- in the Synchronization Word. The synchronization word bytes are + -- transmitted in descending order. + -- 00: Synchronization Word 3 + -- 01: Synchronization Word 3 and 2 + -- 10: Synchronization Word 3 and 2 and 1 + -- 11: Synchronization Word 3 and 2 and 1 and 0 + + fixpklen : Bit; -- R/W + -- Fix Transmit/Receive Packet Length. + -- When fixpklen = 1 the packet length (pklen[7:0]) is not included in + -- the transmit header. When fixpklen = 0 the packet length is included + -- in the transmit header. In receive mode, if this bit is set the + -- packet length is obtained from the pklen[7:0] field in Reg 3Eh; + -- otherwise the packet length is obtained from the received header + -- packet length byte. + + hdlen : Header_Length; -- R/W + -- Header Length. + -- Transmit/Receive Header Length. Length of header used if packet + -- handler is enabled for TX/RX (enpactx/rx). Headers are + -- transmitted/received in descending order. + -- 000: No TX/RX header + -- 001: Header 3 + -- 010: Header 3 and 2 + -- 011: Header 3 and 2 and 1 + -- 100: Header 3 and 2 and 1 and 0 + + skipsyn : Bit; -- R/W + -- Skipsyn. + -- Skip Sync Word search timeout. If high, the system will ignore the + -- search timeout period when failing to find Sync Word and will not + -- return to searching for Preamble. Setting this bit does not + -- eliminate the search for Sync Word. Proper detection of Sync Word + -- remains necessary in FIFO mode in order to determine the start of + -- the Payload field and to thus store the correct bytes in the RX FIFO. + end record with Size => Register'Size; + -- Reset value = 00100010 + + for Header_Control_2_Register use record + prealen at 0 range 0 .. 0; + synclen at 0 range 1 .. 2; + fixpklen at 0 range 3 .. 3; + hdlen at 0 range 4 .. 6; + skipsyn at 0 range 7 .. 7; + end record; + + subtype Preamble_Length_Register is UInt8; -- R/W + -- Preamble Length. + -- The value in the prealen[8:0] register corresponds to the number of + -- nibbles (4 bits) in the packet. For example prealen[8:0] = '000001000' + -- corresponds to a preamble length of 32 bits (8 x 4bits) or 4 bytes. + -- The maximum preamble length is prealen[8:0] = 111111111 which + -- corresponds to a 255 bytes Preamble. Writing 0 will have the same result + -- as if writing 1, which corresponds to one single nibble of preamble. + -- Reset value = 00001000 + + type Preamble_Detection_Control_1_Register is record + rssi_offset : UInt3; -- R/W + -- Value added as offset to RSSI calculation. Every increment in this + -- register results in an increment of +4 dB in the RSSI. + + preath : UInt5; -- R/W + -- Preamble Detection Threshold. The value in the preath[4:0] register + -- corresponds to the number of nibbles (4 bits) of preamble pattern + -- (i.e., 01010...) that must be received correctly, before a + -- PREAMBLE_VALID signal is issued. This threshold helps guard against + -- false preamble detection upon noise. + end record with Size => Register'Size; + -- Reset value = 00101010 + + for Preamble_Detection_Control_1_Register use record + rssi_offset at 0 range 0 .. 2; + preath at 0 range 3 .. 7; + end record; + + subtype Synchronization_Word_Register is UInt8; -- R/W + -- sync3[31:24] sync2[23:16] sync1[15:8] sync0[7:0] + -- Reset value = 00101101 11010100 00000000 00000000 + + subtype Transmit_Header_Register is UInt8; -- R/W + -- txhd3[31:24] txhd2[23:16] txhd1[15:8] txhd0[7:0] + -- Reset value = 00000000 + + subtype Packet_Length_Register is UInt8; -- R/W + -- Packet Length. + -- The value in the pklen[7:0] register corresponds directly to the number + -- of bytes in the Packet. For example pklen[7:0] = '00001000' corresponds + -- to a packet length of 8 bytes. The maximum packet length is + -- pklen[7:0] = '11111111', a 255 byte packet. Writing 0 is possible, in + -- this case we do not send any data in the packet. During RX, if + -- fixpklen = 1, this will specify also the Packet Length for RX mode. + -- Reset value = 00000000 + + subtype Check_Header_Register is UInt8; -- R/W + -- chhd3[31:24] chhd2[23:16] chhd1[15:8] chhd0[7:0] + -- Reset value = 00000000 + + subtype Header_Enable_Register is UInt8; -- R/W + -- hden3[31:24] hden2[23:16] hden1[15:8] hden0[7:0] + -- Reset value = 11111111 11111111 11111111 11111111 + + subtype Received_Header_Register is UInt8; -- R + -- rxhd3[31:24] rxhd2[23:16] rxhd1[15:8] rxhd0[7:0] + -- Reset value = 00000000 00000000 00000000 00000000 + + subtype Received_Packet_Length_Register is UInt8; -- R + -- Length Byte of the Received Packet during fixpklen = 0. + -- This register specifies the number of Data bytes in the last received + -- packet, and reflects the value of the packet length byte in the received + -- header. This is relevant ONLY if the fixpklen bit D3 of Reg 33h is + -- cleared. If the fixpklen bit is set, then the expected number of + -- received Data bytes must be programmed into the pklen[7:0] field in + -- Reg 3Eh. + -- Reset value = xxxxxxxx + + type ADC8_Control_Register is record + adc8 : UInt6; -- R/W + Reserved : UInt2; -- R/W + end record with Size => Register'Size; + -- Reset value = 00010000 + + for ADC8_Control_Register use record + adc8 at 0 range 0 .. 5; + Reserved at 0 range 6 .. 7; + end record; + + type Channel_Filter_Coefficient_Address_Register is record + Reserved : UInt4; -- R/W + invalid_preamble_threshold : UInt4; -- R/W + -- Invalid Preamble Threshold. + -- invalid_preamble_threshold[3:0}=This configures (in nibbles) for how + -- long we will search for preamble. If during this time the preamble + -- is not detected, we will send a signal (which can be configured as + -- interrupt) and restart looking for the preamble again. The interval + -- between each interrupt is given by the formula below. + end record with Size => Register'Size; + -- Reset value = 00000000 + + for Channel_Filter_Coefficient_Address_Register use record + Reserved at 0 range 0 .. 3; + invalid_preamble_threshold at 0 range 4 .. 7; + end record; + + for Internal_Chip_State use + (LP => 2#000#, + RDY => 2#001#, + TX => 2#010#, + Tune => 2#011#, + RX => 2#111#); + + type Crystal_Oscillator_Register is record + enbuf : Bit; -- R/W + -- Output Buffer Enable. + -- This bit is active only if the bufovr bit is set to 1. + + bufovr : Bit; -- R/W + -- Output Buffer Enable Override. + -- If set to 1 then the enbuf bit controls the output buffer. + -- 0: output buffer is controlled by the state machine. + -- 1: output buffer is controlled by the enbuf bit. + + enamp2x : Bit; -- R/W + -- 2 Times Higher Amplification Enable. + + enbias2x : Bit; -- R/W + -- 2 Times Higher Bias Current Enable. + + clkhyst : Bit; -- R/W + -- Clock Hysteresis Setting. + + pwst : Internal_Chip_State; -- R + -- Internal Power States of the Chip. + end record with Size => Register'Size; + -- Reset value = xxx00100 + + for Crystal_Oscillator_Register use record + enbuf at 0 range 0 .. 0; + bufovr at 0 range 1 .. 1; + enamp2x at 0 range 2 .. 2; + enbias2x at 0 range 3 .. 3; + clkhyst at 0 range 4 .. 4; + pwst at 0 range 5 .. 7; + end record; + + type AGC_Override_Register is record + pga : UInt4; -- R/W + -- PGA Gain Override Value. + -- 0000: 0 dB + -- 0001: 3 dB + -- 0010: 6 dB + -- ... + -- 1000: 24 dB max. + + lnagain : Bit; -- R/W + -- LNA Gain Select. + -- Inagain=LNA Gain select. + -- 0 - min. gain = 5 dB + -- 1 - max. gain = 25 dB + + agcen : Bit; -- R/W + -- Automatic Gain Control Enable. + -- agcen=Automatic Gain Control enable. When this bit is set then the + -- result of the control can be read out from bits [4:0], otherwise + -- the gain can be controlled manually by writing into bits [4:0]. + + sgin : Bit; -- R/W + -- sgin=AGC stop increasing gain override bit (active low). When '0' + -- (default), AGC gain increases during signal reductions are prevented. + -- When '1', AGC gain increases during signal reductions are allowed. + -- Only effective during Preamble, prior to detection of PREAMBLE_VALID + -- signal. + + Reserved : Bit; -- R + end record with Size => Register'Size; + -- Reset value = 00100000 + + for AGC_Override_Register use record + pga at 0 range 0 .. 3; + lnagain at 0 range 4 .. 4; + agcen at 0 range 5 .. 5; + sgin at 0 range 6 .. 6; + Reserved at 0 range 7 .. 7; + end record; + + type TX_Power_Register is record + txpow : UInt3; -- R/W + -- TX Output Power. + -- The output power is configurable from +13 dBm to -8 dBm (Si4430/31), + -- and from +20 dBM to -1 dBM (Si4432) in -3 dB steps. txpow[2:0]=000 + -- corresponds to min output power, while txpow[2:0]=111 corresponds + -- to max output power. + + lna_sw : Bit; -- R/W + -- LNA Switch Controller. + -- This bit determines when internal MOS switches at the LNA input(s) + -- are invoked. When lna_sw=0, these switches open. When lna_sw=1, + -- these switches are closed in TX mode and open at all other times. + -- This bit MUST be set for proper operation in any Direct Tie + -- application. + + Reserved : UInt4; -- R + end record with Size => Register'Size; + -- Reset value = 00100000 + + for TX_Power_Register use record + txpow at 0 range 0 .. 2; + lna_sw at 0 range 3 .. 3; + Reserved at 0 range 4 .. 7; + end record; + + subtype TX_Data_Rate_Register is UInt8; -- R/W + -- txdr1[15:8] txdr0[7:0] + -- Reset value = 00001010 00111101 + -- Defaults = 40 kbps. + + type Modulation_Mode_Control_1_Register is record + enwhite : Bit; -- R/W + -- Data Whitening is Enabled if this bit is set. + + enmanch : Bit; -- R/W + -- Manchester Coding is Enabled if this bit is set. + -- What Manchester coding does is to replace a single high bit (1) with + -- two bits starting with low followed by high (01) and a low bit (0) + -- with a high bit followed by a low bit (10). When Manchester is + -- enabled, please configure as well the enmaninv at 70h bit [2] since + -- it influences the Manchester encoding/decoding process. + + enmaninv : Bit; -- R/W + -- Manchester Data Inversion is Enabled if this bit is set. + -- When this bit is low, a 10 pair is considered a Manchester 0, and + -- a 01 pair as a Manchester 1. By setting this bit, do the opposite: + -- every 10 will be considered as a 1, and every 01 will be considered + -- as a 0. This function is relevant only if the Manchester mode is + -- enabled. + + manppol : Bit; -- R/W + -- Manchester Preamble Polarity (will transmit a series of 1 if set, + -- or series of 0 if reset). + -- This bit affects only the transmitter side, not the receiver. This + -- is valid only if Manchester Mode is enabled. + + enphpwdn : Bit; -- R/W + -- If set, the Packet Handler will be powered down when chip is in + -- low power mode. + + txdtrtscale : Bit; -- R/W + -- This bit should be set for Data Rates below 30 kbps. + + Reserved : UInt2; -- R + end record with Size => Register'Size; + -- Reset value = 00001100 + + for Modulation_Mode_Control_1_Register use record + enwhite at 0 range 0 .. 0; + enmanch at 0 range 1 .. 1; + enmaninv at 0 range 2 .. 2; + manppol at 0 range 3 .. 3; + enphpwdn at 0 range 4 .. 4; + txdtrtscale at 0 range 5 .. 5; + Reserved at 0 range 6 .. 7; + end record; + + for Modulation_Mode use + (Unmodulated_Carrier => 2#00#, + OOK => 2#01#, + FSK => 2#10#, + GFSK => 2#11#); + + for Modulation_Source use + (Direct_GPIO => 2#00#, + Direct_SDI => 2#01#, + FIFO => 2#10#, + PN9 => 2#11#); + + for Modulation_TX_Data_Clock use + (No_CLK => 2#00#, + CLK_GPIO => 2#01#, + CLK_SDO => 2#10#, + CLK_nIRQ => 2#11#); + + type Modulation_Mode_Control_2_Register is record + modtyp : Modulation_Mode; -- R/W + -- Modulation Type. + + fd : Bit; -- R/W + -- fd[8] + -- MSB of Frequency Deviation Setting, see + -- "Register 72h. Frequency Deviation". + + eninv : Bit; -- R/W + -- Invert TX and RX Data. + + dtmod : Modulation_Source; -- R/W + -- Modulation Source. + + trclk : Modulation_TX_Data_Clock; -- R/W + -- TX Data Clock Configuration. + end record with Size => Register'Size; + -- Reset value = 00000000 + + for Modulation_Mode_Control_2_Register use record + modtyp at 0 range 0 .. 1; + fd at 0 range 2 .. 2; + eninv at 0 range 3 .. 3; + dtmod at 0 range 4 .. 5; + trclk at 0 range 6 .. 7; + end record; + + subtype Frequency_Deviation_Register is UInt8; -- R/W + -- fd[7:0] + -- Reset value = 00100000 + + subtype Frequency_Offset_1_Register is UInt8; -- R/W + -- fo[7:0] + -- Frequency Offset Setting. + -- The frequency offset can be calculated as Offset = 156.25 Hz x + -- (hbsel + 1) x fo[7:0]. + -- fo[9:0] is a twos complement value. + -- Reset value = 00000000 + + type Frequency_Offset_2_Register is record + fo : UInt2; -- R/W + -- fo[9:8] + -- Upper Bits of the Frequency Offset Setting. + -- fo[9] is the sign bit. The frequency offset can be calculated as + -- Offset = 156.25 Hz x (hbsel + 1) x fo[7:0]. fo[9:0] is a twos + -- complement value. + + Reserved : UInt6; -- R + end record with Size => Register'Size; + -- Reset value = 00000000 + + for Frequency_Offset_2_Register use record + fo at 0 range 0 .. 1; + Reserved at 0 range 2 .. 7; + end record; + + type Frequency_Band_Select_Register is record + fb : UInt5; -- R/W + -- Frequency Band Select. + -- Every increment corresponds to a 10 MHz increase in frequency + -- (when hbsel=0) or a 20 MHz increase in frequency (when hbsel=1). + -- Example: Setting fb[4:0]=00000 will result inn tuning within the + -- 240-250 MHz frequency range (for hbsel=0) or within the 480-500 MHz + -- frequency range (for hbsel=1). Setting fb[4:0]=00001 will result in + -- tuning within the 250-260 MHz frequency range (hbsel=0) or + -- 500-520 MHz range (hbsel=1), and so on. + + hbsel : Bit; + -- High Band Select. + -- Setting hbsel = 1 will choose the frequency range from 480-960 MHz + -- (high bands). Setting hbsel = 0 will choose the frequency range + -- from 240-479.9 MHz (low bands). + + sbsel : Bit; + -- Side Band Select. + -- Setting sbsel = 1 (recommended setting) will result in tuning the + -- RX LO below the desired channel frequency in RX mode + -- (low-side injection) such that the high-side sideband is selected. + -- Note that setting sbsel = 0 will result in positioning the RX LO + -- above the desired tuned frequency (high-side injection), but will + -- NOT additionally flip the processing of the complex (I + jQ) signals + -- in the IF chain necessary to select the lower sideband as the + -- desired signal. + + Reserved : Bit; -- R + end record with Size => Register'Size; + -- Reset value = 01110101 + + for Frequency_Band_Select_Register use record + fb at 0 range 0 .. 4; + hbsel at 0 range 5 .. 5; + sbsel at 0 range 6 .. 6; + Reserved at 0 range 7 .. 7; + end record; + + subtype Nominal_Carrier_Frequency_Register is UInt8; -- R/W + -- fc1[15:8] fc0[7:0] + -- Reset value = 10111011 10000000 + + subtype Frequency_Hopping_Channel_Select_Register is UInt8; -- R/W + -- Reset value = 00000000 + + subtype Frequency_Hopping_Step_Size_Register is UInt8; -- R/W + -- Frequency Hopping Step Size in 10 kHz Increments. + -- See formula for the nominal carrier frequency at "Register 76h. Nominal + -- Carrier Frequency". Important: The EZHop method of frequency programming + -- only works while remaining entirely within one of the following defined + -- frequency sub-bands: 240-320 MHz, 320-480 MHz, 480-640 MHz, and + -- 640-960 MHz. It is not allowed to define a base frequency that falls + -- in one sub-band while the selected channel number falls in another + -- sub-band. + -- Reset value = 00000000 + + type TX_FIFO_Control_1_Register is record + txafthr : UInt6; -- R/W + -- TX FIFO Almost Full Threshold. + -- This register specifies the threshold value at which the TXFFAFULL + -- status bit/interrupt will be generated, as data bytes are stored + -- into the TX FIFO for later transmission. This value should be + -- programmed to 1 byte less than the desired threshold value. + -- Example: A value of 0x3C=60d will not generate an interrupt if 60 + -- bytes (or less) are written to the TX FIFO, but will generate an + -- interrupt when 61 bytes (or more) are written to the TX FIFO. + + Reserved : UInt2; -- R + end record with Size => Register'Size; + -- Reset value = 00110111 + + for TX_FIFO_Control_1_Register use record + txafthr at 0 range 0 .. 5; + Reserved at 0 range 6 .. 7; + end record; + + type TX_FIFO_Control_2_Register is record + txfaethr : UInt6; -- R/W + -- TX FIFO Almost Empty Threshold. + -- This register specifies the threshold value at which the TXFFAEM + -- status bit/interrupt will be generated, as data bytes are pulled + -- from the TX FIFO and transmitted. This value should be programmed + -- to 1 byte less than the desired threshold value. Example: A value + -- of 0x05 will generate an interrupt when 6 bytes remain in the + -- TX FIFO. + + Reserved : UInt2; -- R + end record with Size => Register'Size; + -- Reset value = 00000100 + + for TX_FIFO_Control_2_Register use record + txfaethr at 0 range 0 .. 5; + Reserved at 0 range 6 .. 7; + end record; + + type RX_FIFO_Control_Register is record + rxafthr : UInt6; -- R/W + -- RX FIFO Almost Full Threshold. + -- This register specifies the threshold value at which the RXFFAFULL + -- status bit/interrupt will be generated, as data bytes are received + -- and stored into the RX FIFO for later retrieval. This value should + -- be programmed to 1 byte less than the desired threshold value. + -- Example: A value of 0x3C=60d will not generate an interrupt if 60 + -- bytes (or less) are received and stored to the RX FIFO, but will + -- generate an interrupt when 61 bytes (or more) are received and + -- stored to the RX FIFO. + + Reserved : UInt2; -- R + end record with Size => Register'Size; + -- Reset value = 00110111 + + for RX_FIFO_Control_Register use record + rxafthr at 0 range 0 .. 5; + Reserved at 0 range 6 .. 7; + end record; + + subtype FIFO_Access_Register is UInt8; -- R/W + -- FIFO Data. + -- A Write (R/W = 1) to this Address will begin a Burst Write to the TX + -- FIFO. The FIFO will be loaded in the same manner as a Burst SPI Write + -- but the SPI address will not be incremented. To conclude the TX FIFO + -- Write the SEL pin should be brought HIGH. A Read (R/W = 0) to this + -- address will begin a burst read of the RX FIFO, in the same manner. + -- Reset value = NA + + -- Register_Name -- + + type Register_Name is + (Device_Type_Code_Name, + Version_Code_Name, + Device_Status_Name, + Interrupt_Status_1_Name, + Interrupt_Status_2_Name, + Interrupt_Enable_1_Name, + Interrupt_Enable_2_Name, + Operating_Mode_And_Function_Control_1_Name, + Operating_Mode_And_Function_Control_2_Name, + Crystal_Oscillator_Load_Capacitance_Name, + Microcontroller_Output_Clock_Name, + GPIO0_Configuration_Name, + GPIO1_Configuration_Name, + GPIO2_Configuration_Name, + IO_Port_Configuration_Name, + ADC_Configuration_Name, + ADC_Sensor_Amplifier_Offset_Name, + ADC_Value_Name, + Temperature_Sensor_Calibration_Name, + Temperature_Value_Offset_Name, + Wake_Up_Timer_Period_1_Name, + Wake_Up_Timer_Period_2_Name, + Wake_Up_Timer_Period_3_Name, + Wake_Up_Timer_Value_1_Name, + Wake_Up_Timer_Value_2_Name, + Low_Duty_Cycle_Mode_Duration_Name, + Low_Battery_Detector_Threshold_Name, + Battery_Voltage_Level_Name, + IF_Filter_Bandwidth_Name, + AFC_Loop_Gearshift_Override_Name, + AFC_Timing_Control_Name, + Clock_Recovery_Gearshift_Override_Name, + Clock_Recovery_Oversampling_Rate_Name, + Clock_Recovery_Offset_2_Name, + Clock_Recovery_Offset_1_Name, + Clock_Recovery_Offset_0_Name, + Clock_Recovery_Timing_Loop_Gain_1_Name, + Clock_Recovery_Timing_Loop_Gain_0_Name, + Received_Signal_Strength_Indicator_Name, + RSSI_Threshold_For_Clear_Channel_Indicator_Name, + Antenna_Diversity_1_Name, + Antenna_Diversity_2_Name, + AFC_Limiter_Name, + AFC_Correction_Name, + OOK_Counter_Value_1_Name, + OOK_Counter_Value_2_Name, + Slicer_Peak_Holder_Name, + Data_Access_Control_Name, + EZMAC_Status_Name, + Header_Control_1_Name, + Header_Control_2_Name, + Preamble_Length_Name, + Preamble_Detection_Control_1_Name, + Synchronization_Word_3_Name, + Synchronization_Word_2_Name, + Synchronization_Word_1_Name, + Synchronization_Word_0_Name, + Transmit_Header_3_Name, + Transmit_Header_2_Name, + Transmit_Header_1_Name, + Transmit_Header_0_Name, + Packet_Length_Name, + Check_Header_3_Name, + Check_Header_2_Name, + Check_Header_1_Name, + Check_Header_0_Name, + Header_Enable_3_Name, + Header_Enable_2_Name, + Header_Enable_1_Name, + Header_Enable_0_Name, + Received_Header_3_Name, + Received_Header_2_Name, + Received_Header_1_Name, + Received_Header_0_Name, + Received_Packet_Length_Name, + ADC8_Control_Name, + Channel_Filter_Coefficient_Address_Name, + Crystal_Oscillator_Name, + AGC_Override_Name, + TX_Power_Name, + TX_Data_Rate_1_Name, + TX_Data_Rate_0_Name, + Modulation_Mode_Control_1_Name, + Modulation_Mode_Control_2_Name, + Frequency_Deviation_Name, + Frequency_Offset_1_Name, + Frequency_Offset_2_Name, + Frequency_Band_Select_Name, + Nominal_Carrier_Frequency_1_Name, + Nominal_Carrier_Frequency_0_Name, + Frequency_Hopping_Channel_Select_Name, + Frequency_Hopping_Step_Size_Name, + TX_FIFO_Control_1_Name, + TX_FIFO_Control_2_Name, + RX_FIFO_Control_Name, + FIFO_Access_Name + ); + + Registers_Addressses : constant array (Register_Name) of + Register_Address := + [Device_Type_Code_Name => 16#00#, + Version_Code_Name => 16#01#, + Device_Status_Name => 16#02#, + Interrupt_Status_1_Name => 16#03#, + Interrupt_Status_2_Name => 16#04#, + Interrupt_Enable_1_Name => 16#05#, + Interrupt_Enable_2_Name => 16#06#, + Operating_Mode_And_Function_Control_1_Name => 16#07#, + Operating_Mode_And_Function_Control_2_Name => 16#08#, + Crystal_Oscillator_Load_Capacitance_Name => 16#09#, + Microcontroller_Output_Clock_Name => 16#0A#, + GPIO0_Configuration_Name => 16#0B#, + GPIO1_Configuration_Name => 16#0C#, + GPIO2_Configuration_Name => 16#0D#, + IO_Port_Configuration_Name => 16#0E#, + ADC_Configuration_Name => 16#0F#, + ADC_Sensor_Amplifier_Offset_Name => 16#10#, + ADC_Value_Name => 16#11#, + Temperature_Sensor_Calibration_Name => 16#12#, + Temperature_Value_Offset_Name => 16#13#, + Wake_Up_Timer_Period_1_Name => 16#14#, + Wake_Up_Timer_Period_2_Name => 16#15#, + Wake_Up_Timer_Period_3_Name => 16#16#, + Wake_Up_Timer_Value_1_Name => 16#17#, + Wake_Up_Timer_Value_2_Name => 16#18#, + Low_Duty_Cycle_Mode_Duration_Name => 16#19#, + Low_Battery_Detector_Threshold_Name => 16#1A#, + Battery_Voltage_Level_Name => 16#1B#, + IF_Filter_Bandwidth_Name => 16#1C#, + AFC_Loop_Gearshift_Override_Name => 16#1D#, + AFC_Timing_Control_Name => 16#1E#, + Clock_Recovery_Gearshift_Override_Name => 16#1F#, + Clock_Recovery_Oversampling_Rate_Name => 16#20#, + Clock_Recovery_Offset_2_Name => 16#21#, + Clock_Recovery_Offset_1_Name => 16#22#, + Clock_Recovery_Offset_0_Name => 16#23#, + Clock_Recovery_Timing_Loop_Gain_1_Name => 16#24#, + Clock_Recovery_Timing_Loop_Gain_0_Name => 16#25#, + Received_Signal_Strength_Indicator_Name => 16#26#, + RSSI_Threshold_For_Clear_Channel_Indicator_Name => 16#27#, + Antenna_Diversity_1_Name => 16#28#, + Antenna_Diversity_2_Name => 16#29#, + AFC_Limiter_Name => 16#2A#, + AFC_Correction_Name => 16#2B#, + OOK_Counter_Value_1_Name => 16#2C#, + OOK_Counter_Value_2_Name => 16#2D#, + Slicer_Peak_Holder_Name => 16#2E#, + Data_Access_Control_Name => 16#30#, + EZMAC_Status_Name => 16#31#, + Header_Control_1_Name => 16#32#, + Header_Control_2_Name => 16#33#, + Preamble_Length_Name => 16#34#, + Preamble_Detection_Control_1_Name => 16#35#, + Synchronization_Word_3_Name => 16#36#, + Synchronization_Word_2_Name => 16#37#, + Synchronization_Word_1_Name => 16#38#, + Synchronization_Word_0_Name => 16#39#, + Transmit_Header_3_Name => 16#3A#, + Transmit_Header_2_Name => 16#3B#, + Transmit_Header_1_Name => 16#3C#, + Transmit_Header_0_Name => 16#3D#, + Packet_Length_Name => 16#3E#, + Check_Header_3_Name => 16#3F#, + Check_Header_2_Name => 16#40#, + Check_Header_1_Name => 16#41#, + Check_Header_0_Name => 16#42#, + Header_Enable_3_Name => 16#43#, + Header_Enable_2_Name => 16#44#, + Header_Enable_1_Name => 16#45#, + Header_Enable_0_Name => 16#46#, + Received_Header_3_Name => 16#47#, + Received_Header_2_Name => 16#48#, + Received_Header_1_Name => 16#49#, + Received_Header_0_Name => 16#4A#, + Received_Packet_Length_Name => 16#4B#, + ADC8_Control_Name => 16#4F#, + Channel_Filter_Coefficient_Address_Name => 16#60#, + Crystal_Oscillator_Name => 16#62#, + AGC_Override_Name => 16#69#, + TX_Power_Name => 16#6D#, + TX_Data_Rate_1_Name => 16#6E#, + TX_Data_Rate_0_Name => 16#6F#, + Modulation_Mode_Control_1_Name => 16#70#, + Modulation_Mode_Control_2_Name => 16#71#, + Frequency_Deviation_Name => 16#72#, + Frequency_Offset_1_Name => 16#73#, + Frequency_Offset_2_Name => 16#74#, + Frequency_Band_Select_Name => 16#75#, + Nominal_Carrier_Frequency_1_Name => 16#76#, + Nominal_Carrier_Frequency_0_Name => 16#77#, + Frequency_Hopping_Channel_Select_Name => 16#79#, + Frequency_Hopping_Step_Size_Name => 16#7A#, + TX_FIFO_Control_1_Name => 16#7C#, + TX_FIFO_Control_2_Name => 16#7D#, + RX_FIFO_Control_Name => 16#7E#, + FIFO_Access_Name => 16#7F# + ]; + + -------------- + -- Commands -- + -------------- + + type Command is new UInt8; + -- Base type for all commands + + type Command_Register is record + Address : Register_Address; + Operation : Operation_Type; + end record with Size => Command'Size; + -- Read registers command + + for Command_Register use record + Address at 0 range 0 .. 6; + Operation at 0 range 7 .. 7; + end record; + + ---------------------- + -- NRF24L01P_Driver -- + ---------------------- + + type Holder_Type_Kind is (Hardware, Software); + + type Holder_Type + (Kind : Holder_Type_Kind := Software) is + record + SPI : HAL.SPI.Any_SPI_Port; + SDN_Pin : HAL.GPIO.Any_GPIO_Point; + + case Kind is + when Hardware => + null; + when Software => + CSN_Pin : HAL.GPIO.Any_GPIO_Point; + -- Used for "selecting" chip vis SPI + end case; + end record; + + type Si4432_Driver is limited record + Holder : Holder_Type; + end record; + + function Read_Register + (This : Si4432_Driver; + Name : Register_Name) + return Register; + + procedure Read_Register + (This : Si4432_Driver; + Name : Register_Name; + Data : out HAL.SPI.SPI_Data_8b); + + procedure Write_Register + (This : Si4432_Driver; + Name : Register_Name; + Data : Register); + + procedure Write_Register + (This : Si4432_Driver; + Name : Register_Name; + Data : HAL.SPI.SPI_Data_8b); + + procedure Write + (This : Si4432_Driver; + Data : HAL.SPI.SPI_Data_8b); + + procedure Write_And_Read + (This : Si4432_Driver; + Command : HAL.SPI.SPI_Data_8b; + Data : out HAL.SPI.SPI_Data_8b); + + procedure CSN_High (This : Si4432_Driver); + procedure CSN_Low (This : Si4432_Driver); + -- High/Low CSN pin in SOFTWARE slave selection mode. + + Null_Interrupt_Status_1_Register : constant Interrupt_Status_1_Register := + (others => 0); + Null_Interrupt_Status_2_Register : constant Interrupt_Status_2_Register := + (others => 0); + +end Si4432; diff --git a/examples/STM32F429_Discovery/si4432_f429disco.gpr b/examples/STM32F429_Discovery/si4432_f429disco.gpr new file mode 100644 index 000000000..fd698aa59 --- /dev/null +++ b/examples/STM32F429_Discovery/si4432_f429disco.gpr @@ -0,0 +1,15 @@ +with "../../boards/stm32f429_discovery/stm32f429_discovery_full.gpr"; + +project Si4432_F429Disco extends "../shared/common/common.gpr" is + + for Runtime ("Ada") use STM32F429_Discovery_Full'Runtime("Ada"); + for Target use "arm-eabi"; + for Main use ("si4432_example.adb"); + for Languages use ("Ada"); + for Source_Dirs use ("../shared/si4432/src"); + for Object_Dir use "../shared/si4432/obj/stm32f429disco"; + for Create_Missing_Dirs use "True"; + + package Compiler renames STM32F429_Discovery_Full.Compiler; + +end Si4432_F429Disco; diff --git a/examples/shared/si4432/.gdbinit b/examples/shared/si4432/.gdbinit new file mode 100644 index 000000000..618b9ce81 --- /dev/null +++ b/examples/shared/si4432/.gdbinit @@ -0,0 +1,24 @@ +# This command file will cause a Cortex-M3 or -M4 board to automatically +# reset immediately after a GDB "load" command executes. Note that GPS +# issues that command as part of the Debug->Init menu invocation. Manual +# "load" command invocations will also trigger the action. +# +# The reset is achieved by writing to the "Application Interrupt and Reset +# Control" register located at address 0xE000ED0C. +# +# Both the processor and the peripherals can be reset by writing a value +# of 0x05FA0004. That value will write to the SYSRESETREQ bit. If you want +# to avoid resetting the peripherals, change the value to 0x05FA0001. That +# value will write to the VECTRESET bit. Do *not* use a value that sets both +# bits. +# +# In both cases, any on-board debug hardware is not reset. +# +# See the book "The Definitive Guide to the ARM Cortex-M3 and Cortex-M4 +# Processors" by Joseph Yiu, 3rd edition, pp 262-263 for further details. + +define hookpost-load +echo Resetting the processor and peripherals...\n +set *0xE000ED0C := 0x05FA0004 +echo Reset complete\n +end \ No newline at end of file diff --git a/examples/shared/si4432/README.md b/examples/shared/si4432/README.md new file mode 100644 index 000000000..64e1ecc71 --- /dev/null +++ b/examples/shared/si4432/README.md @@ -0,0 +1,23 @@ +This is a simple test/example for Si4432B1 with +STM32F429Disco. Two Si4432B1 should be connected +to the following board's pins: + +| TX: | | +|------|-----| +| SDN | PB7 | +| CSN | PE3 | +| IRQ | PC3 | +| SCK | PE2 | +| MISO | PE5 | +| MOSI | PE6 | + +| RX: | | +|------|------| +| SDN | PC11 | +| CSN | PC12 | +| IRQ | PB4 | +| SCK | PE2 | +| MISO | PE5 | +| MOSI | PE6 | + +to communicate with each other. diff --git a/examples/shared/si4432/src/si4432_example.adb b/examples/shared/si4432/src/si4432_example.adb new file mode 100644 index 000000000..7e61cbe79 --- /dev/null +++ b/examples/shared/si4432/src/si4432_example.adb @@ -0,0 +1,650 @@ +------------------------------------------------------------------------------ +-- -- +-- Copyright (C) 2025, AdaCore -- +-- -- +-- Redistribution and use in source and binary forms, with or without -- +-- modification, are permitted provided that the following conditions are -- +-- met: -- +-- 1. Redistributions of source code must retain the above copyright -- +-- notice, this list of conditions and the following disclaimer. -- +-- 2. Redistributions in binary form must reproduce the above copyright -- +-- notice, this list of conditions and the following disclaimer in -- +-- the documentation and/or other materials provided with the -- +-- distribution. -- +-- 3. Neither the name of the copyright holder nor the names of its -- +-- contributors may be used to endorse or promote products derived -- +-- from this software without specific prior written permission. -- +-- -- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -- +-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -- +-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -- +-- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -- +-- HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -- +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -- +-- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -- +-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -- +-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -- +-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -- +-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- +-- -- +------------------------------------------------------------------------------ + +-- Simple test/example for STM32F429disco with two Si4432B1 attached + +with Ada.Exceptions; +with Last_Chance_Handler; pragma Unreferenced (Last_Chance_Handler); +-- The "last chance handler" is the user-defined routine that is called when +-- an exception is propagated. We need it in the executable, therefore it +-- must be somewhere in the closure of the context clauses. + +with HAL.SPI; +with STM32.Board; use STM32.Board; +with STM32.Device; +with STM32.GPIO; use STM32.GPIO; +with STM32.SPI; use STM32.SPI; +with STM32.EXTI; + +with Si4432; use Si4432; +with Watchdogs; use Watchdogs; + +-- Service +with Ada.Real_Time; use Ada.Real_Time; +with HAL.Bitmap; use HAL.Bitmap; +with BMP_Fonts; +with LCD_Std_Out; + +-- TX: +-- SDN PB7 +-- CSN PE3 +-- IRQ PC3 +-- SPI4 Pins: +-- PE2 SPI4_SCK +-- PE5 SPI4_MISO +-- PE6 SPI4_MOSI + +-- RX: +-- SDN PC11 +-- CSN PC12 +-- IRQ PB4 +-- SPI4 Pins: +-- PE2 SPI4_SCK +-- PE5 SPI4_MISO +-- PE6 SPI4_MOSI + +procedure Si4432_Example is + + use type HAL.UInt8; + + SPI4_Pins : constant GPIO_Points := + (STM32.Device.PE2, STM32.Device.PE5, STM32.Device.PE6); + SPI : SPI_Port renames STM32.Device.SPI_4; + + procedure Init_Pins; -- Initialize pins + procedure Init_SPI; -- Initialize SPI + + procedure Configure_RX; -- Configure RX side + procedure Configure_TX; -- Configure TX side + + procedure Configure (Driver : Si4432_Driver); + -- Apply common RX/TX settings + + procedure On_RX_IRQ; -- RX IRQ handler + procedure On_TX_IRQ; -- TX IRQ handler + + -- Wait for the specified RX/TX statuses + procedure Wait_For_RX (Status1, Status2 : HAL.UInt8); + procedure Wait_For_TX (Status1, Status2 : HAL.UInt8); + + procedure Ckeck_RX_Data (Value : String); -- Check that we got proper data + procedure On_Error (Msg : String); -- Prints error message + + ------------------ + -- Configure_RX -- + ------------------ + + -- RX -- + RX_SDN : GPIO_Point renames STM32.Device.PC11; + RX_CSN : GPIO_Point renames STM32.Device.PC12; + RX : Si4432_Driver; + + Has_RX_IRQ : Boolean := False with Volatile, Atomic; + RX_Status : Interrupt_Statuses := (others => 0) with Volatile, Atomic; + + procedure Configure_RX is + begin + -- Initialize RX -- + Initialize + (This => RX, + CSN_Pin => RX_CSN'Access, + SDN_Pin => RX_SDN'Access, + SPI => SPI'Access); + delay 0.1; + + -- Reset + Set_Power (RX, On); + delay 0.2; + Clear_Interrupts (RX); + Has_RX_IRQ := False; + Software_Reset (RX); + Wait_For_RX (0, Status_Chip_Ready); + + Set_Interrupt_Enable + (RX, + CRC_Error => True, + Valid_Packet_Received => True, + RX_FIFO_Almost_Full => False, + Valid_Preamble => False, + Sync_Word => False, + RSSI => False, + POR => False, + Chip_Ready => False); + + LCD_Std_Out.Put_Line ("RX code:" & Device_Type_Code (RX)'Img); + LCD_Std_Out.Put_Line ("RX version:" & Version_Code (RX)'Img); + + Configure (RX); + + Set_Modulation_Mode_Control_1 + (RX, + Data_Whitening => False, + Manchester_Coding => False, + Manchester_Data_Inversion => False, + Manchester_Preamble_Polarity => False, + Packet_Handler_Down => False, + Data_Rates_Below => False); + + -- Set the modem parameters according to the exel calculator + -- (parameters: 9.6 kbps, deviation: 45 kHz, channel filter + -- BW: 102.2 kHz) + Set_IF_Filter_Bandwidth + (RX, + Coefficient => 16#E#, + Decimation_Rates => 1, + Bypass_Decimate => False); + + Set_Clock_Recovery_Oversampling_Rate (RX, 16#D0#); + + Set_Clock_Recovery_Offset + (RX, + NCO_Offset => 16#9D49#, + Skip_2nd_Phase => False); + + Set_Clock_Recovery_Timing_Loop_Gain + (RX, + Gain => 16#24#, + Multiplying_By_2 => False, + Compensation_Enable => False); + + Set_AFC_Loop_Gearshift_Override + (RX, + Reset_Preamble => False, + Taps => False, + Bypass => False, + AFC_High_Gear => 0, + AFC => True, + AFC_Wideband => False); + + -- Si443x revision B1, there are dedicated registers for setting the + -- AFC Limit. It makes the radio easier to use; there is no need to + -- change the Frequency Deviation register + Set_AFC_Limiter (RX, 16#20#); + + Set_Data_Access_Control + (RX, + CRC_Selection => CRC_16, + CRC_Enable => True, + Enable_Packet_TX_Handling => False, + Skip_2nd_Phase_Preamble_Detection => False, + CRC_Data_Only_Enable => False, + LSB_First_Enable => False, + Enable_Packet_RX_Handling => True); + + Set_Preamble_Detection_Control + (RX, + RSSI_Offset => 0, + Detection_Threshold => 5); + + Set_AGC_Override + (RX, + Gain_Override => 0, + LNA_Gain_Select => False, + Automatic_Gain_Control => True, + Sgin => True); + end Configure_RX; + + ------------------ + -- Configure_TX -- + ------------------ + + -- TX -- + TX_SDN : GPIO_Point renames STM32.Device.PB7; + TX_CSN : GPIO_Point renames STM32.Device.PE3; + TX : Si4432_Driver; + + Has_TX_IRQ : Boolean := False with Volatile, Atomic; + TX_Status : Interrupt_Statuses := (others => 0) with Volatile, Atomic; + + procedure Configure_TX is + begin + -- Initialize TX -- + Initialize + (This => TX, + CSN_Pin => TX_CSN'Access, + SDN_Pin => TX_SDN'Access, + SPI => SPI'Access); + delay 0.1; + + -- Reset + Set_Power (TX, On); + delay 0.2; + Clear_Interrupts (TX); + Has_TX_IRQ := False; + Software_Reset (TX); + Wait_For_TX (0, Status_Chip_Ready); + + Set_Interrupt_Enable + (TX, + Packet_Sent => True, + TX_FIFO_Almost_Full => True, + POR => False, + Chip_Ready => False); + + LCD_Std_Out.Put_Line ("TX code:" & Device_Type_Code (TX)'Img); + LCD_Std_Out.Put_Line ("TX version:" & Version_Code (TX)'Img); + + Configure (TX); + + Set_Frequency_Deviation_Hz (TX, 45_000); -- +/- 45 kHz + + Set_Data_Access_Control + (TX, + CRC_Selection => CRC_16, + CRC_Enable => True, + Enable_Packet_TX_Handling => True, + Skip_2nd_Phase_Preamble_Detection => False, + CRC_Data_Only_Enable => False, + LSB_First_Enable => False, + Enable_Packet_RX_Handling => False); + + -- 9.6kbps + Set_TX_Data_Rate (TX, 16#4EA5#); + Set_Modulation_Mode_Control_1 + (TX, + Data_Whitening => False, + Manchester_Coding => False, + Manchester_Data_Inversion => True, + Manchester_Preamble_Polarity => True, + Packet_Handler_Down => False, + Data_Rates_Below => True); + + Set_Preamble_Length (TX, 9); + + Set_TX_Power + (TX, + Output_Power => 0, -- min output power + LNA_Switch => True); + end Configure_TX; + + --------------- + -- Configure -- + --------------- + + procedure Configure (Driver : Si4432_Driver) is + begin + -- Frequency -- + Set_Frequency (Driver, 915.0); -- 915 MHz + Set_Nominal_Carrier_Frequency (Driver, 16#BB80#); + + Set_Header_Control + (Driver, + Header_Bytes_Check => 0, -- No heareds + Broadcast_Address_Check => 0, -- No broadcasts + Synchronization => Word_3_2, + Fix_TR_Packet_Length => False, -- variable packet length + Header => No_Header, + Skipsyn => False); + + -- Synch Word + Set_Synchronization_Word (Driver, 3, 16#DD#); + Set_Synchronization_Word (Driver, 2, 16#4D#); + + -- Modulation + Set_Modulation_Mode_Control_2 + (Driver, + Modulation => GFSK, + Invert_TX_RX => False, + Source => FIFO, + TX_Data_Clock => CLK_GPIO); + + -- GPIO + Set_GPIO1_Configuration + (Driver, + Pin_Function => TX_State, + Pullup_Resistor_Enable => False, + Driving_Capability => 0); + + Set_GPIO2_Configuration + (Driver, + Pin_Function => RX_State, + Pullup_Resistor_Enable => False, + Driving_Capability => 0); + + Set_Crystal_Oscillator_Load_Capacitance + (Driver, + Tuning_Capacitance => 16#57#, + Shft => 1); + end Configure; + + --------------- + -- Init_Pins -- + --------------- + + procedure Init_Pins is + -- Initialize pins + begin + + -- TX -- + STM32.Device.Enable_Clock (GPIO_Points'(TX_SDN, TX_CSN, TX_IRQ)); + + Configure_IO + (Points => (TX_SDN, TX_CSN), + Config => + (Mode => Mode_Out, + Resistors => Floating, + Output_Type => Push_Pull, + Speed => Speed_Low)); + + TX_SDN.Set; + TX_CSN.Set; + + -- RX IRQ pin + TX_IRQ.Configure_IO + (Config => + (Mode => Mode_In, + Resistors => Floating)); + + TX_Watchdog.Set_Callback (On_TX_IRQ'Unrestricted_Access); + TX_IRQ.Configure_Trigger (STM32.EXTI.Interrupt_Falling_Edge); + + -- RX -- + STM32.Device.Enable_Clock (GPIO_Points'(RX_SDN, RX_CSN, RX_IRQ)); + + Configure_IO + (Points => (RX_SDN, RX_CSN), + Config => + (Mode => Mode_Out, + Resistors => Floating, + Output_Type => Push_Pull, + Speed => Speed_Low)); + + RX_SDN.Set; + RX_CSN.Set; + + -- RX IRQ pin + RX_IRQ.Configure_IO + (Config => + (Mode => Mode_In, + Resistors => Floating)); + + RX_Watchdog.Set_Callback (On_RX_IRQ'Unrestricted_Access); + RX_IRQ.Configure_Trigger (STM32.EXTI.Interrupt_Falling_Edge); + end Init_Pins; + + -------------- + -- Init_SPI -- + -------------- + + procedure Init_SPI + -- Initialize SPI + is + use STM32.Device; + + Conf : constant GPIO_Port_Configuration := + (Mode => Mode_AF, + Resistors => Floating, + AF_Output_Type => Push_Pull, + AF_Speed => Speed_Very_High, + AF => GPIO_AF_SPI4_5); + + SPI_Conf : constant SPI_Configuration := + (Direction => D2Lines_FullDuplex, + Mode => Master, + Data_Size => HAL.SPI.Data_Size_8b, + Clock_Polarity => Low, + Clock_Phase => P1Edge, + Slave_Management => Software_Managed, + Baud_Rate_Prescaler => BRP_16, + First_Bit => MSB, + CRC_Poly => 10); + begin + Enable_Clock (SPI4_Pins); + Enable_Clock (SPI); + + Configure_IO (SPI4_Pins, Conf); + + Reset (SPI); + if not SPI.Enabled then + SPI.Configure (SPI_Conf); + SPI.Enable; + end if; + end Init_SPI; + + Period : constant Time_Span := Milliseconds (200); + Next_Release : Time := Clock; + BG : constant Bitmap_Color := (Alpha => 255, others => 64); + + --------------- + -- On_RX_IRQ -- + --------------- + + procedure On_RX_IRQ is + begin + RX_Status := Get_Interrupt_Statuses (RX); + Has_RX_IRQ := True; + end On_RX_IRQ; + + --------------- + -- On_TX_IRQ -- + --------------- + + procedure On_TX_IRQ is + begin + TX_Status := Get_Interrupt_Statuses (TX); + Has_TX_IRQ := True; + end On_TX_IRQ; + + -------------- + -- On_Error -- + -------------- + + procedure On_Error (Msg : String) is + begin + Set_Power (RX, Off); + Set_Power (TX, Off); + + LCD_Std_Out.Put_Line (Msg); + Display.Update_Layer (1, Copy_Back => True); + + loop + STM32.Board.Toggle (Red_LED); + Next_Release := Next_Release + Period; + delay until Next_Release; + end loop; + end On_Error; + + ----------------- + -- Wait_For_RX -- + ----------------- + + procedure Wait_For_RX (Status1, Status2 : HAL.UInt8) is + -- Waiting for status on the RX side + begin + loop + if Has_RX_IRQ then + Has_RX_IRQ := False; + if (Status1 and RX_Status (1)) > 0 + or else (Status2 and RX_Status (2)) > 0 + then + exit; + end if; + end if; + delay 0.1; + end loop; + end Wait_For_RX; + + ----------------- + -- Wait_For_TX -- + ----------------- + + procedure Wait_For_TX (Status1, Status2 : HAL.UInt8) is + -- Waiting for status on the TX side + begin + loop + if Has_TX_IRQ then + Has_TX_IRQ := False; + if (Status1 and TX_Status (1)) > 0 + or else (Status2 and TX_Status (2)) > 0 + then + exit; + end if; + end if; + delay 0.1; + end loop; + end Wait_For_TX; + + ------------------- + -- Ckeck_RX_Data -- + ------------------- + + procedure Ckeck_RX_Data (Value : String) + -- Checks data on the RX side + is + Length : Natural; + begin + LCD_Std_Out.Put_Line ("Ckeck_RX_Data"); + Length := Natural (Get_Received_Packet_Length (RX)); + LCD_Std_Out.Put_Line (Length'Img); + + if Length > 0 then + declare + Data : HAL.SPI.SPI_Data_8b (1 .. Length); + Str : String (Data'Range) with Import, Address => Data'Address; + begin + Get_Received (RX, Data); + LCD_Std_Out.Put_Line ("Got: '" & Str & "'"); + Display.Update_Layer (1, Copy_Back => True); + + if Str /= Value then + On_Error ("RX DATA FAILS"); + end if; + end; + + else + On_Error ("RX DATA EMPTY"); + end if; + end Ckeck_RX_Data; + +begin + delay 2.0; + + -- Initialize GPIO/SPI + Init_Pins; + Init_SPI; + delay 1.0; + + -- Init testing infrastructure + STM32.Board.Initialize_LEDs; + Display.Initialize; + Display.Initialize_Layer (1, ARGB_8888); + LCD_Std_Out.Set_Font (BMP_Fonts.Font12x12); + LCD_Std_Out.Current_Background_Color := BG; + Display.Hidden_Buffer (1).Set_Source (BG); + Display.Hidden_Buffer (1).Fill; + LCD_Std_Out.Clear_Screen; + + ---------------- + -- Configure -- + ---------------- + + Configure_RX; + Configure_TX; + + ------------------- + -- Send message -- + ------------------- + + LCD_Std_Out.Put_Line ("Send message"); + + -- Set RX in active state + Set_State (RX, Si4432.RX); + + -- Wait until RX is active + declare + Power : Chip_State; + Frequency_Error : Boolean; + Header_Error : Boolean; + RX_FIFO_Empty : Boolean; + RX_TX_FIFO_Underflow : Boolean; + RX_TX_FIFO_Overflow : Boolean; + begin + loop + Get_Device_Status + (RX, Power, Frequency_Error, Header_Error, RX_FIFO_Empty, + RX_TX_FIFO_Underflow, RX_TX_FIFO_Overflow); + exit when Power = Si4432.RX; + delay 0.5; + end loop; + end; + + Has_TX_IRQ := False; + Has_RX_IRQ := False; + + pragma Assert ((TX_Status (1) and Status_Packet_Sent) = 0); + + -- Send message from the TX + declare + S : constant String := "Hello"; + Data : HAL.SPI.SPI_Data_8b (S'Range) with Import, Address => S'Address; + begin + Send (TX, Data); + end; + + -- Wait until the message has been sent + Wait_For_TX (Status_Packet_Sent, 0); + -- Inactivate TX + Set_State (TX, Idle); + + -- Wait until the message has been received on the RX side + Wait_For_RX + ((Status_CRC_Error or Status_Valid_Packet_Received), + 0); + -- Inactivate RX + Set_State (RX, Idle); + + -- Check RX status + if (RX_Status (1) and Status_Valid_Packet_Received) > 0 then + -- Have valid packet, check if it is equal to sent message + Ckeck_RX_Data ("Hello"); + else + -- CRC error in packet + On_Error ("CRC error"); + end if; + + -- Power Off + Set_Power (RX, Off); + Set_Power (TX, Off); + + -- All is OK + LCD_Std_Out.Put_Line ("All tests passed"); + Display.Update_Layer (1, Copy_Back => True); + + loop + STM32.Board.Toggle (Green_LED); + Next_Release := Next_Release + Period; + delay until Next_Release; + end loop; + +exception + when E : others => + On_Error (Ada.Exceptions.Exception_Information (E)); +end Si4432_Example; diff --git a/examples/shared/si4432/src/watchdogs.adb b/examples/shared/si4432/src/watchdogs.adb new file mode 100644 index 000000000..98147e389 --- /dev/null +++ b/examples/shared/si4432/src/watchdogs.adb @@ -0,0 +1,92 @@ +------------------------------------------------------------------------------ +-- -- +-- Copyright (C) 2025, AdaCore -- +-- -- +-- Redistribution and use in source and binary forms, with or without -- +-- modification, are permitted provided that the following conditions are -- +-- met: -- +-- 1. Redistributions of source code must retain the above copyright -- +-- notice, this list of conditions and the following disclaimer. -- +-- 2. Redistributions in binary form must reproduce the above copyright -- +-- notice, this list of conditions and the following disclaimer in -- +-- the documentation and/or other materials provided with the -- +-- distribution. -- +-- 3. Neither the name of the copyright holder nor the names of its -- +-- contributors may be used to endorse or promote products derived -- +-- from this software without specific prior written permission. -- +-- -- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -- +-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -- +-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -- +-- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -- +-- HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -- +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -- +-- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -- +-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -- +-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -- +-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -- +-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- +-- -- +------------------------------------------------------------------------------ + +package body Watchdogs is + + ----------------- + -- RX_Watchdog -- + ----------------- + + protected body RX_Watchdog is + + ------------------ + -- Set_Callback -- + ------------------ + + procedure Set_Callback (Proc : Watchdog_Callback) is + begin + Callback := Proc; + end Set_Callback; + + --------------- + -- Interrupt -- + --------------- + + procedure Interrupt is + begin + STM32.EXTI.Clear_External_Interrupt (RX_EXTI_Line); + if Callback /= null then + Callback.all; + end if; + end Interrupt; + + end RX_Watchdog; + + ----------------- + -- TX_Watchdog -- + ----------------- + + protected body TX_Watchdog is + + ------------------ + -- Set_Callback -- + ------------------ + + procedure Set_Callback (Proc : Watchdog_Callback) is + begin + Callback := Proc; + end Set_Callback; + + --------------- + -- Interrupt -- + --------------- + + procedure Interrupt is + begin + STM32.EXTI.Clear_External_Interrupt (TX_EXTI_Line); + if Callback /= null then + Callback.all; + end if; + end Interrupt; + + end TX_Watchdog; + +end Watchdogs; diff --git a/examples/shared/si4432/src/watchdogs.ads b/examples/shared/si4432/src/watchdogs.ads new file mode 100644 index 000000000..05e449ce6 --- /dev/null +++ b/examples/shared/si4432/src/watchdogs.ads @@ -0,0 +1,81 @@ +------------------------------------------------------------------------------ +-- -- +-- Copyright (C) 2025, AdaCore -- +-- -- +-- Redistribution and use in source and binary forms, with or without -- +-- modification, are permitted provided that the following conditions are -- +-- met: -- +-- 1. Redistributions of source code must retain the above copyright -- +-- notice, this list of conditions and the following disclaimer. -- +-- 2. Redistributions in binary form must reproduce the above copyright -- +-- notice, this list of conditions and the following disclaimer in -- +-- the documentation and/or other materials provided with the -- +-- distribution. -- +-- 3. Neither the name of the copyright holder nor the names of its -- +-- contributors may be used to endorse or promote products derived -- +-- from this software without specific prior written permission. -- +-- -- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -- +-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -- +-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -- +-- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -- +-- HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -- +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -- +-- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -- +-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -- +-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -- +-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -- +-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- +-- -- +------------------------------------------------------------------------------ + +-- Watchdogs to catch IRQs + +with Ada.Interrupts.Names; + +with STM32.GPIO; use STM32.GPIO; +with STM32.Device; +with STM32.EXTI; + +package Watchdogs is + + RX_IRQ : GPIO_Point renames STM32.Device.PB4; + TX_IRQ : GPIO_Point renames STM32.Device.PC3; + + type Watchdog_Callback is access procedure; + + -- RX_Watchdog -- + + protected RX_Watchdog is + pragma Interrupt_Priority; + + procedure Set_Callback (Proc : Watchdog_Callback); + + private + RX_EXTI_Line : STM32.EXTI.External_Line_Number := + RX_IRQ.Interrupt_Line_Number; + + procedure Interrupt; + pragma Attach_Handler (Interrupt, Ada.Interrupts.Names.EXTI4_Interrupt); + + Callback : Watchdog_Callback := null; + end RX_Watchdog; + + -- TX_Watchdog -- + + protected TX_Watchdog is + pragma Interrupt_Priority; + + procedure Set_Callback (Proc : Watchdog_Callback); + + private + TX_EXTI_Line : STM32.EXTI.External_Line_Number := + TX_IRQ.Interrupt_Line_Number; + + procedure Interrupt; + pragma Attach_Handler (Interrupt, Ada.Interrupts.Names.EXTI3_Interrupt); + + Callback : Watchdog_Callback := null; + end TX_Watchdog; + +end Watchdogs;