From 623b50b6cc05c97ae731de99e2625b7f9554d11b Mon Sep 17 00:00:00 2001 From: Pat Rogers Date: Wed, 27 Mar 2024 16:49:08 -0500 Subject: [PATCH 01/18] adding/revising WM8994 driver and Audio wrapper driver for it --- boards/stm32_common/stm32f746disco/audio.adb | 234 +++++++++++-------- boards/stm32_common/stm32f746disco/audio.ads | 33 ++- components/src/audio/W8994/wm8994.adb | 134 ++++++----- components/src/audio/W8994/wm8994.ads | 69 ++++-- 4 files changed, 298 insertions(+), 172 deletions(-) diff --git a/boards/stm32_common/stm32f746disco/audio.adb b/boards/stm32_common/stm32f746disco/audio.adb index fa481d98b..23f69cfe7 100644 --- a/boards/stm32_common/stm32f746disco/audio.adb +++ b/boards/stm32_common/stm32f746disco/audio.adb @@ -32,7 +32,6 @@ -- @author MCD Application Team -- ------------------------------------------------------------------------------ -with HAL; use HAL; with STM32; use STM32; with STM32.Device; use STM32.Device; with STM32.Board; use STM32.Board; @@ -50,25 +49,102 @@ package body Audio is SAI2_SD_B : GPIO_Point renames PG10; SAI2_FS_A : GPIO_Point renames PI7; SAI_Pins : constant GPIO_Points := - (SAI2_MCLK_A, SAI2_SCK_A, SAI2_SD_A, SAI2_SD_B, - SAI2_FS_A); + (SAI2_MCLK_A, SAI2_SCK_A, SAI2_SD_A, SAI2_SD_B, SAI2_FS_A); SAI_Pins_AF : GPIO_Alternate_Function renames GPIO_AF_SAI2_10; - -- SAI in/out conf SAI_Out_Block : SAI_Block renames Block_A; --- SAI_In_Block : SAI_Block renames Block_B; procedure Set_Audio_Clock (Freq : Audio_Frequency); + procedure Initialize_Audio_Out_Pins; - procedure Initialize_SAI_Out (Freq : Audio_Frequency); + + procedure Initialize_Audio_DMA; + -- Configure the DMA channel to the SAI peripheral + + procedure Initialize_SAI_Out (Freq : Audio_Frequency; Sink : Audio_Output_Device); + procedure Initialize_Audio_I2C; + -- Initialize the I2C Port to send commands to the driver + + function As_Device_Volume (Input : Audio_Volume) return WM8994.Volume_Level; + -- Converts the percentage input value to the device-specific range + + ---------------- + -- Initialize -- + ---------------- + + procedure Initialize + (This : in out WM8994_Audio_Device; + Volume : Audio_Volume; + Frequency : Audio_Frequency; + Sink : Audio_Output_Device) + is + begin + STM32.SAI.Deinitialize (Audio_SAI, SAI_Out_Block); + + Set_Audio_Clock (Frequency); + + -- Initialize the SAI + Initialize_Audio_Out_Pins; + Initialize_Audio_DMA; + Initialize_SAI_Out (Frequency, Sink); + + Initialize_Audio_I2C; + + if This.Device.Chip_ID /= WM8994.WM8994_ID then + raise Program_Error with "Invalid Chip ID received from the Audio Codec"; + end if; + + This.Device.Reset; + This.Device.Initialize + (Input => WM8994.No_Input, + Output => WM8994.Output_Device (Sink), + Volume => As_Device_Volume (Volume), + Frequency => WM8994.Audio_Frequency (Frequency)); + + This.Sink := Sink; + -- For sake of any individual calls to Set_Frequency, assuming the STM + -- code is correct that we also need to set the clocks when setting the + -- frequency + end Initialize; + + ---------------- + -- Set_Volume -- + ---------------- + + procedure Set_Volume + (This : in out WM8994_Audio_Device; + Volume : Audio_Volume) + is + begin + This.Device.Set_Volume (As_Device_Volume (Volume)); + end Set_Volume; + + ------------------- + -- Set_Frequency -- + ------------------- + + procedure Set_Frequency + (This : in out WM8994_Audio_Device; + Frequency : Audio_Frequency) + is + begin + -- The following is per the example source file from STM, + -- STM32746G-Disco_example\board_drivers\stm32746g_discovery_audio.c, + -- whereas the WM8894 driver just has a specific function that writes + -- the necessary configuration bits to the device register without any + -- clock configuration too. + Set_Audio_Clock (Frequency); + STM32.SAI.Disable (Audio_SAI, SAI_Out_Block); + Initialize_SAI_Out (Frequency, This.Sink); + STM32.SAI.Enable (Audio_SAI, SAI_Out_Block); + end Set_Frequency; --------------------- -- Set_Audio_Clock -- --------------------- - procedure Set_Audio_Clock (Freq : Audio_Frequency) - is + procedure Set_Audio_Clock (Freq : Audio_Frequency) is begin -- Two groups of frequencies: the 44kHz family and the 48kHz family -- The Actual audio frequency is calculated then with the following @@ -92,31 +168,21 @@ package body Audio is (Audio_SAI, PLLI2SN => 344, -- VCO Output = 344MHz PLLI2SQ => 7, -- SAI Clk(First level) = 49.142 MHz - PLLI2SDIVQ => 1); -- I2S Clk = 49.142 MHz + PLLI2SDIVQ => 1); -- I2S Clk = 49.142 MHz + + when Audio_Freq_12khz | Audio_Freq_24khz | Audio_Freq_88khz => + raise Program_Error with "freq not yet implemented"; + -- FIXME! end case; end Set_Audio_Clock; - ------------------------------- - -- Initialize_Audio_Out_Pins -- - ------------------------------- + -------------------------- + -- Initialize_Audio_DMA -- + -------------------------- - procedure Initialize_Audio_Out_Pins - is + procedure Initialize_Audio_DMA is begin - Enable_Clock (Audio_SAI); - Enable_Clock (SAI_Pins); - - Configure_IO - (SAI_Pins, - (Mode => Mode_AF, - AF => SAI_Pins_AF, - AF_Output_Type => Push_Pull, - AF_Speed => Speed_High, - Resistors => Floating)); - Enable_Clock (Audio_DMA); - - -- Configure the DMA channel to the SAI peripheral Disable (Audio_DMA, Audio_DMA_Out_Stream); Configure (Audio_DMA, @@ -134,16 +200,38 @@ package body Audio is Memory_Burst_Size => Memory_Burst_Single, Peripheral_Burst_Size => Peripheral_Burst_Single)); Clear_All_Status (Audio_DMA, Audio_DMA_Out_Stream); + end Initialize_Audio_DMA; + + ------------------------------- + -- Initialize_Audio_Out_Pins -- + ------------------------------- + + procedure Initialize_Audio_Out_Pins is + begin + Enable_Clock (Audio_SAI); + Enable_Clock (SAI_Pins); + + Configure_IO + (SAI_Pins, + (Mode => Mode_AF, + AF => SAI_Pins_AF, + AF_Output_Type => Push_Pull, + AF_Speed => Speed_High, + Resistors => Floating)); end Initialize_Audio_Out_Pins; ------------------------ -- Initialize_SAI_Out -- ------------------------ - procedure Initialize_SAI_Out (Freq : Audio_Frequency) + procedure Initialize_SAI_Out + (Freq : Audio_Frequency; + Sink : Audio_Output_Device) is + Active_Slots : SAI_Slots; begin STM32.SAI.Disable (Audio_SAI, SAI_Out_Block); + STM32.SAI.Configure_Audio_Block (Audio_SAI, SAI_Out_Block, @@ -158,6 +246,7 @@ package body Audio is Synchronization => Asynchronous_Mode, Output_Drive => Drive_Immediate, FIFO_Threshold => FIFO_1_Quarter_Full); + STM32.SAI.Configure_Block_Frame (Audio_SAI, SAI_Out_Block, @@ -166,13 +255,24 @@ package body Audio is Frame_Sync => FS_Frame_And_Channel_Identification, FS_Polarity => FS_Active_Low, FS_Offset => Before_First_Bit); + + case Sink is + when Headphone | Auto => + Active_Slots := Slot_0 or Slot_2; + when Speaker => + Active_Slots := Slot_1 or Slot_3; + when Both => + Active_Slots := Slot_0 or Slot_1 or Slot_2 or Slot_3; + end case; + STM32.SAI.Configure_Block_Slot (Audio_SAI, SAI_Out_Block, First_Bit_Offset => 0, Slot_Size => Data_Size, Number_Of_Slots => 4, - Enabled_Slots => Slot_0 or Slot_2); + Enabled_Slots => Active_Slots); + STM32.SAI.Enable (Audio_SAI, SAI_Out_Block); end Initialize_SAI_Out; @@ -180,8 +280,7 @@ package body Audio is -- Initialize_Audio_I2C -- -------------------------- - procedure Initialize_Audio_I2C - is + procedure Initialize_Audio_I2C is begin STM32.Setup.Setup_I2C_Master (Port => Audio_I2C, SDA => Audio_I2C_SDA, @@ -191,41 +290,6 @@ package body Audio is Clock_Speed => 100_000); end Initialize_Audio_I2C; - ---------------- - -- Initialize -- - ---------------- - - procedure Initialize_Audio_Out - (This : in out WM8994_Audio_Device; - Volume : Audio_Volume; - Frequency : Audio_Frequency) - is - begin - STM32.SAI.Deinitialize (Audio_SAI, SAI_Out_Block); - - Set_Audio_Clock (Frequency); - - -- Initialize the SAI - Initialize_Audio_Out_Pins; - Initialize_SAI_Out (Frequency); - - -- Initialize the I2C Port to send commands to the driver - Initialize_Audio_I2C; - - if This.Device.Read_ID /= WM8994.WM8994_ID then - raise Constraint_Error with "Invalid ID received from the Audio Code"; - end if; - - This.Device.Reset; - This.Device.Init - (Input => WM8994.No_Input, - Output => WM8994.Auto, - Volume => UInt8 (Volume), - Frequency => - WM8994.Audio_Frequency'Enum_Val - (Audio_Frequency'Enum_Rep (Frequency))); - end Initialize_Audio_Out; - ---------- -- Play -- ---------- @@ -268,8 +332,7 @@ package body Audio is -- Resume -- ------------ - procedure Resume (This : in out WM8994_Audio_Device) - is + procedure Resume (This : in out WM8994_Audio_Device) is begin This.Device.Resume; DMA_Resume (Audio_SAI, SAI_Out_Block); @@ -279,8 +342,7 @@ package body Audio is -- Stop -- ---------- - procedure Stop (This : in out WM8994_Audio_Device) - is + procedure Stop (This : in out WM8994_Audio_Device) is begin This.Device.Stop (WM8994.Stop_Power_Down_Sw); DMA_Stop (Audio_SAI, SAI_Out_Block); @@ -289,32 +351,12 @@ package body Audio is STM32.DMA.Clear_All_Status (Audio_DMA, Audio_DMA_Out_Stream); end Stop; - ---------------- - -- Set_Volume -- - ---------------- - - procedure Set_Volume - (This : in out WM8994_Audio_Device; - Volume : Audio_Volume) - is - begin - This.Device.Set_Volume (UInt8 (Volume)); - end Set_Volume; - - ------------------- - -- Set_Frequency -- - ------------------- + ---------------------- + -- As_Device_Volume -- + ---------------------- - procedure Set_Frequency - (This : in out WM8994_Audio_Device; - Frequency : Audio_Frequency) - is - pragma Unreferenced (This); - begin - Set_Audio_Clock (Frequency); - STM32.SAI.Disable (Audio_SAI, SAI_Out_Block); - Initialize_SAI_Out (Frequency); - STM32.SAI.Enable (Audio_SAI, SAI_Out_Block); - end Set_Frequency; + function As_Device_Volume (Input : Audio_Volume) return WM8994.Volume_Level is + (if Input = 100 then WM8994.Max_Volume + else UInt16 (Input) * WM8994.Max_Volume / 100); end Audio; diff --git a/boards/stm32_common/stm32f746disco/audio.ads b/boards/stm32_common/stm32f746disco/audio.ads index 04655c87d..07f578c59 100644 --- a/boards/stm32_common/stm32f746disco/audio.ads +++ b/boards/stm32_common/stm32f746disco/audio.ads @@ -32,28 +32,45 @@ -- @author MCD Application Team -- ------------------------------------------------------------------------------ -with HAL.Audio; use HAL.Audio; +-- with HAL.Audio; use HAL.Audio; +with HAL; use HAL; with HAL.I2C; use HAL.I2C; with Ravenscar_Time; -private with WM8994; +with WM8994; package Audio is type WM8994_Audio_Device (Port : not null Any_I2C_Port) is tagged limited private; - procedure Initialize_Audio_Out + type Audio_Output_Device is new WM8994.Output_Device + range WM8994.Speaker .. WM8994.Auto; + -- Only No_Output is not included + + type Audio_Frequency is new WM8994.Audio_Frequency; + -- TODO: use HAL.Audio package's type, with WM8994 additions to that type + + type Audio_Volume is range 0 .. 100; -- a percentage + -- TODO: use HAL.Audio package's type + + type Audio_Buffer is array (Natural range <>) of UInt16 + with Component_Size => 16, Alignment => 2; + -- TODO: change to signed 16-bit, since that's apparently what should be used for PCM samples, + -- so revert the change to HAL.Audio.Audio_Buffer (so it is INteger_16 again) and use that. + + procedure Initialize (This : in out WM8994_Audio_Device; Volume : Audio_Volume; - Frequency : Audio_Frequency); + Frequency : Audio_Frequency; + Sink : Audio_Output_Device); procedure Set_Volume (This : in out WM8994_Audio_Device; Volume : Audio_Volume); procedure Set_Frequency - (This : in out WM8994_Audio_Device; + (This : in out WM8994_Audio_Device; Frequency : Audio_Frequency); procedure Play @@ -73,9 +90,11 @@ private Audio_I2C_Addr : constant I2C_Address := 16#34#; - type WM8994_Audio_Device (Port : not null Any_I2C_Port) is - tagged limited record + type WM8994_Audio_Device + (Port : not null Any_I2C_Port) + is tagged limited record Device : WM8994.WM8994_Device (Port, Audio_I2C_Addr, Ravenscar_Time.Delays); + Sink : Audio_Output_Device; end record; end Audio; diff --git a/components/src/audio/W8994/wm8994.adb b/components/src/audio/W8994/wm8994.adb index 860fe601d..8bf49c6bd 100644 --- a/components/src/audio/W8994/wm8994.adb +++ b/components/src/audio/W8994/wm8994.adb @@ -31,20 +31,20 @@ package body WM8994 is - WM8994_CHIPID_ADDR : constant := 16#00#; + WM8994_CHIPID_ADDR : constant := 16#00#; - Output_Enabled : Boolean := False; - Input_Enabled : Boolean := False; + Output_Enabled : Boolean := False; + Input_Enabled : Boolean := False; pragma Unreferenced (Input_Enabled); - --------------- -- I2C_Write -- --------------- - procedure I2C_Write (This : in out WM8994_Device; - Reg : UInt16; - Value : UInt16) + procedure I2C_Write + (This : in out WM8994_Device; + Register : UInt16; + Value : UInt16) is Status : I2C_Status; Data : I2C_Data (1 .. 2); @@ -56,13 +56,13 @@ package body WM8994 is This.Port.Mem_Write (Addr => This.I2C_Addr, - Mem_Addr => Reg, + Mem_Addr => Register, Mem_Addr_Size => Memory_Size_16b, Data => Data, Status => Status); - if Reg /= 0 then - Check := I2C_Read (This, Reg); + if Register /= 0 then + Check := I2C_Read (This, Register); end if; end I2C_Write; @@ -70,40 +70,40 @@ package body WM8994 is -- I2C_Read -- -------------- - function I2C_Read (This : in out WM8994_Device; - Reg : UInt16) - return UInt16 + function I2C_Read + (This : in out WM8994_Device; + Register : UInt16) + return UInt16 is Status : I2C_Status; Data : I2C_Data (1 .. 2); - Ret : UInt16; + Result : UInt16; begin This.Port.Mem_Read (Addr => This.I2C_Addr, - Mem_Addr => Reg, + Mem_Addr => Register, Mem_Addr_Size => Memory_Size_16b, Data => Data, Status => Status); - Ret := Shift_Left (UInt16 (Data (1)), 8) or UInt16 (Data (2)); - - return Ret; + Result := Shift_Left (UInt16 (Data (1)), 8) or UInt16 (Data (2)); + return Result; end I2C_Read; - ---------- - -- Init -- - ---------- + ---------------- + -- Initialize -- + ---------------- - procedure Init + procedure Initialize (This : in out WM8994_Device; Input : Input_Device; Output : Output_Device; - Volume : UInt8; + Volume : Volume_Level; Frequency : Audio_Frequency) is Power_Mgnt_Reg_1 : UInt16 := 0; - begin - -- WM8994 Errata work-arounds + -- WM8994 Errata work-arounds. + -- See https://github.com/STMicroelectronics/stm32-wm8994/blob/main/wm8994.c I2C_Write (This, 16#102#, 16#0003#); I2C_Write (This, 16#817#, 16#0000#); I2C_Write (This, 16#102#, 16#0000#); @@ -302,16 +302,16 @@ package body WM8994 is -- Volume Control This.Set_Volume (Volume); end if; - end Init; + end Initialize; ------------- - -- Read_ID -- + -- Chip_ID -- ------------- - function Read_ID (This : in out WM8994_Device) return UInt16 is + function Chip_ID (This : in out WM8994_Device) return UInt16 is begin return This.I2C_Read (WM8994_CHIPID_ADDR); - end Read_ID; + end Chip_ID; ---------- -- Play -- @@ -375,7 +375,7 @@ package body WM8994 is -- Disable DAC1 and DAC2 I2C_Write (This, 16#05#, 16#0000#); - -- Reset Codec by writing in 0x0000 address register + -- Reset Codec by writing in 16#0000 address register I2C_Write (This, 16#0000#, 16#0000#); end if; end Stop; @@ -384,13 +384,10 @@ package body WM8994 is -- Set_Volume -- ---------------- - procedure Set_Volume (This : in out WM8994_Device; Volume : Volume_Level) + procedure Set_Volume + (This : in out WM8994_Device; + Volume : Volume_Level) is - -- Actual Volume in range 0 .. 16#3F# - Converted_Volume : constant UInt16 := - (if Volume = 100 then 63 - else UInt16 (Volume) * 63 / 100); - begin if Volume = 0 then -- Mute the codec @@ -399,16 +396,16 @@ package body WM8994 is This.Set_Mute (Mute_Off); -- Left Headphone Volume - I2C_Write (This, 16#1C#, Converted_Volume or 16#140#); + I2C_Write (This, 16#1C#, Volume or 16#140#); -- Right Headphone volume - I2C_Write (This, 16#1D#, Converted_Volume or 16#140#); + I2C_Write (This, 16#1D#, Volume or 16#140#); -- Left Speaker volume - I2C_Write (This, 16#26#, Converted_Volume or 16#140#); + I2C_Write (This, 16#26#, Volume or 16#140#); -- Right Speaker volume - I2C_Write (This, 16#27#, Converted_Volume or 16#140#); + I2C_Write (This, 16#27#, Volume or 16#140#); end if; end Set_Volume; @@ -438,8 +435,9 @@ package body WM8994 is -- Set_Output_Mode -- --------------------- - procedure Set_Output_Mode (This : in out WM8994_Device; - Device : Output_Device) + procedure Set_Output_Mode + (This : in out WM8994_Device; + Device : Output_Device) is begin case Device is @@ -495,32 +493,62 @@ package body WM8994 is -- Set_Frequency -- ------------------- - procedure Set_Frequency (This : in out WM8994_Device; - Freq : Audio_Frequency) + procedure Set_Frequency + (This : in out WM8994_Device; + Freq : Audio_Frequency) is begin + -- In the following, the values written set both the AIF1_SR [3:0] bits + -- and the AIF1CLK_RATE [3:0] bits (the latter to set the ratio). The + -- ratio is always 256, which is indicated by the bit pattern 2#0011#, + -- so the lower digits in the values is always 3 in hex. + -- + -- See the table labled "Register 0210h AIF1 Rate" pages 285 and 286 of + -- WM8994_Rev4.6 from Cirrus Logic case Freq is when Audio_Freq_8kHz => -- AIF1 Sample Rate = 8 (kHz), ratio=256 I2C_Write (This, 16#210#, 16#0003#); - when Audio_Freq_16kHz => - -- AIF1 Sample Rate = 16 (kHz), ratio=256 - I2C_Write (This, 16#210#, 16#0033#); - when Audio_Freq_48kHz => - -- AIF1 Sample Rate = 48 (kHz), ratio=256 - I2C_Write (This, 16#210#, 16#0083#); - when Audio_Freq_96kHz => - -- AIF1 Sample Rate = 96 (kHz), ratio=256 - I2C_Write (This, 16#210#, 16#00A3#); + when Audio_Freq_11kHz => -- AIF1 Sample Rate = 11.025 (kHz), ratio=256 I2C_Write (This, 16#210#, 16#0013#); + + when Audio_Freq_12kHz => + -- AIF1 Sample Rate = 12 (kHz), ratio=256 + I2C_Write (This, 16#210#, 16#0023#); + + when Audio_Freq_16kHz => + -- AIF1 Sample Rate = 16 (kHz), ratio=256 + I2C_Write (This, 16#210#, 16#0033#); + when Audio_Freq_22kHz => -- AIF1 Sample Rate = 22.050 (kHz), ratio=256 I2C_Write (This, 16#210#, 16#0043#); + + when Audio_Freq_24kHz => + -- AIF1 Sample Rate = 24 (kHz), ratio=256 + I2C_Write (This, 16#210#, 16#0053#); + + when Audio_Freq_32kHz => + -- AIF1 Sample Rate = 32 (kHz), ratio=256 + I2C_Write (This, 16#210#, 16#0063#); + when Audio_Freq_44kHz => -- AIF1 Sample Rate = 44.1 (kHz), ratio=256 I2C_Write (This, 16#210#, 16#0073#); + + when Audio_Freq_48kHz => + -- AIF1 Sample Rate = 48 (kHz), ratio=256 + I2C_Write (This, 16#210#, 16#0083#); + + when Audio_Freq_88kHz => + -- AIF1 Sample Rate = 88.2 (kHz), ratio=256 + I2C_Write (This, 16#210#, 16#0093#); + + when Audio_Freq_96kHz => + -- AIF1 Sample Rate = 96 (kHz), ratio=256 + I2C_Write (This, 16#210#, 16#00A3#); end case; end Set_Frequency; diff --git a/components/src/audio/W8994/wm8994.ads b/components/src/audio/W8994/wm8994.ads index fe55d45b5..1fd3211d1 100644 --- a/components/src/audio/W8994/wm8994.ads +++ b/components/src/audio/W8994/wm8994.ads @@ -37,12 +37,16 @@ with HAL.Time; package WM8994 is + -- TODO: see page 144 Datasheet WM8994_Rev4.6, from Cirrus Logic regarding + -- "For suppression of pop noise ..." + type Output_Device is (No_Output, Speaker, Headphone, Both, Auto); + type Input_Device is (No_Input, Microphone, @@ -53,21 +57,38 @@ package WM8994 is type Audio_Frequency is (Audio_Freq_8kHz, Audio_Freq_11kHz, + Audio_Freq_12kHz, Audio_Freq_16kHz, Audio_Freq_22kHz, + Audio_Freq_24kHz, + Audio_Freq_32kHz, Audio_Freq_44kHz, Audio_Freq_48kHz, + Audio_Freq_88kHz, Audio_Freq_96kHz) with Size => 32; + -- Sample rates from 8kHz to 96kHz are all supported, per Datasheet + -- WM8994_Rev4.6, pages 43 and 93, from Cirrus Logic. See all Tables 37 + -- and 41. + -- + -- Note that 88.2kHz and 96kHz modes are supported for AIF1 input (DAC + -- playback) only. + for Audio_Frequency use (Audio_Freq_8kHz => 8_000, Audio_Freq_11kHz => 11_025, + Audio_Freq_12kHz => 12_000, Audio_Freq_16kHz => 16_000, Audio_Freq_22kHz => 22_050, + Audio_Freq_24kHz => 24_000, + Audio_Freq_32kHz => 32_000, Audio_Freq_44kHz => 44_100, Audio_Freq_48kHz => 48_000, + Audio_Freq_88kHz => 88_200, Audio_Freq_96kHz => 96_000); + -- TODO: support 24K and 32K frequencies + type Mute is (Mute_On, Mute_Off); @@ -84,7 +105,9 @@ package WM8994 is -- is set to default configuration (user should re-Initialize the codec in -- order to play again the audio stream). - subtype Volume_Level is UInt8 range 0 .. 100; + Max_Volume : constant := 16#3F#; + + subtype Volume_Level is UInt16 range 0 .. Max_Volume; type WM8994_Device (Port : not null Any_I2C_Port; @@ -92,35 +115,49 @@ package WM8994 is Time : not null HAL.Time.Any_Delays) is tagged limited private; - procedure Init (This : in out WM8994_Device; - Input : Input_Device; - Output : Output_Device; - Volume : UInt8; - Frequency : Audio_Frequency); + procedure Initialize + (This : in out WM8994_Device; + Input : Input_Device; + Output : Output_Device; + Volume : Volume_Level; + Frequency : Audio_Frequency); + + function Chip_ID (This : in out WM8994_Device) return UInt16; - function Read_ID (This : in out WM8994_Device) return UInt16; procedure Play (This : in out WM8994_Device); + procedure Pause (This : in out WM8994_Device); + procedure Resume (This : in out WM8994_Device); + procedure Stop (This : in out WM8994_Device; Cmd : Stop_Mode); + procedure Set_Volume (This : in out WM8994_Device; Volume : Volume_Level); + procedure Set_Mute (This : in out WM8994_Device; Cmd : Mute); + procedure Set_Output_Mode (This : in out WM8994_Device; Device : Output_Device); + procedure Set_Frequency (This : in out WM8994_Device; Freq : Audio_Frequency); + procedure Reset (This : in out WM8994_Device); private - type WM8994_Device (Port : not null Any_I2C_Port; - I2C_Addr : UInt10; - Time : not null HAL.Time.Any_Delays) is tagged limited null record; - - procedure I2C_Write (This : in out WM8994_Device; - Reg : UInt16; - Value : UInt16); - function I2C_Read (This : in out WM8994_Device; - Reg : UInt16) + + type WM8994_Device + (Port : not null Any_I2C_Port; + I2C_Addr : UInt10; + Time : not null HAL.Time.Any_Delays) + is tagged limited null record; + + procedure I2C_Write (This : in out WM8994_Device; + Register : UInt16; + Value : UInt16); + + function I2C_Read (This : in out WM8994_Device; + Register : UInt16) return UInt16; end WM8994; From 99151628401f2951e26838ce739450e443c53e7b Mon Sep 17 00:00:00 2001 From: Pat Rogers Date: Wed, 27 Mar 2024 18:11:53 -0500 Subject: [PATCH 02/18] use new IO package for WM8994, with constants for register addresses --- components/src/audio/W8994/wm8994-io.adb | 55 +++++ components/src/audio/W8994/wm8994-io.ads | 250 +++++++++++++++++++++++ components/src/audio/W8994/wm8994.adb | 243 +++++++++------------- components/src/audio/W8994/wm8994.ads | 8 - 4 files changed, 401 insertions(+), 155 deletions(-) create mode 100644 components/src/audio/W8994/wm8994-io.adb create mode 100644 components/src/audio/W8994/wm8994-io.ads diff --git a/components/src/audio/W8994/wm8994-io.adb b/components/src/audio/W8994/wm8994-io.adb new file mode 100644 index 000000000..df4a8b9cf --- /dev/null +++ b/components/src/audio/W8994/wm8994-io.adb @@ -0,0 +1,55 @@ +package body WM8994.IO is + + --------------- + -- I2C_Write -- + --------------- + + procedure I2C_Write + (This : in out WM8994_Device; + Register : Register_Address; + Value : UInt16) + is + Status : I2C_Status; + Data : I2C_Data (1 .. 2); + Check : UInt16 with Unreferenced; + begin + -- Device is MSB first + Data (1) := UInt8 (Shift_Right (Value and 16#FF00#, 8)); + Data (2) := UInt8 (Value and 16#FF#); + + This.Port.Mem_Write + (Addr => This.I2C_Addr, + Mem_Addr => UInt16 (Register), + Mem_Addr_Size => Memory_Size_16b, + Data => Data, + Status => Status); + + if Register /= 0 then + Check := I2C_Read (This, Register); + end if; + end I2C_Write; + + -------------- + -- I2C_Read -- + -------------- + + function I2C_Read + (This : in out WM8994_Device; + Register : Register_Address) + return UInt16 + is + Status : I2C_Status; + Data : I2C_Data (1 .. 2); + Result : UInt16; + begin + This.Port.Mem_Read + (Addr => This.I2C_Addr, + Mem_Addr => UInt16 (Register), + Mem_Addr_Size => Memory_Size_16b, + Data => Data, + Status => Status); + Result := Shift_Left (UInt16 (Data (1)), 8) or UInt16 (Data (2)); + return Result; + end I2C_Read; + +end WM8994.IO; diff --git a/components/src/audio/W8994/wm8994-io.ads b/components/src/audio/W8994/wm8994-io.ads new file mode 100644 index 000000000..b9093fc11 --- /dev/null +++ b/components/src/audio/W8994/wm8994-io.ads @@ -0,0 +1,250 @@ +package WM8994.IO is + + type Register_Address is new UInt16; + + procedure I2C_Write + (This : in out WM8994_Device; + Register : Register_Address; + Value : UInt16); + + function I2C_Read + (This : in out WM8994_Device; + Register : Register_Address) + return UInt16; + + WM8994_SW_Reset : constant Register_Address := 16#0000#; + WM8994_PWR_Management_1 : constant Register_Address := 16#0001#; + WM8994_PWR_Management_2 : constant Register_Address := 16#0002#; + WM8994_PWR_Management_3 : constant Register_Address := 16#0003#; + WM8994_PWR_Management_4 : constant Register_Address := 16#0004#; + WM8994_PWR_Management_5 : constant Register_Address := 16#0005#; + WM8994_PWR_Management_6 : constant Register_Address := 16#0006#; + WM8994_Input_Mixer_1 : constant Register_Address := 16#0015#; + WM8994_Left_Line_In12_Vol : constant Register_Address := 16#0018#; + WM8994_Left_Line_In34_Vol : constant Register_Address := 16#0019#; + WM8994_Right_Line_In12_Vol : constant Register_Address := 16#001A#; + WM8994_Right_Line_In34_Vol : constant Register_Address := 16#001B#; + WM8994_Left_Output_Vol : constant Register_Address := 16#001C#; + WM8994_Right_Output_Vol : constant Register_Address := 16#001D#; + WM8994_Line_Output_Vol : constant Register_Address := 16#001E#; + WM8994_Output2_Vol : constant Register_Address := 16#001F#; + WM8994_Left_OPGA_Vol : constant Register_Address := 16#0020#; + WM8994_Right_OPGA_Vol : constant Register_Address := 16#0021#; + WM8994_SPKMIXL_ATT : constant Register_Address := 16#0022#; + WM8994_SPKMIXR_ATT : constant Register_Address := 16#0023#; + WM8994_Output_Mixer : constant Register_Address := 16#0024#; + WM8994_CLASS_D : constant Register_Address := 16#0025#; + WM8994_SPK_Left_Vol : constant Register_Address := 16#0026#; + WM8994_SPK_Right_Vol : constant Register_Address := 16#0027#; + WM8994_Input_Mixer_2 : constant Register_Address := 16#0028#; + WM8994_Input_Mixer_3 : constant Register_Address := 16#0029#; + WM8994_Input_Mixer_4 : constant Register_Address := 16#002A#; + WM8994_Input_Mixer_5 : constant Register_Address := 16#002B#; + WM8994_Input_Mixer_6 : constant Register_Address := 16#002C#; + WM8994_Output_Mixer_1 : constant Register_Address := 16#002D#; + WM8994_Output_Mixer_2 : constant Register_Address := 16#002E#; + WM8994_Output_Mixer_3 : constant Register_Address := 16#002F#; + WM8994_Output_Mixer_4 : constant Register_Address := 16#0030#; + WM8994_Output_Mixer_5 : constant Register_Address := 16#0031#; + WM8994_Output_Mixer_6 : constant Register_Address := 16#0032#; + WM8994_Output2_Mixer : constant Register_Address := 16#0033#; + WM8994_Line_Mixer_1 : constant Register_Address := 16#0034#; + WM8994_Line_Mixer_2 : constant Register_Address := 16#0035#; + WM8994_Speaker_Mixer : constant Register_Address := 16#0036#; + WM8994_Add_Control : constant Register_Address := 16#0037#; + WM8994_AntiPop1 : constant Register_Address := 16#0038#; + WM8994_AntiPop2 : constant Register_Address := 16#0039#; + WM8994_MicBias : constant Register_Address := 16#003A#; + WM8994_LDO1 : constant Register_Address := 16#003B#; + WM8994_LDO2 : constant Register_Address := 16#003C#; + WM8994_Charge_Pump1 : constant Register_Address := 16#004C#; + WM8994_Charge_Pump2 : constant Register_Address := 16#004D#; + WM8994_CLASS_W : constant Register_Address := 16#0051#; + WM8994_DC_Servo1 : constant Register_Address := 16#0054#; + WM8994_DC_Servo2 : constant Register_Address := 16#0055#; + WM8994_DC_Servo_Readback : constant Register_Address := 16#0058#; + WM8994_DC_Servo_Writeval : constant Register_Address := 16#0059#; + WM8994_Analog_HP : constant Register_Address := 16#0060#; + WM8994_Chip_Revision : constant Register_Address := 16#0100#; + WM8994_Control_Interface : constant Register_Address := 16#0101#; + WM8994_WRITE_SEQ_CTRL1 : constant Register_Address := 16#0110#; + WM8994_WRITE_SEQ_CTRL2 : constant Register_Address := 16#0111#; + WM8994_AIF1_Clocking1 : constant Register_Address := 16#0200#; + WM8994_AIF1_Clocking2 : constant Register_Address := 16#0201#; + WM8994_AIF2_Clocking1 : constant Register_Address := 16#0204#; + WM8994_AIF2_Clocking2 : constant Register_Address := 16#0205#; + WM8994_Clocking1 : constant Register_Address := 16#0208#; + WM8994_Clocking2 : constant Register_Address := 16#0209#; + WM8994_AIF1_Rate : constant Register_Address := 16#0210#; + WM8994_AIF2_Rate : constant Register_Address := 16#0211#; + WM8994_Rate_Status : constant Register_Address := 16#0212#; + WM8994_FLL1_Control1 : constant Register_Address := 16#0220#; + WM8994_FLL1_Control2 : constant Register_Address := 16#0221#; + WM8994_FLL1_Control3 : constant Register_Address := 16#0222#; + WM8994_FLL1_Control4 : constant Register_Address := 16#0223#; + WM8994_FLL1_Control5 : constant Register_Address := 16#0224#; + WM8994_FLL2_Control1 : constant Register_Address := 16#0240#; + WM8994_FLL2_Control2 : constant Register_Address := 16#0241#; + WM8994_FLL2_Control3 : constant Register_Address := 16#0242#; + WM8994_FLL2_Control4 : constant Register_Address := 16#0243#; + WM8994_FLL2_Control5 : constant Register_Address := 16#0244#; + WM8994_AIF1_Control1 : constant Register_Address := 16#0300#; + WM8994_AIF1_Control2 : constant Register_Address := 16#0301#; + WM8994_AIF1_Master_Slave : constant Register_Address := 16#0302#; + WM8994_AIF1_BCLK : constant Register_Address := 16#0303#; + WM8994_AIF1_ADC_LRCLK : constant Register_Address := 16#0304#; + WM8994_AIF1_DAC_LRCLK : constant Register_Address := 16#0305#; + WM8994_AIF1_DAC_DELTA : constant Register_Address := 16#0306#; + WM8994_AIF1_ADC_DELTA : constant Register_Address := 16#0307#; + WM8994_AIF2_Control1 : constant Register_Address := 16#0310#; + WM8994_AIF2_Control2 : constant Register_Address := 16#0311#; + WM8994_AIF2_Master_Slave : constant Register_Address := 16#0312#; + WM8994_AIF2_BCLK : constant Register_Address := 16#0313#; + WM8994_AIF2_ADC_LRCLK : constant Register_Address := 16#0314#; + WM8994_AIF2_DAC_LRCLK : constant Register_Address := 16#0315#; + WM8994_AIF2_DAC_DELTA : constant Register_Address := 16#0316#; + WM8994_AIF2_ADC_DELTA : constant Register_Address := 16#0317#; + WM8994_AIF1_ADC1_Left_Vol : constant Register_Address := 16#0400#; + WM8994_AIF1_ADC1_Right_Vol : constant Register_Address := 16#0401#; + WM8994_AIF1_DAC1_Left_Vol : constant Register_Address := 16#0402#; + WM8994_AIF1_DAC1_Right_Vol : constant Register_Address := 16#0403#; + WM8994_AIF1_ADC2_Left_Vol : constant Register_Address := 16#0404#; + WM8994_AIF1_ADC2_Right_Vol : constant Register_Address := 16#0405#; + WM8994_AIF1_DAC2_Left_Vol : constant Register_Address := 16#0406#; + WM8994_AIF1_DAC2_Right_Vol : constant Register_Address := 16#0407#; + WM8994_AIF1_ADC1_Filters : constant Register_Address := 16#0410#; + WM8994_AIF1_ADC2_Filters : constant Register_Address := 16#0411#; + WM8994_AIF1_DAC1_Filter1 : constant Register_Address := 16#0420#; + WM8994_AIF1_DAC1_Filter2 : constant Register_Address := 16#0421#; + WM8994_AIF1_DAC2_Filter1 : constant Register_Address := 16#0422#; + WM8994_AIF1_DAC2_Filter2 : constant Register_Address := 16#0423#; + WM8994_AIF1_DRC1 : constant Register_Address := 16#0440#; + WM8994_AIF1_DRC1_1 : constant Register_Address := 16#0441#; + WM8994_AIF1_DRC1_2 : constant Register_Address := 16#0442#; + WM8994_AIF1_DRC1_3 : constant Register_Address := 16#0443#; + WM8994_AIF1_DRC1_4 : constant Register_Address := 16#0444#; + WM8994_AIF1_DRC2 : constant Register_Address := 16#0450#; + WM8994_AIF1_DRC2_1 : constant Register_Address := 16#0451#; + WM8994_AIF1_DRC2_2 : constant Register_Address := 16#0452#; + WM8994_AIF1_DRC2_3 : constant Register_Address := 16#0453#; + WM8994_AIF1_DRC2_4 : constant Register_Address := 16#0454#; + WM8994_AIF1_DAC1_EQG_1 : constant Register_Address := 16#0480#; + WM8994_AIF1_DAC1_EQG_2 : constant Register_Address := 16#0481#; + WM8994_AIF1_DAC1_EQG_1A : constant Register_Address := 16#0482#; + WM8994_AIF1_DAC1_EQG_1B : constant Register_Address := 16#0483#; + WM8994_AIF1_DAC1_EQG_1PG : constant Register_Address := 16#0484#; + WM8994_AIF1_DAC1_EQG_2A : constant Register_Address := 16#0485#; + WM8994_AIF1_DAC1_EQG_2B : constant Register_Address := 16#0486#; + WM8994_AIF1_DAC1_EQG_2C : constant Register_Address := 16#0487#; + WM8994_AIF1_DAC1_EQG_2PG : constant Register_Address := 16#0488#; + WM8994_AIF1_DAC1_EQG_3A : constant Register_Address := 16#0489#; + WM8994_AIF1_DAC1_EQG_3B : constant Register_Address := 16#048A#; + WM8994_AIF1_DAC1_EQG_3C : constant Register_Address := 16#048B#; + WM8994_AIF1_DAC1_EQG_3PG : constant Register_Address := 16#048C#; + WM8994_AIF1_DAC1_EQG_4A : constant Register_Address := 16#048D#; + WM8994_AIF1_DAC1_EQG_4B : constant Register_Address := 16#048E#; + WM8994_AIF1_DAC1_EQG_4C : constant Register_Address := 16#048F#; + WM8994_AIF1_DAC1_EQG_4PG : constant Register_Address := 16#0490#; + WM8994_AIF1_DAC1_EQG_5A : constant Register_Address := 16#0491#; + WM8994_AIF1_DAC1_EQG_5B : constant Register_Address := 16#0492#; + WM8994_AIF1_DAC1_EQG_5PG : constant Register_Address := 16#0493#; + WM8994_AIF1_DAC2_EQG_1 : constant Register_Address := 16#04A0#; + WM8994_AIF1_DAC2_EQG_2 : constant Register_Address := 16#04A1#; + WM8994_AIF1_DAC2_EQG_1A : constant Register_Address := 16#04A2#; + WM8994_AIF1_DAC2_EQG_1B : constant Register_Address := 16#04A3#; + WM8994_AIF1_DAC2_EQG_1PG : constant Register_Address := 16#04A4#; + WM8994_AIF1_DAC2_EQG_2A : constant Register_Address := 16#04A5#; + WM8994_AIF1_DAC2_EQG_2B : constant Register_Address := 16#04A6#; + WM8994_AIF1_DAC2_EQG_2C : constant Register_Address := 16#04A7#; + WM8994_AIF1_DAC2_EQG_2PG : constant Register_Address := 16#04A8#; + WM8994_AIF1_DAC2_EQG_3A : constant Register_Address := 16#04A9#; + WM8994_AIF1_DAC2_EQG_3B : constant Register_Address := 16#04AA#; + WM8994_AIF1_DAC2_EQG_3C : constant Register_Address := 16#04AB#; + WM8994_AIF1_DAC2_EQG_3PG : constant Register_Address := 16#04AC#; + WM8994_AIF1_DAC2_EQG_4A : constant Register_Address := 16#04AD#; + WM8994_AIF1_DAC2_EQG_4B : constant Register_Address := 16#04AE#; + WM8994_AIF1_DAC2_EQG_4C : constant Register_Address := 16#04AF#; + WM8994_AIF1_DAC2_EQG_4PG : constant Register_Address := 16#04B0#; + WM8994_AIF1_DAC2_EQG_5A : constant Register_Address := 16#04B1#; + WM8994_AIF1_DAC2_EQG_5B : constant Register_Address := 16#04B2#; + WM8994_AIF1_DAC2_EQG_5PG : constant Register_Address := 16#04B3#; + WM8994_AIF2_ADC_Left_Vol : constant Register_Address := 16#0500#; + WM8994_AIF2_ADC_Right_Vol : constant Register_Address := 16#0501#; + WM8994_AIF2_DAC_Left_Vol : constant Register_Address := 16#0502#; + WM8994_AIF2_DAC_Right_Vol : constant Register_Address := 16#0503#; + WM8994_AIF2_ADC_Filters : constant Register_Address := 16#0510#; + WM8994_AIF2_DAC_Filter_1 : constant Register_Address := 16#0520#; + WM8994_AIF2_DAC_Filter_2 : constant Register_Address := 16#0521#; + WM8994_AIF2_DRC_1 : constant Register_Address := 16#0540#; + WM8994_AIF2_DRC_2 : constant Register_Address := 16#0541#; + WM8994_AIF2_DRC_3 : constant Register_Address := 16#0542#; + WM8994_AIF2_DRC_4 : constant Register_Address := 16#0543#; + WM8994_AIF2_DRC_5 : constant Register_Address := 16#0544#; + WM8994_AIF2_EQG_1 : constant Register_Address := 16#0580#; + WM8994_AIF2_EQG_2 : constant Register_Address := 16#0581#; + WM8994_AIF2_EQG_1A : constant Register_Address := 16#0582#; + WM8994_AIF2_EQG_1B : constant Register_Address := 16#0583#; + WM8994_AIF2_EQG_1PG : constant Register_Address := 16#0584#; + WM8994_AIF2_EQG_2A : constant Register_Address := 16#0585#; + WM8994_AIF2_EQG_2B : constant Register_Address := 16#0586#; + WM8994_AIF2_EQG_2C : constant Register_Address := 16#0587#; + WM8994_AIF2_EQG_2PG : constant Register_Address := 16#0588#; + WM8994_AIF2_EQG_3A : constant Register_Address := 16#0589#; + WM8994_AIF2_EQG_3B : constant Register_Address := 16#058A#; + WM8994_AIF2_EQG_3C : constant Register_Address := 16#058B#; + WM8994_AIF2_EQG_3PG : constant Register_Address := 16#058C#; + WM8994_AIF2_EQG_4A : constant Register_Address := 16#058D#; + WM8994_AIF2_EQG_4B : constant Register_Address := 16#058E#; + WM8994_AIF2_EQG_4C : constant Register_Address := 16#058F#; + WM8994_AIF2_EQG_4PG : constant Register_Address := 16#0590#; + WM8994_AIF2_EQG_5A : constant Register_Address := 16#0591#; + WM8994_AIF2_EQG_5B : constant Register_Address := 16#0592#; + WM8994_AIF2_EQG_5PG : constant Register_Address := 16#0593#; + WM8994_DAC1_Mixer_Vol : constant Register_Address := 16#0600#; + WM8994_AIF1_DAC1_LMR : constant Register_Address := 16#0601#; + WM8994_AIF1_DAC1_RMR : constant Register_Address := 16#0602#; + WM8994_DAC2_Mixer_Vol : constant Register_Address := 16#0603#; + WM8994_AIF1_DAC2_LMR : constant Register_Address := 16#0604#; + WM8994_AIF1_DAC2_RMR : constant Register_Address := 16#0605#; + WM8994_AIF1_ADC1_LMR : constant Register_Address := 16#0606#; + WM8994_AIF1_ADC1_RMR : constant Register_Address := 16#0607#; + WM8994_AIF1_ADC2_LMR : constant Register_Address := 16#0608#; + WM8994_AIF1_ADC2_RMR : constant Register_Address := 16#0609#; + WM8994_DAC1_Left_Vol : constant Register_Address := 16#0610#; + WM8994_DAC1_Right_Vol : constant Register_Address := 16#0611#; + WM8994_DAC2_Left_Vol : constant Register_Address := 16#0612#; + WM8994_DAC2_Right_Vol : constant Register_Address := 16#0613#; + WM8994_DAC_SoftMute : constant Register_Address := 16#0614#; + WM8994_Oversampling : constant Register_Address := 16#0620#; + WM8994_Sidetone : constant Register_Address := 16#0621#; + WM8994_GPIO1 : constant Register_Address := 16#0700#; + WM8994_GPIO2 : constant Register_Address := 16#0701#; + WM8994_GPIO3 : constant Register_Address := 16#0702#; + WM8994_GPIO4 : constant Register_Address := 16#0703#; + WM8994_GPIO5 : constant Register_Address := 16#0704#; + WM8994_GPIO6 : constant Register_Address := 16#0705#; + WM8994_GPIO7 : constant Register_Address := 16#0706#; + WM8994_GPIO8 : constant Register_Address := 16#0707#; + WM8994_GPIO9 : constant Register_Address := 16#0708#; + WM8994_GPIO10 : constant Register_Address := 16#0709#; + WM8994_GPIO11 : constant Register_Address := 16#070A#; + WM8994_PULL_Control_1 : constant Register_Address := 16#0720#; + WM8994_PULL_Control_2 : constant Register_Address := 16#0721#; + WM8994_INT_Status_1 : constant Register_Address := 16#0730#; + WM8994_INT_Status_2 : constant Register_Address := 16#0731#; + WM8994_INT_Raw_Status_2 : constant Register_Address := 16#0732#; + WM8994_INT_Status1_Mask : constant Register_Address := 16#0738#; + WM8994_INT_Status2_Mask : constant Register_Address := 16#0739#; + WM8994_INT_Control : constant Register_Address := 16#0740#; + WM8994_IRQ_Debounce : constant Register_Address := 16#0748#; + WM8994_WRITE_Sequencer0 : constant Register_Address := 16#3000#; + WM8994_WRITE_Sequencer1 : constant Register_Address := 16#3001#; + WM8994_WRITE_Sequencer2 : constant Register_Address := 16#3002#; + WM8994_WRITE_Sequencer3 : constant Register_Address := 16#3003#; + WM8994_WRITE_Sequencer4 : constant Register_Address := 16#3508#; + WM8994_WRITE_Sequencer5 : constant Register_Address := 16#3509#; + WM8994_WRITE_Sequencer6 : constant Register_Address := 16#3510#; + WM8994_WRITE_Sequencer7 : constant Register_Address := 16#3511#; + WM8994_SW_Reset_Mask : constant Register_Address := 16#FFFF#; + +end WM8994.IO; diff --git a/components/src/audio/W8994/wm8994.adb b/components/src/audio/W8994/wm8994.adb index 8bf49c6bd..6c33279bb 100644 --- a/components/src/audio/W8994/wm8994.adb +++ b/components/src/audio/W8994/wm8994.adb @@ -1,6 +1,6 @@ ------------------------------------------------------------------------------ -- -- --- Copyright (C) 2015-2016, AdaCore -- +-- Copyright (C) 2015-2024, AdaCore -- -- -- -- Redistribution and use in source and binary forms, with or without -- -- modification, are permitted provided that the following conditions are -- @@ -28,6 +28,7 @@ -- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- -- -- ------------------------------------------------------------------------------ +with WM8994.IO; use WM8994.IO; package body WM8994 is @@ -37,58 +38,6 @@ package body WM8994 is Input_Enabled : Boolean := False; pragma Unreferenced (Input_Enabled); - --------------- - -- I2C_Write -- - --------------- - - procedure I2C_Write - (This : in out WM8994_Device; - Register : UInt16; - Value : UInt16) - is - Status : I2C_Status; - Data : I2C_Data (1 .. 2); - Check : UInt16 with Unreferenced; - begin - -- Device is MSB first - Data (1) := UInt8 (Shift_Right (Value and 16#FF00#, 8)); - Data (2) := UInt8 (Value and 16#FF#); - - This.Port.Mem_Write - (Addr => This.I2C_Addr, - Mem_Addr => Register, - Mem_Addr_Size => Memory_Size_16b, - Data => Data, - Status => Status); - - if Register /= 0 then - Check := I2C_Read (This, Register); - end if; - end I2C_Write; - - -------------- - -- I2C_Read -- - -------------- - - function I2C_Read - (This : in out WM8994_Device; - Register : UInt16) - return UInt16 - is - Status : I2C_Status; - Data : I2C_Data (1 .. 2); - Result : UInt16; - begin - This.Port.Mem_Read - (Addr => This.I2C_Addr, - Mem_Addr => Register, - Mem_Addr_Size => Memory_Size_16b, - Data => Data, - Status => Status); - Result := Shift_Left (UInt16 (Data (1)), 8) or UInt16 (Data (2)); - return Result; - end I2C_Read; - ---------------- -- Initialize -- ---------------- @@ -109,10 +58,10 @@ package body WM8994 is I2C_Write (This, 16#102#, 16#0000#); -- Enable VMID soft restart, Start-up Bias current enabled - I2C_Write (This, 16#39#, 16#006C#); + I2C_Write (This, WM8994_AntiPop2, 16#006C#); -- Enable BIAS generator, Enable VMID - I2C_Write (This, 16#01#, 16#0003#); + I2C_Write (This, WM8994_PWR_Management_1, 16#0003#); This.Time.Delay_Milliseconds (50); @@ -129,53 +78,53 @@ package body WM8994 is -- Enable AIF1ADC2 (Left), Enable AIF1ADC2 (Right) -- Enable DMICDAT2 (Left), Enable DMICDAT2 (Right) -- Enable Left ADC, Enable Right ADC - I2C_Write (This, 16#04#, 16#0C30#); + I2C_Write (This, WM8994_PWR_Management_4, 16#0C30#); -- Enable AIF1 DRC2 Signal Detect & DRC in AIF1ADC2 Left/Right -- Timeslot 1 - I2C_Write (This, 16#450#, 16#00DB#); + I2C_Write (This, WM8994_AIF1_DRC2, 16#00DB#); -- Disable IN1L, IN1R, IN2L, IN2R, Enable Thermal sensor & -- shutdown - I2C_Write (This, 16#02#, 16#6000#); + I2C_Write (This, WM8994_PWR_Management_4, 16#6000#); -- Enable the DMIC2(Left) to AIF1 Timeslot 1 (Left) mixer path - I2C_Write (This, 16#608#, 16#0002#); + I2C_Write (This, WM8994_AIF1_ADC2_LMR, 16#0002#); -- Enable the DMIC2(Right) to AIF1 Timeslot 1 (Right) mixer path - I2C_Write (This, 16#609#, 16#0002#); + I2C_Write (This, WM8994_AIF1_ADC2_RMR, 16#0002#); -- GPIO1 pin configuration GP1_DIR = output, GP1_FN = AIF1 DRC2 -- signal detect - I2C_Write (This, 16#700#, 16#000E#); + I2C_Write (This, WM8994_GPIO1, 16#000E#); when Input_Line => -- Enable AIF1ADC1 (Left), Enable AIF1ADC1 (Right) -- Enable Left ADC, Enable Right ADC - I2C_Write (This, 16#04#, 16#0303#); + I2C_Write (This, WM8994_PWR_Management_4, 16#0303#); -- Enable AIF1 DRC1 Signal Detect & DRC in AIF1ADC1 Left/Right -- Timeslot 0 - I2C_Write (This, 16#440#, 16#00DB#); + I2C_Write (This, WM8994_AIF1_DRC1, 16#00DB#); -- Enable IN1L and IN1R, Disable IN2L and IN2R, Enable Thermal -- sensor & shutdown - I2C_Write (This, 16#02#, 16#6350#); + I2C_Write (This, WM8994_PWR_Management_4, 16#6350#); -- Enable the ADCL(Left) to AIF1 Timeslot 0 (Left) mixer path - I2C_Write (This, 16#606#, 16#0002#); + I2C_Write (This, WM8994_AIF1_ADC1_LMR, 16#0002#); -- Enable the ADCR(Right) to AIF1 Timeslot 0 (Right) mixer path - I2C_Write (This, 16#607#, 16#0002#); + I2C_Write (This, WM8994_AIF1_ADC1_RMR, 16#0002#); -- GPIO1 pin configuration GP1_DIR = output, GP1_FN = AIF1 DRC1 -- signal detect - I2C_Write (This, 16#700#, 16#000D#); + I2C_Write (This, WM8994_GPIO1, 16#000D#); end case; This.Set_Frequency (Frequency); -- AIF1 Word Length = 16-bits, AIF1 Format = I2S (Default Register -- Value) - I2C_Write (This, 16#300#, 16#4010#); + I2C_Write (This, WM8994_AIF1_Control1, 16#4010#); -- slave mode - I2C_Write (This, 16#302#, 16#0000#); + I2C_Write (This, WM8994_AIF1_Master_Slave, 16#0000#); -- Enable the DSP processing clock for AIF1, Enable the core clock - I2C_Write (This, 16#208#, 16#000A#); + I2C_Write (This, WM8994_Clocking1, 16#000A#); -- Enable AIF1 Clock, AIF1 Clock Source = MCLK1 pin - I2C_Write (This, 16#200#, 16#0001#); + I2C_Write (This, WM8994_AIF1_Clocking1, 16#0001#); if Output /= No_Output then -- Analog Output Configuration @@ -185,79 +134,79 @@ package body WM8994 is I2C_Write (This, 16#03#, 16#0300#); -- Left Speaker Mixer Volume = 0dB - I2C_Write (This, 16#22#, 16#0000#); + I2C_Write (This, WM8994_SPKMIXL_ATT, 16#0000#); -- Speaker output mode = Class D, Right Speaker Mixer Volume = 0dB -- ((16#23#, 16#0100#) = class AB) - I2C_Write (This, 16#23#, 16#0000#); + I2C_Write (This, WM8994_SPKMIXR_ATT, 16#0000#); -- Unmute DAC2 (Left) to Left Speaker Mixer (SPKMIXL) path, -- Unmute DAC2 (Right) to Right Speaker Mixer (SPKMIXR) path - I2C_Write (This, 16#36#, 16#0300#); + I2C_Write (This, WM8994_Speaker_Mixer, 16#0300#); -- Enable bias generator, Enable VMID, Enable SPKOUTL, Enable SPKOUTR - I2C_Write (This, 16#01#, 16#3003#); + I2C_Write (This, WM8994_PWR_Management_1, 16#3003#); -- Headphone/Speaker Enable -- Enable Class W, Class W Envelope Tracking = AIF1 Timeslot 0 - I2C_Write (This, 16#51#, 16#0001#); + I2C_Write (This, WM8994_CLASS_W, 16#0001#); -- Enable bias generator, Enable VMID, Enable HPOUT1 (Left) and -- Enable HPOUT1 (Right) input stages idem for Speaker Power_Mgnt_Reg_1 := Power_Mgnt_Reg_1 or 16#0303# or 16#3003#; - I2C_Write (This, 16#01#, Power_Mgnt_Reg_1); + I2C_Write (This, WM8994_PWR_Management_1, Power_Mgnt_Reg_1); -- Enable HPOUT1 (Left) and HPOUT1 (Right) intermediate stages - I2C_Write (This, 16#60#, 16#0022#); + I2C_Write (This, WM8994_Analog_HP, 16#0022#); -- Enable Charge Pump - I2C_Write (This, 16#4C#, 16#9F25#); + I2C_Write (This, WM8994_Charge_Pump1, 16#9F25#); -- Add Delay This.Time.Delay_Milliseconds (15); -- Select DAC1 (Left) to Left Headphone Output PGA (HPOUT1LVOL) path - I2C_Write (This, 16#2D#, 16#0001#); + I2C_Write (This, WM8994_Output_Mixer_1, 16#0001#); -- Select DAC1 (Right) to Right Headphone Output PGA (HPOUT1RVOL) -- path. - I2C_Write (This, 16#2E#, 16#0001#); + I2C_Write (This, WM8994_Output_Mixer_2, 16#0001#); -- Enable Left Output Mixer (MIXOUTL), Enable Right Output Mixer -- (MIXOUTR) idem for SPKOUTL and SPKOUTR. - I2C_Write (This, 16#03#, 16#0030# or 16#0300#); + I2C_Write (This, WM8994_PWR_Management_3, 16#0030# or 16#0300#); -- Enable DC Servo and trigger start-up mode on left and right -- channels. - I2C_Write (This, 16#54#, 16#0033#); + I2C_Write (This, WM8994_DC_Servo1, 16#0033#); -- Add Delay This.Time.Delay_Milliseconds (250); -- Enable HPOUT1 (Left) and HPOUT1 (Right) intermediate and output -- stages. Remove clamps. - I2C_Write (This, 16#60#, 16#00EE#); + I2C_Write (This, WM8994_Analog_HP, 16#00EE#); -- Unmutes -- Unmute DAC 1 (Left) - I2C_Write (This, 16#610#, 16#00C0#); + I2C_Write (This, WM8994_DAC1_Left_Vol, 16#00C0#); -- Unmute DAC 1 (Right) - I2C_Write (This, 16#611#, 16#00C0#); + I2C_Write (This, WM8994_DAC1_Right_Vol, 16#00C0#); -- Unmute the AIF1 Timeslot 0 DAC path - I2C_Write (This, 16#420#, 16#0000#); + I2C_Write (This, WM8994_AIF1_DAC1_Filter1, 16#0000#); -- Unmute DAC 2 (Left) - I2C_Write (This, 16#612#, 16#00C0#); + I2C_Write (This, WM8994_DAC2_Left_Vol, 16#00C0#); -- Unmute DAC 2 (Right) - I2C_Write (This, 16#613#, 16#00C0#); + I2C_Write (This, WM8994_DAC2_Right_Vol, 16#00C0#); -- Unmute the AIF1 Timeslot 1 DAC2 path - I2C_Write (This, 16#422#, 16#0000#); + I2C_Write (This, WM8994_AIF1_DAC2_Filter1, 16#0000#); -- Volume Control This.Set_Volume (Volume); @@ -267,36 +216,36 @@ package body WM8994 is if Input = Microphone then -- Enable Microphone bias 1 generator, Enable VMID Power_Mgnt_Reg_1 := Power_Mgnt_Reg_1 or 16#0013#; - I2C_Write (This, 16#01#, Power_Mgnt_Reg_1); + I2C_Write (This, WM8994_PWR_Management_1, Power_Mgnt_Reg_1); -- ADC oversample enable - I2C_Write (This, 16#620#, 16#0002#); + I2C_Write (This, WM8994_Oversampling, 16#0002#); -- AIF ADC2 HPF enable, HPF cut = voice mode 1 fc=127Hz at fs=8kHz - I2C_Write (This, 16#411#, 16#3800#); + I2C_Write (This, WM8994_AIF1_ADC2_Filters, 16#3800#); elsif Input = Input_Line then -- Enable normal bias generator, Enable VMID Power_Mgnt_Reg_1 := Power_Mgnt_Reg_1 or 16#0003#; - I2C_Write (This, 16#01#, Power_Mgnt_Reg_1); + I2C_Write (This, WM8994_PWR_Management_1, Power_Mgnt_Reg_1); -- Disable mute on IN1L, IN1L Volume = +0dB - I2C_Write (This, 16#18#, 16#000B#); + I2C_Write (This, WM8994_Left_Line_In12_Vol, 16#000B#); -- Disable mute on IN1R, IN1R Volume = +0dB - I2C_Write (This, 16#1A#, 16#000B#); + I2C_Write (This, WM8994_Right_Line_In12_Vol, 16#000B#); -- Disable mute on IN1L_TO_MIXINL, Gain = +0dB - I2C_Write (This, 16#29#, 16#0025#); + I2C_Write (This, WM8994_Input_Mixer_3, 16#0025#); -- Disable mute on IN1R_TO_MIXINL, Gain = +0dB - I2C_Write (This, 16#2A#, 16#0025#); + I2C_Write (This, WM8994_Input_Mixer_4, 16#0025#); -- IN1LN_TO_IN1L, IN1LP_TO_VMID, IN1RN_TO_IN1R, IN1RP_TO_VMID - I2C_Write (This, 16#28#, 16#0011#); + I2C_Write (This, WM8994_Input_Mixer_2, 16#0011#); -- AIF ADC1 HPF enable, HPF cut = hifi mode fc=4Hz at fs=48kHz - I2C_Write (This, 16#410#, 16#1800#); + I2C_Write (This, WM8994_AIF1_ADC1_Filters, 16#1800#); end if; -- Volume Control @@ -310,7 +259,7 @@ package body WM8994 is function Chip_ID (This : in out WM8994_Device) return UInt16 is begin - return This.I2C_Read (WM8994_CHIPID_ADDR); + return I2C_Read (This, WM8994_CHIPID_ADDR); end Chip_ID; ---------- @@ -332,7 +281,7 @@ package body WM8994 is This.Set_Mute (Mute_On); -- CODEC in powersave mode - I2C_Write (This, 16#02#, 16#01#); + I2C_Write (This, WM8994_PWR_Management_2, 16#01#); end Pause; ------------ @@ -361,22 +310,22 @@ package body WM8994 is Output_Enabled := False; -- Mute the AIF1 Timeslot 0 DAC1 path - I2C_Write (This, 16#420#, 16#0200#); + I2C_Write (This, WM8994_AIF1_DAC1_Filter1, 16#0200#); -- Mute the AIF1 Timeslot 1 DAC2 path - I2C_Write (This, 16#422#, 16#0200#); + I2C_Write (This, WM8994_AIF1_DAC2_Filter1, 16#0200#); -- Disable DAC1L_TO_HPOUT1L - I2C_Write (This, 16#2D#, 16#0000#); + I2C_Write (This, WM8994_Output_Mixer_1, 16#0000#); -- Disable DAC1R_TO_HPOUT1R - I2C_Write (This, 16#2E#, 16#0000#); + I2C_Write (This, WM8994_Output_Mixer_2, 16#0000#); -- Disable DAC1 and DAC2 - I2C_Write (This, 16#05#, 16#0000#); + I2C_Write (This, WM8994_PWR_Management_5, 16#0000#); - -- Reset Codec by writing in 16#0000 address register - I2C_Write (This, 16#0000#, 16#0000#); + -- Reset Codec + I2C_Write (This, WM8994_SW_Reset, 16#0000#); end if; end Stop; @@ -396,16 +345,16 @@ package body WM8994 is This.Set_Mute (Mute_Off); -- Left Headphone Volume - I2C_Write (This, 16#1C#, Volume or 16#140#); + I2C_Write (This, WM8994_Left_Output_Vol, Volume or 16#140#); -- Right Headphone volume - I2C_Write (This, 16#1D#, Volume or 16#140#); + I2C_Write (This, WM8994_Right_Output_Vol, Volume or 16#140#); -- Left Speaker volume - I2C_Write (This, 16#26#, Volume or 16#140#); + I2C_Write (This, WM8994_SPK_Left_Vol, Volume or 16#140#); -- Right Speaker volume - I2C_Write (This, 16#27#, Volume or 16#140#); + I2C_Write (This, WM8994_SPK_Right_Vol, Volume or 16#140#); end if; end Set_Volume; @@ -419,14 +368,14 @@ package body WM8994 is case Cmd is when Mute_On => -- Soft Mute the AIF1 Timeslot 0 DAC1 path L&R - I2C_Write (This, 16#420#, 16#0200#); + I2C_Write (This, WM8994_AIF1_DAC1_Filter1, 16#0200#); -- Soft Mute the AIF1 Timeslot 1 DAC2 path L&R - I2C_Write (This, 16#422#, 16#0200#); + I2C_Write (This, WM8994_AIF1_DAC2_Filter1, 16#0200#); when Mute_Off => -- Unmute the AIF1 Timeslot 0 DAC1 path L&R - I2C_Write (This, 16#420#, 16#0000#); + I2C_Write (This, WM8994_AIF1_DAC1_Filter1, 16#0000#); -- Unmute the AIF1 Timeslot 1 DAC2 path L&R - I2C_Write (This, 16#422#, 16#0000#); + I2C_Write (This, WM8994_AIF1_DAC2_Filter1, 16#0000#); end case; end if; end Set_Mute; @@ -443,49 +392,49 @@ package body WM8994 is case Device is when No_Output => -- Disable DAC1 (left), DAC1 (Right) - I2C_Write (This, 16#05#, 16#0000#); + I2C_Write (This, WM8994_PWR_Management_5, 16#0000#); -- Mute the AIF1 Timeslot 0 DAC1 path - I2C_Write (This, 16#420#, 16#0200#); + I2C_Write (This, WM8994_AIF1_DAC1_Filter1, 16#0200#); -- Mute the AIF1 Timeslot 1 DAC2 path - I2C_Write (This, 16#422#, 16#0200#); + I2C_Write (This, WM8994_AIF1_DAC2_Filter1, 16#0200#); when Speaker => -- Enable DAC1 (left), DAC1 (Right) - I2C_Write (This, 16#05#, 16#0C0C#); + I2C_Write (This, WM8994_PWR_Management_5, 16#0C0C#); -- Enable the AIF1 Timeslot 0 (Left) to DAC1 (left) mixer path - I2C_Write (This, 16#601#, 16#0000#); + I2C_Write (This, WM8994_AIF1_DAC1_LMR, 16#0000#); -- Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path - I2C_Write (This, 16#602#, 16#0000#); + I2C_Write (This, WM8994_AIF1_DAC1_RMR, 16#0000#); -- Disable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path - I2C_Write (This, 16#604#, 16#0002#); + I2C_Write (This, WM8994_AIF1_DAC2_LMR, 16#0002#); -- Disable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path - I2C_Write (This, 16#605#, 16#0002#); + I2C_Write (This, WM8994_AIF1_DAC2_RMR, 16#0002#); when Headphone | Auto => -- Disable DAC1 (left), DAC1 (Right) -- Enable DAC2 (left), DAC2 (Right) - I2C_Write (This, 16#05#, 16#0303#); + I2C_Write (This, WM8994_PWR_Management_5, 16#0303#); -- Enable the AIF1 Timeslot 0 (Left) to DAC1 (left) mixer path - I2C_Write (This, 16#601#, 16#0001#); + I2C_Write (This, WM8994_AIF1_DAC1_LMR, 16#0001#); -- Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path - I2C_Write (This, 16#602#, 16#0001#); + I2C_Write (This, WM8994_AIF1_DAC1_RMR, 16#0001#); -- Disable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path - I2C_Write (This, 16#604#, 16#0000#); + I2C_Write (This, WM8994_AIF1_DAC2_LMR, 16#0000#); -- Disable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path - I2C_Write (This, 16#605#, 16#0000#); + I2C_Write (This, WM8994_AIF1_DAC2_RMR, 16#0000#); when Both => -- Enable DAC1 (left), DAC1 (Right) -- Enable DAC2 (left), DAC2 (Right) - I2C_Write (This, 16#05#, 16#0303# or 16#0C0C#); + I2C_Write (This, WM8994_PWR_Management_5, 16#0303# or 16#0C0C#); -- Enable the AIF1 Timeslot 0 (Left) to DAC1 (left) mixer path - I2C_Write (This, 16#601#, 16#0001#); + I2C_Write (This, WM8994_AIF1_DAC1_LMR, 16#0001#); -- Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path - I2C_Write (This, 16#602#, 16#0001#); + I2C_Write (This, WM8994_AIF1_DAC1_RMR, 16#0001#); -- Enable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path - I2C_Write (This, 16#604#, 16#0002#); + I2C_Write (This, WM8994_AIF1_DAC2_LMR, 16#0002#); -- Enable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path - I2C_Write (This, 16#605#, 16#0002#); + I2C_Write (This, WM8994_AIF1_DAC2_RMR, 16#0002#); end case; end Set_Output_Mode; @@ -508,47 +457,47 @@ package body WM8994 is case Freq is when Audio_Freq_8kHz => -- AIF1 Sample Rate = 8 (kHz), ratio=256 - I2C_Write (This, 16#210#, 16#0003#); + I2C_Write (This, WM8994_AIF1_Rate, 16#0003#); when Audio_Freq_11kHz => -- AIF1 Sample Rate = 11.025 (kHz), ratio=256 - I2C_Write (This, 16#210#, 16#0013#); + I2C_Write (This, WM8994_AIF1_Rate, 16#0013#); when Audio_Freq_12kHz => -- AIF1 Sample Rate = 12 (kHz), ratio=256 - I2C_Write (This, 16#210#, 16#0023#); + I2C_Write (This, WM8994_AIF1_Rate, 16#0023#); when Audio_Freq_16kHz => -- AIF1 Sample Rate = 16 (kHz), ratio=256 - I2C_Write (This, 16#210#, 16#0033#); + I2C_Write (This, WM8994_AIF1_Rate, 16#0033#); when Audio_Freq_22kHz => -- AIF1 Sample Rate = 22.050 (kHz), ratio=256 - I2C_Write (This, 16#210#, 16#0043#); + I2C_Write (This, WM8994_AIF1_Rate, 16#0043#); when Audio_Freq_24kHz => -- AIF1 Sample Rate = 24 (kHz), ratio=256 - I2C_Write (This, 16#210#, 16#0053#); + I2C_Write (This, WM8994_AIF1_Rate, 16#0053#); when Audio_Freq_32kHz => -- AIF1 Sample Rate = 32 (kHz), ratio=256 - I2C_Write (This, 16#210#, 16#0063#); + I2C_Write (This, WM8994_AIF1_Rate, 16#0063#); when Audio_Freq_44kHz => -- AIF1 Sample Rate = 44.1 (kHz), ratio=256 - I2C_Write (This, 16#210#, 16#0073#); + I2C_Write (This, WM8994_AIF1_Rate, 16#0073#); when Audio_Freq_48kHz => -- AIF1 Sample Rate = 48 (kHz), ratio=256 - I2C_Write (This, 16#210#, 16#0083#); + I2C_Write (This, WM8994_AIF1_Rate, 16#0083#); when Audio_Freq_88kHz => -- AIF1 Sample Rate = 88.2 (kHz), ratio=256 - I2C_Write (This, 16#210#, 16#0093#); + I2C_Write (This, WM8994_AIF1_Rate, 16#0093#); when Audio_Freq_96kHz => -- AIF1 Sample Rate = 96 (kHz), ratio=256 - I2C_Write (This, 16#210#, 16#00A3#); + I2C_Write (This, WM8994_AIF1_Rate, 16#00A3#); end case; end Set_Frequency; @@ -558,7 +507,7 @@ package body WM8994 is procedure Reset (This : in out WM8994_Device) is begin - I2C_Write (This, 16#0000#, 16#0000#); + I2C_Write (This, WM8994_SW_Reset, 16#0000#); Output_Enabled := False; Input_Enabled := False; end Reset; diff --git a/components/src/audio/W8994/wm8994.ads b/components/src/audio/W8994/wm8994.ads index 1fd3211d1..fdf28d581 100644 --- a/components/src/audio/W8994/wm8994.ads +++ b/components/src/audio/W8994/wm8994.ads @@ -152,12 +152,4 @@ private Time : not null HAL.Time.Any_Delays) is tagged limited null record; - procedure I2C_Write (This : in out WM8994_Device; - Register : UInt16; - Value : UInt16); - - function I2C_Read (This : in out WM8994_Device; - Register : UInt16) - return UInt16; - end WM8994; From a660c65c1c762d7901f816c2d908a6800d227bae Mon Sep 17 00:00:00 2001 From: Pat Rogers Date: Thu, 28 Mar 2024 09:23:43 -0500 Subject: [PATCH 03/18] better name for procedure Play much commenting --- boards/stm32_common/stm32f746disco/audio.adb | 10 ++--- boards/stm32_common/stm32f746disco/audio.ads | 43 ++++++++++++++------ 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/boards/stm32_common/stm32f746disco/audio.adb b/boards/stm32_common/stm32f746disco/audio.adb index 23f69cfe7..0a85dad15 100644 --- a/boards/stm32_common/stm32f746disco/audio.adb +++ b/boards/stm32_common/stm32f746disco/audio.adb @@ -290,11 +290,11 @@ package body Audio is Clock_Speed => 100_000); end Initialize_Audio_I2C; - ---------- - -- Play -- - ---------- + ------------------- + -- Start_Playing -- + ------------------- - procedure Play + procedure Start_Playing (This : in out WM8994_Audio_Device; Buffer : Audio_Buffer) is @@ -316,7 +316,7 @@ package body Audio is if not Enabled (Audio_SAI, SAI_Out_Block) then Enable (Audio_SAI, SAI_Out_Block); end if; - end Play; + end Start_Playing; ----------- -- Pause -- diff --git a/boards/stm32_common/stm32f746disco/audio.ads b/boards/stm32_common/stm32f746disco/audio.ads index 07f578c59..4ccdf1eb8 100644 --- a/boards/stm32_common/stm32f746disco/audio.ads +++ b/boards/stm32_common/stm32f746disco/audio.ads @@ -44,7 +44,7 @@ package Audio is type WM8994_Audio_Device (Port : not null Any_I2C_Port) is tagged limited private; - type Audio_Output_Device is new WM8994.Output_Device + type Audio_Output_Device is new WM8994.Output_Device range WM8994.Speaker .. WM8994.Auto; -- Only No_Output is not included @@ -57,34 +57,53 @@ package Audio is type Audio_Buffer is array (Natural range <>) of UInt16 with Component_Size => 16, Alignment => 2; -- TODO: change to signed 16-bit, since that's apparently what should be used for PCM samples, - -- so revert the change to HAL.Audio.Audio_Buffer (so it is INteger_16 again) and use that. + -- so revert the change to HAL.Audio.Audio_Buffer (so it is Integer_16 again) and use that. procedure Initialize (This : in out WM8994_Audio_Device; Volume : Audio_Volume; Frequency : Audio_Frequency; Sink : Audio_Output_Device); + -- This routine initializes the hardware and configures the volume, + -- sampling frequency, and output device (the sink). This routine must be + -- called, before any others. The routines for setting the volume and + -- the output frequency are optional. - procedure Set_Volume - (This : in out WM8994_Audio_Device; - Volume : Audio_Volume); - - procedure Set_Frequency - (This : in out WM8994_Audio_Device; - Frequency : Audio_Frequency); - - procedure Play + procedure Start_Playing (This : in out WM8994_Audio_Device; Buffer : Audio_Buffer); + -- Start playing, for the first time, content from the audio file/stream. + -- This routine must be called, perhaps just once but more than once if the + -- other routines below are called. The effect is to tell the underlying + -- WM8994 codec where the buffer to be played is located, and cause the + -- codec to start playing that buffer. Playing continues after the call + -- returns. An additional mechanism, outside this package, updates the + -- content of the buffer while the codec is playing it. That update/play + -- process continues until either there is no more music to be played, or + -- Stop or Pause is called. procedure Pause (This : in out WM8994_Audio_Device); + -- After calling Pause, only Resume should be called for resuming play (do + -- not call Start_Playing again). procedure Resume (This : in out WM8994_Audio_Device); + -- Procedure Resume should be called only when the audio is playing or + -- paused (not stopped). procedure Stop (This : in out WM8994_Audio_Device); + -- Stops the hardware and update/play process. Once called, you must call + -- Start_Playing again if you want to restart the output. + + procedure Set_Volume + (This : in out WM8994_Audio_Device; + Volume : Audio_Volume); + + procedure Set_Frequency + (This : in out WM8994_Audio_Device; + Frequency : Audio_Frequency); private @@ -94,7 +113,7 @@ private (Port : not null Any_I2C_Port) is tagged limited record Device : WM8994.WM8994_Device (Port, Audio_I2C_Addr, Ravenscar_Time.Delays); - Sink : Audio_Output_Device; + Sink : Audio_Output_Device := No_Output; end record; end Audio; From 264a39bfca9f4a0f2ef2af1493ac5874870b58d1 Mon Sep 17 00:00:00 2001 From: Pat Rogers Date: Thu, 28 Mar 2024 10:00:56 -0500 Subject: [PATCH 04/18] Move to signed 16-bit PCM samples, rather than unsigned --- boards/stm32_common/stm32f746disco/audio.ads | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/boards/stm32_common/stm32f746disco/audio.ads b/boards/stm32_common/stm32f746disco/audio.ads index 4ccdf1eb8..5b8dd2ab3 100644 --- a/boards/stm32_common/stm32f746disco/audio.ads +++ b/boards/stm32_common/stm32f746disco/audio.ads @@ -1,6 +1,6 @@ ------------------------------------------------------------------------------ -- -- --- Copyright (C) 2016, AdaCore -- +-- Copyright (C) 2016-2024, AdaCore -- -- -- -- Redistribution and use in source and binary forms, with or without -- -- modification, are permitted provided that the following conditions are -- @@ -32,10 +32,10 @@ -- @author MCD Application Team -- ------------------------------------------------------------------------------ --- with HAL.Audio; use HAL.Audio; -with HAL; use HAL; +with HAL; use HAL; with HAL.I2C; use HAL.I2C; with Ravenscar_Time; +with Interfaces; use Interfaces; with WM8994; @@ -49,15 +49,11 @@ package Audio is -- Only No_Output is not included type Audio_Frequency is new WM8994.Audio_Frequency; - -- TODO: use HAL.Audio package's type, with WM8994 additions to that type type Audio_Volume is range 0 .. 100; -- a percentage - -- TODO: use HAL.Audio package's type - type Audio_Buffer is array (Natural range <>) of UInt16 + type Audio_Buffer is array (Natural range <>) of Integer_16 with Component_Size => 16, Alignment => 2; - -- TODO: change to signed 16-bit, since that's apparently what should be used for PCM samples, - -- so revert the change to HAL.Audio.Audio_Buffer (so it is Integer_16 again) and use that. procedure Initialize (This : in out WM8994_Audio_Device; @@ -113,7 +109,7 @@ private (Port : not null Any_I2C_Port) is tagged limited record Device : WM8994.WM8994_Device (Port, Audio_I2C_Addr, Ravenscar_Time.Delays); - Sink : Audio_Output_Device := No_Output; + Sink : Audio_Output_Device; -- := No_Output; -- TODO... end record; end Audio; From b72118a99a2f0b1a7512d554fc85bca052e3f0a2 Mon Sep 17 00:00:00 2001 From: Pat Rogers Date: Thu, 28 Mar 2024 10:45:19 -0500 Subject: [PATCH 05/18] Add important comments re: mystery code and update copyright year * Document the fact (in comments) that the "Errata work-arounds" are completely mysterious. * update copyright year * Add comment for entire unit at top --- components/src/audio/W8994/wm8994.adb | 7 +++++-- components/src/audio/W8994/wm8994.ads | 22 ++++++++++------------ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/components/src/audio/W8994/wm8994.adb b/components/src/audio/W8994/wm8994.adb index 6c33279bb..8d2c1fdd8 100644 --- a/components/src/audio/W8994/wm8994.adb +++ b/components/src/audio/W8994/wm8994.adb @@ -51,8 +51,11 @@ package body WM8994 is is Power_Mgnt_Reg_1 : UInt16 := 0; begin - -- WM8994 Errata work-arounds. - -- See https://github.com/STMicroelectronics/stm32-wm8994/blob/main/wm8994.c + -- WM8994 Errata work-arounds. See + -- https://github.com/STMicroelectronics/stm32-wm8994/blob/main/wm8994.c + -- These registers are not documented, and the effects of these writes + -- are not documented anywhere either. Nobody seems to have written it + -- down anywhere. I2C_Write (This, 16#102#, 16#0003#); I2C_Write (This, 16#817#, 16#0000#); I2C_Write (This, 16#102#, 16#0000#); diff --git a/components/src/audio/W8994/wm8994.ads b/components/src/audio/W8994/wm8994.ads index fdf28d581..eaa7a8a9f 100644 --- a/components/src/audio/W8994/wm8994.ads +++ b/components/src/audio/W8994/wm8994.ads @@ -1,6 +1,6 @@ ------------------------------------------------------------------------------ -- -- --- Copyright (C) 2015-2016, AdaCore -- +-- Copyright (C) 2015-2024, AdaCore -- -- -- -- Redistribution and use in source and binary forms, with or without -- -- modification, are permitted provided that the following conditions are -- @@ -29,7 +29,8 @@ -- -- ------------------------------------------------------------------------------ --- Driver for the WM8994 CODEC +-- This package provides a simple driver for the WM8994 CODEC. It does not +-- provide a full definition of the WM8994's functionality. with HAL; use HAL; with HAL.I2C; use HAL.I2C; @@ -87,23 +88,20 @@ package WM8994 is Audio_Freq_88kHz => 88_200, Audio_Freq_96kHz => 96_000); - -- TODO: support 24K and 32K frequencies - type Mute is (Mute_On, Mute_Off); type Stop_Mode is (Stop_Power_Down_Sw, + -- Stop_Power_Down_Sw only mutes the audio codec, it does not alter + -- hardware settings. When resuming from this mode the codec keeps the + -- previous initialization so there is no need to re-initialize the + -- codec registers. Stop_Power_Down_Hw); - -- Stop_Power_Down_Sw: - -- only mutes the audio codec. When resuming from this mode the codec - -- keeps the previous initialization (no need to re-Initialize the codec - -- registers). - -- Stop_Power_Down_Hw: - -- Physically power down the codec. When resuming from this mode, the codec - -- is set to default configuration (user should re-Initialize the codec in - -- order to play again the audio stream). + -- Stop_Power_Down_Hw physically powers down the codec hardware. When + -- resuming from this mode, the codec is set to default configuration + -- so users should re-initialize the codec. Max_Volume : constant := 16#3F#; From 5b053204efae37bb346fd4356ad497c008cc9ba7 Mon Sep 17 00:00:00 2001 From: Pat Rogers Date: Thu, 28 Mar 2024 16:49:33 -0500 Subject: [PATCH 06/18] Make the output device type use a static predicate to limit the options Otherwise, as a range constraint, the result would be order-dependent on the parent type. Now use No_Output for the default value of the Output record component, to check for lack of a prior call to Initialize. --- boards/stm32_common/stm32f746disco/audio.adb | 13 +++++--- boards/stm32_common/stm32f746disco/audio.ads | 32 ++++++++++++++------ 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/boards/stm32_common/stm32f746disco/audio.adb b/boards/stm32_common/stm32f746disco/audio.adb index 0a85dad15..75d2d4ffd 100644 --- a/boards/stm32_common/stm32f746disco/audio.adb +++ b/boards/stm32_common/stm32f746disco/audio.adb @@ -84,11 +84,9 @@ package body Audio is Set_Audio_Clock (Frequency); - -- Initialize the SAI Initialize_Audio_Out_Pins; Initialize_Audio_DMA; Initialize_SAI_Out (Frequency, Sink); - Initialize_Audio_I2C; if This.Device.Chip_ID /= WM8994.WM8994_ID then @@ -102,7 +100,7 @@ package body Audio is Volume => As_Device_Volume (Volume), Frequency => WM8994.Audio_Frequency (Frequency)); - This.Sink := Sink; + This.Output := WM8994.Output_Device (Sink); -- For sake of any individual calls to Set_Frequency, assuming the STM -- code is correct that we also need to set the clocks when setting the -- frequency @@ -128,7 +126,12 @@ package body Audio is (This : in out WM8994_Audio_Device; Frequency : Audio_Frequency) is + use type WM8994.Output_Device; begin + if This.Output = WM8994.No_Output then + raise Constraint_Error with "No prior call to Initialize"; + end if; + -- The following is per the example source file from STM, -- STM32746G-Disco_example\board_drivers\stm32746g_discovery_audio.c, -- whereas the WM8894 driver just has a specific function that writes @@ -136,7 +139,7 @@ package body Audio is -- clock configuration too. Set_Audio_Clock (Frequency); STM32.SAI.Disable (Audio_SAI, SAI_Out_Block); - Initialize_SAI_Out (Frequency, This.Sink); + Initialize_SAI_Out (Frequency, Audio_Output_Device (This.Output)); STM32.SAI.Enable (Audio_SAI, SAI_Out_Block); end Set_Frequency; @@ -257,7 +260,7 @@ package body Audio is FS_Offset => Before_First_Bit); case Sink is - when Headphone | Auto => + when Headphone => Active_Slots := Slot_0 or Slot_2; when Speaker => Active_Slots := Slot_1 or Slot_3; diff --git a/boards/stm32_common/stm32f746disco/audio.ads b/boards/stm32_common/stm32f746disco/audio.ads index 5b8dd2ab3..2054e5d39 100644 --- a/boards/stm32_common/stm32f746disco/audio.ads +++ b/boards/stm32_common/stm32f746disco/audio.ads @@ -44,9 +44,9 @@ package Audio is type WM8994_Audio_Device (Port : not null Any_I2C_Port) is tagged limited private; - type Audio_Output_Device is new WM8994.Output_Device - range WM8994.Speaker .. WM8994.Auto; - -- Only No_Output is not included + type Audio_Output_Device is new WM8994.Output_Device with + Static_Predicate => Audio_Output_Device in + Headphone | Speaker | Both; type Audio_Frequency is new WM8994.Audio_Frequency; @@ -68,15 +68,16 @@ package Audio is procedure Start_Playing (This : in out WM8994_Audio_Device; Buffer : Audio_Buffer); - -- Start playing, for the first time, content from the audio file/stream. + -- Start playing, for the first time, content from the specified buffer. -- This routine must be called, perhaps just once but more than once if the -- other routines below are called. The effect is to tell the underlying -- WM8994 codec where the buffer to be played is located, and cause the - -- codec to start playing that buffer. Playing continues after the call - -- returns. An additional mechanism, outside this package, updates the - -- content of the buffer while the codec is playing it. That update/play - -- process continues until either there is no more music to be played, or - -- Stop or Pause is called. + -- codec to start playing the contents. + -- + -- NB: playing continues after the call returns. An additional mechanism, + -- outside this package, updates the content of the buffer while the codec + -- is playing it. That update/play process continues until either there is + -- no more music to be played, or Stop or Pause is called. procedure Pause (This : in out WM8994_Audio_Device); @@ -109,7 +110,18 @@ private (Port : not null Any_I2C_Port) is tagged limited record Device : WM8994.WM8994_Device (Port, Audio_I2C_Addr, Ravenscar_Time.Delays); - Sink : Audio_Output_Device; -- := No_Output; -- TODO... + Output : WM8994.Output_Device := WM8994.No_Output; + -- The initial value of Output is overwritten by Initialize. The value + -- No_Output will trigger a C_E if ever referenced, so it is used as a + -- check that Initialize has been called. We need the component Output + -- itself for the sake of a clean parameter profile for Set_Frequency, + -- otherwise clients would have to pass another parameter to specify + -- the output device selection again (after having done so when calling + -- Initialize). That's because Set_Frequency needs to do enough hardware + -- re-initialization to accommodate the new frequency, but doing so + -- requires the output device selection so that the re-init can select + -- the active slots. Just activating all slots (as is done in the STM + -- C code) doesn't work (at least in the current Ada code). end record; end Audio; From 01a10646422b9ec749df8534905729f75ade7637 Mon Sep 17 00:00:00 2001 From: Pat Rogers Date: Sat, 21 Mar 2026 15:42:24 -0500 Subject: [PATCH 07/18] Add support for dual channel conversion --- arch/ARM/STM32/drivers/stm32-dac.adb | 89 +++++++++++++++++++++------- arch/ARM/STM32/drivers/stm32-dac.ads | 32 +++++++++- 2 files changed, 96 insertions(+), 25 deletions(-) diff --git a/arch/ARM/STM32/drivers/stm32-dac.adb b/arch/ARM/STM32/drivers/stm32-dac.adb index 390be52ff..60d50d140 100644 --- a/arch/ARM/STM32/drivers/stm32-dac.adb +++ b/arch/ARM/STM32/drivers/stm32-dac.adb @@ -1,6 +1,6 @@ ------------------------------------------------------------------------------ -- -- --- Copyright (C) 2015, AdaCore -- +-- Copyright (C) 2015-2026, AdaCore -- -- -- -- Redistribution and use in source and binary forms, with or without -- -- modification, are permitted provided that the following conditions are -- @@ -115,11 +115,9 @@ package body STM32.DAC is when DAC_Resolution_12_Bits => case Alignment is when Left_Aligned => - This.DHR12L1.DACC1DHR := - UInt12 (Value and Max_12bit_Resolution); + This.DHR12L1.DACC1DHR := UInt12 (Value and Max_12bit_Resolution); when Right_Aligned => - This.DHR12R1.DACC1DHR := - UInt12 (Value and Max_12bit_Resolution); + This.DHR12R1.DACC1DHR := UInt12 (Value and Max_12bit_Resolution); end case; when DAC_Resolution_8_Bits => This.DHR8R1.DACC1DHR := UInt8 (Value and Max_8bit_Resolution); @@ -130,11 +128,9 @@ package body STM32.DAC is when DAC_Resolution_12_Bits => case Alignment is when Left_Aligned => - This.DHR12L2.DACC2DHR := - UInt12 (Value and Max_12bit_Resolution); + This.DHR12L2.DACC2DHR := UInt12 (Value and Max_12bit_Resolution); when Right_Aligned => - This.DHR12R2.DACC2DHR := - UInt12 (Value and Max_12bit_Resolution); + This.DHR12R2.DACC2DHR := UInt12 (Value and Max_12bit_Resolution); end case; when DAC_Resolution_8_Bits => This.DHR8R2.DACC2DHR := UInt8 (Value and Max_8bit_Resolution); @@ -143,6 +139,35 @@ package body STM32.DAC is end case; end Set_Output; + ----------------------------- + -- Set_Dual_Channel_Output -- + ----------------------------- + + procedure Set_Dual_Channel_Output + (This : in out Digital_To_Analog_Converter; + Channel_2_Data : UInt16; + Channel_1_Data : UInt16; + Resolution : DAC_Resolution; + Alignment : Data_Alignment) + is + begin + -- See RM0385 Rev 8, sections 16.5.9 .. 16.5.11 for these registers + case Resolution is + when DAC_Resolution_12_Bits => + case Alignment is + when Left_Aligned => + This.DHR12LD.DACC2DHR := UInt12 (Channel_2_Data and Max_12bit_Resolution); + This.DHR12LD.DACC1DHR := UInt12 (Channel_1_Data and Max_12bit_Resolution); + when Right_Aligned => + This.DHR12RD.DACC2DHR := UInt12 (Channel_2_Data and Max_12bit_Resolution); + This.DHR12RD.DACC1DHR := UInt12 (Channel_1_Data and Max_12bit_Resolution); + end case; + when DAC_Resolution_8_Bits => + This.DHR8RD.DACC2DHR := UInt8 (Channel_2_Data and Max_8bit_Resolution); + This.DHR8RD.DACC1DHR := UInt8 (Channel_1_Data and Max_8bit_Resolution); + end case; + end Set_Dual_Channel_Output; + ------------------------------------ -- Trigger_Conversion_By_Software -- ------------------------------------ @@ -194,21 +219,15 @@ package body STM32.DAC is when DAC_Resolution_12_Bits => case Alignment is when Left_Aligned => - This.DHR12LD.DACC1DHR := - UInt12 (Channel_1_Value and Max_12bit_Resolution); - This.DHR12LD.DACC2DHR := - UInt12 (Channel_2_Value and Max_12bit_Resolution); + This.DHR12LD.DACC1DHR := UInt12 (Channel_1_Value and Max_12bit_Resolution); + This.DHR12LD.DACC2DHR := UInt12 (Channel_2_Value and Max_12bit_Resolution); when Right_Aligned => - This.DHR12RD.DACC1DHR := - UInt12 (Channel_1_Value and Max_12bit_Resolution); - This.DHR12RD.DACC2DHR := - UInt12 (Channel_2_Value and Max_12bit_Resolution); + This.DHR12RD.DACC1DHR := UInt12 (Channel_1_Value and Max_12bit_Resolution); + This.DHR12RD.DACC2DHR := UInt12 (Channel_2_Value and Max_12bit_Resolution); end case; when DAC_Resolution_8_Bits => - This.DHR8RD.DACC1DHR := - UInt8 (Channel_1_Value and Max_8bit_Resolution); - This.DHR8RD.DACC2DHR := - UInt8 (Channel_2_Value and Max_8bit_Resolution); + This.DHR8RD.DACC1DHR := UInt8 (Channel_1_Value and Max_8bit_Resolution); + This.DHR8RD.DACC2DHR := UInt8 (Channel_2_Value and Max_8bit_Resolution); end case; end Set_Dual_Output_Voltages; @@ -682,10 +701,36 @@ package body STM32.DAC is when DAC_Resolution_8_Bits => Result := This.DHR8R2'Address; end case; - end case; return Result; end Data_Address; + ---------------------------------- + -- Data_Address_Dual_Conversion -- + ---------------------------------- + + function Data_Address_Dual_Conversion + (This : Digital_To_Analog_Converter; + Resolution : DAC_Resolution; + Alignment : Data_Alignment) + return Address + is + Result : Address; + begin + case Resolution is + when DAC_Resolution_12_Bits => + case Alignment is + when Left_Aligned => + Result := This.DHR12LD'Address; + when Right_Aligned => + Result := This.DHR12RD'Address; + end case; + when DAC_Resolution_8_Bits => + Result := This.DHR8RD'Address; + end case; + + return Result; + end Data_Address_Dual_Conversion; + end STM32.DAC; diff --git a/arch/ARM/STM32/drivers/stm32-dac.ads b/arch/ARM/STM32/drivers/stm32-dac.ads index dcaccb354..41f41a549 100644 --- a/arch/ARM/STM32/drivers/stm32-dac.ads +++ b/arch/ARM/STM32/drivers/stm32-dac.ads @@ -1,6 +1,6 @@ ------------------------------------------------------------------------------ -- -- --- Copyright (C) 2015, AdaCore -- +-- Copyright (C) 2015-2026, AdaCore -- -- -- -- Redistribution and use in source and binary forms, with or without -- -- modification, are permitted provided that the following conditions are -- @@ -51,7 +51,9 @@ package STM32.DAC is type DAC_Channel is (Channel_1, Channel_2); - -- Note that Channel 1 is tied to GPIO pin PA4, and Channel 2 to PA5 + -- Note that Channel 1 is tied to GPIO pin PA4, and Channel 2 to PA5. + -- Note that Channel 1 is mapped to DMA1 Stream 5 channel 7. + -- Note that Channel 2 is mapped on DMA1 Stream 6 channel 7. procedure Enable (This : in out Digital_To_Analog_Converter; @@ -88,6 +90,8 @@ package STM32.DAC is Max_8bit_Resolution : constant := 16#00FF#; type Data_Alignment is (Left_Aligned, Right_Aligned); + -- These only apply when using 12-bit resolution. For 8-bit resolution the + -- alignment is always right-aligned. procedure Set_Output (This : in out Digital_To_Analog_Converter; @@ -102,6 +106,18 @@ package STM32.DAC is -- the reference input voltage and the 'n' of Max_nbit_Counts is either 12 -- or 8. + procedure Set_Dual_Channel_Output + (This : in out Digital_To_Analog_Converter; + Channel_2_Data : UInt16; + Channel_1_Data : UInt16; + Resolution : DAC_Resolution; + Alignment : Data_Alignment); + -- This routine writes the 32-bit value, composed from the two 16-bit + -- values, with the necessary layout (8/12left-right alignment) to + -- the appropriate output register for conversion on both channels + -- simultaneously. DMA is the alternative to software calling this + -- procedure. + procedure Trigger_Conversion_By_Software (This : in out Digital_To_Analog_Converter; Channel : DAC_Channel) @@ -328,7 +344,17 @@ package STM32.DAC is Alignment : Data_Alignment) return Address; -- Returns the address of the Data Holding register within This, for the - -- specified Channel, at the specified Resolution and Alignment. + -- specified Channel, given the specified Resolution and Alignment. + -- + -- This function is stricly for use with DMA, all others use the API above. + + function Data_Address_Dual_Conversion + (This : Digital_To_Analog_Converter; + Resolution : DAC_Resolution; + Alignment : Data_Alignment) + return Address; + -- Returns the address of the Data Holding register within This, for the + -- dual conversion case, given the specified Resolution and Alignment. -- -- This function is stricly for use with DMA, all others use the API above. From 1403b9f6b4eb99fa860c2a024f5d06f07ef6047c Mon Sep 17 00:00:00 2001 From: Pat Rogers Date: Sat, 21 Mar 2026 15:45:36 -0500 Subject: [PATCH 08/18] replace curly quotes with straight quotes in comments for sake of compiler --- arch/ARM/STM32/drivers/sai/stm32-sai.ads | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/ARM/STM32/drivers/sai/stm32-sai.ads b/arch/ARM/STM32/drivers/sai/stm32-sai.ads index db2b2692c..afb371f36 100644 --- a/arch/ARM/STM32/drivers/sai/stm32-sai.ads +++ b/arch/ARM/STM32/drivers/sai/stm32-sai.ads @@ -1,6 +1,6 @@ ------------------------------------------------------------------------------ -- -- --- Copyright (C) 2016, AdaCore -- +-- Copyright (C) 2016-2026, AdaCore -- -- -- -- Redistribution and use in source and binary forms, with or without -- -- modification, are permitted provided that the following conditions are -- @@ -188,7 +188,7 @@ package STM32.SAI is (FS_Frame, FS_Frame_And_Channel_Identification) with Size => 1; - -- Meaningless and is not used in AC’97 or SPDIF audio block + -- Meaningless and is not used in AC'97 or SPDIF audio block -- configuration. It must be configured when the audio block is disabled. -- -- In case of FS_Frame_And_Channel_Identification, the number of slots @@ -206,7 +206,7 @@ package STM32.SAI is FS_Active_High) with Size => 1; -- It is used to configure the level of the start of frame on the FS - -- signal. It is meaningless and is not used in AC’97 or SPDIF audio + -- signal. It is meaningless and is not used in AC'97 or SPDIF audio -- block configuration. -- -- FS_Active_Low: FS is active low (falling edge) @@ -216,7 +216,7 @@ package STM32.SAI is (First_Bit, Before_First_Bit) with Size => 1; - -- Meaningless and is not used in AC’97 or SPDIF audio block + -- Meaningless and is not used in AC'97 or SPDIF audio block -- configuration. This bit must be configured when the audio block -- is disabled. -- First_Bit: FS is asserted on the first bit of the slot 0. @@ -231,7 +231,7 @@ package STM32.SAI is -- The slot size must be higher or equal to the data size. If this -- condition is not respected, the behavior of the SAI will be -- undetermined. - -- Ignored in AC’97 or SPDIF mode. + -- Ignored in AC'97 or SPDIF mode. -- Data_Size: The slot size is equivalent to the data size (specified in -- DS[3:0] in the SAI_xCR1 register). From d8722c4d478b005c32dcd60c2e8a6c8d34751bf0 Mon Sep 17 00:00:00 2001 From: Pat Rogers Date: Sat, 21 Mar 2026 15:51:55 -0500 Subject: [PATCH 09/18] Correct ethernet registers' decls due to incorrect SVD file. * for the Ethernet MAC frame filter register, ie MACFFR_Register, correct a component name, a type, and a size in MACFFR_Register to match the documentation. Component "RAM" should be "PAM", and PCF should be a 2-bit quantity (requiring a change to the size of the unused bits reserved at the end) * for the Ethernet MAC debug register, ie MACDBGR_Register, the package from SVD does not correspond to the documentation at all. Therefore we change this register definition manually. See RM0385 Rev 8 pages 1610 and 1611. * likewise, for the Ethernet MAC MII data register, ie MACMIIDR_Register, change component name to match documentation We also need to change the SVD file itself, in the svd2ada project. --- .../STM32/svd/stm32f7x/stm32_svd-ethernet.ads | 85 +++++++++++-------- 1 file changed, 51 insertions(+), 34 deletions(-) diff --git a/arch/ARM/STM32/svd/stm32f7x/stm32_svd-ethernet.ads b/arch/ARM/STM32/svd/stm32f7x/stm32_svd-ethernet.ads index c3366b409..95b7a35ce 100644 --- a/arch/ARM/STM32/svd/stm32f7x/stm32_svd-ethernet.ads +++ b/arch/ARM/STM32/svd/stm32f7x/stm32_svd-ethernet.ads @@ -411,11 +411,11 @@ package STM32_SVD.Ethernet is -- no description available DAIF : Boolean := False; -- no description available - RAM : Boolean := False; + PAM : Boolean := False; -- was RAM, incorrectly named in original SVD (see corrected SVD file) -- no description available BFD : Boolean := False; -- no description available - PCF : Boolean := False; + PCF : HAL.UInt2 := 0; -- incorrectly set to 1 bit in original SVD (see corrected SVD file) -- no description available SAIF : Boolean := False; -- no description available @@ -423,7 +423,7 @@ package STM32_SVD.Ethernet is -- no description available HPF : Boolean := False; -- unspecified - Reserved_10_30 : HAL.UInt21 := 16#0#; + Reserved_11_30 : HAL.UInt20 := 16#0#; -- incorrectly set to 21 bits in original SVD (see corrected SVD file) -- no description available RA : Boolean := False; end record @@ -435,13 +435,13 @@ package STM32_SVD.Ethernet is HU at 0 range 1 .. 1; HM at 0 range 2 .. 2; DAIF at 0 range 3 .. 3; - RAM at 0 range 4 .. 4; + PAM at 0 range 4 .. 4; BFD at 0 range 5 .. 5; - PCF at 0 range 6 .. 6; - SAIF at 0 range 7 .. 7; - SAF at 0 range 8 .. 8; - HPF at 0 range 9 .. 9; - Reserved_10_30 at 0 range 10 .. 30; + PCF at 0 range 6 .. 7; + SAIF at 0 range 8 .. 8; + SAF at 0 range 9 .. 9; + HPF at 0 range 10 .. 10; + Reserved_11_30 at 0 range 11 .. 30; RA at 0 range 31 .. 31; end record; @@ -484,7 +484,7 @@ package STM32_SVD.Ethernet is -- Ethernet MAC MII data register type MACMIIDR_Register is record -- no description available - TD : MACMIIDR_TD_Field := 16#0#; + MD : MACMIIDR_TD_Field := 16#0#; -- was TD, incorrectly named in original SVD (see corrected SVD file) -- unspecified Reserved_16_31 : HAL.UInt16 := 16#0#; end record @@ -492,7 +492,7 @@ package STM32_SVD.Ethernet is Bit_Order => System.Low_Order_First; for MACMIIDR_Register use record - TD at 0 range 0 .. 15; + MD at 0 range 0 .. 15; Reserved_16_31 at 0 range 16 .. 31; end record; @@ -594,34 +594,51 @@ package STM32_SVD.Ethernet is WFFRPR at 0 range 31 .. 31; end record; - -- Ethernet MAC debug register + -- Ethernet MAC debug register. The package from SVD does not correspond + -- to the documentation. Therefore we change this register definition + -- manually. See RM0385 Rev 8 pages 1610 and 1611. + -- TODO: update the SVD file so this manual change isn't necessary! type MACDBGR_Register is record - -- Read-only. CR - CR : Boolean; - -- Read-only. CSR - CSR : Boolean; - -- Read-only. ROR - ROR : Boolean; - -- Read-only. MCF - MCF : Boolean; - -- Read-only. MCP - MCP : Boolean; - -- Read-only. MCFHP - MCFHP : Boolean; - -- unspecified - Reserved_6_31 : HAL.UInt26; + Reserved_26_31 : HAL.UInt6; + Tx_FIFO_Full : Boolean; -- TFF + Tx_FIFO_Not_Empty : Boolean; -- TFNE + Reserved_23 : HAL.Bit := 0; + Tx_FIFO_Write_Active : Boolean; -- TFWA + Tx_FIFO_Read_Status : HAL.UInt2; -- TFRS + MAC_Transmitter_Paused : Boolean; -- MTP + MAC_Transmit_Frame_Controller_Status : HAL.UInt2; -- MTFCS + MAC_MII_Transmit_Engine_Active : Boolean; -- MMTEA + Reserved_10_15 : HAL.UInt6 := 0; + Rx_FIFO_Fill_Level : HAL.UInt2; -- RFFL + Reserved_7 : HAL.Bit := 0; + Rx_FIFO_Read_Controller_Status : HAL.UInt2; -- RFRCS + Rx_FIFO_Write_Controller_Active : Boolean; -- RFWRA + Reserved_3 : HAL.Bit := 0; + MAC_Small_FIFO_RW_Controller_Status : HAL.UInt2; -- MSFRWCS + MAC_MII_Receive_Protocol_Engine_Active : Boolean; -- MMRPEA end record - with Volatile_Full_Access, Size => 32, + with Volatile_Full_Access, + Size => 32, Bit_Order => System.Low_Order_First; for MACDBGR_Register use record - CR at 0 range 0 .. 0; - CSR at 0 range 1 .. 1; - ROR at 0 range 2 .. 2; - MCF at 0 range 3 .. 3; - MCP at 0 range 4 .. 4; - MCFHP at 0 range 5 .. 5; - Reserved_6_31 at 0 range 6 .. 31; + Reserved_26_31 at 0 range 26 .. 31; + Tx_FIFO_Full at 0 range 25 .. 25; + Tx_FIFO_Not_Empty at 0 range 24 .. 24; + Reserved_23 at 0 range 23 .. 23; + Tx_FIFO_Write_Active at 0 range 22 .. 22; + Tx_FIFO_Read_Status at 0 range 20 .. 21; + MAC_Transmitter_Paused at 0 range 19 .. 19; + MAC_Transmit_Frame_Controller_Status at 0 range 17 .. 18; + MAC_MII_Transmit_Engine_Active at 0 range 16 .. 16; + Reserved_10_15 at 0 range 10 .. 15; + Rx_FIFO_Fill_Level at 0 range 8 .. 9; + Reserved_7 at 0 range 7 .. 7; + Rx_FIFO_Read_Controller_Status at 0 range 5 .. 6; + Rx_FIFO_Write_Controller_Active at 0 range 4 .. 4; + Reserved_3 at 0 range 3 .. 3; + MAC_Small_FIFO_RW_Controller_Status at 0 range 1 .. 2; + MAC_MII_Receive_Protocol_Engine_Active at 0 range 0 .. 0; end record; -- Ethernet MAC interrupt status register From 9e0552292f3baeb60c27b06483dc8fc5c8e7fa75 Mon Sep 17 00:00:00 2001 From: Pat Rogers Date: Sat, 21 Mar 2026 16:00:00 -0500 Subject: [PATCH 10/18] Change type names to match WM8994 datasheet. * Change ADT name to Audio_CODEC for closer match to documentation and meaningfulness * For the same reasons, change name Output_Device to Analog_Outputs. * Minor reordering to put the primary ADT declaration near the top of the package. --- components/src/audio/W8994/wm8994-io.adb | 35 ++++++++++++- components/src/audio/W8994/wm8994-io.ads | 35 ++++++++++++- components/src/audio/W8994/wm8994.adb | 29 +++++----- components/src/audio/W8994/wm8994.ads | 67 +++++++++++------------- 4 files changed, 113 insertions(+), 53 deletions(-) diff --git a/components/src/audio/W8994/wm8994-io.adb b/components/src/audio/W8994/wm8994-io.adb index df4a8b9cf..0b4d8953f 100644 --- a/components/src/audio/W8994/wm8994-io.adb +++ b/components/src/audio/W8994/wm8994-io.adb @@ -1,3 +1,34 @@ +------------------------------------------------------------------------------ +-- -- +-- Copyright (C) 2026, 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 WM8994.IO is --------------- @@ -5,7 +36,7 @@ package body WM8994.IO is --------------- procedure I2C_Write - (This : in out WM8994_Device; + (This : in out Audio_CODEC; Register : Register_Address; Value : UInt16) is @@ -34,7 +65,7 @@ package body WM8994.IO is -------------- function I2C_Read - (This : in out WM8994_Device; + (This : in out Audio_CODEC; Register : Register_Address) return UInt16 is diff --git a/components/src/audio/W8994/wm8994-io.ads b/components/src/audio/W8994/wm8994-io.ads index b9093fc11..5901cd273 100644 --- a/components/src/audio/W8994/wm8994-io.ads +++ b/components/src/audio/W8994/wm8994-io.ads @@ -1,14 +1,45 @@ +------------------------------------------------------------------------------ +-- -- +-- Copyright (C) 2026, 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 WM8994.IO is type Register_Address is new UInt16; procedure I2C_Write - (This : in out WM8994_Device; + (This : in out Audio_CODEC; Register : Register_Address; Value : UInt16); function I2C_Read - (This : in out WM8994_Device; + (This : in out Audio_CODEC; Register : Register_Address) return UInt16; diff --git a/components/src/audio/W8994/wm8994.adb b/components/src/audio/W8994/wm8994.adb index 8d2c1fdd8..12acfd7d0 100644 --- a/components/src/audio/W8994/wm8994.adb +++ b/components/src/audio/W8994/wm8994.adb @@ -1,6 +1,6 @@ ------------------------------------------------------------------------------ -- -- --- Copyright (C) 2015-2024, AdaCore -- +-- Copyright (C) 2015-2026, AdaCore -- -- -- -- Redistribution and use in source and binary forms, with or without -- -- modification, are permitted provided that the following conditions are -- @@ -28,6 +28,7 @@ -- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- -- -- ------------------------------------------------------------------------------ + with WM8994.IO; use WM8994.IO; package body WM8994 is @@ -43,9 +44,9 @@ package body WM8994 is ---------------- procedure Initialize - (This : in out WM8994_Device; + (This : in out Audio_CODEC; Input : Input_Device; - Output : Output_Device; + Output : Analog_Outputs; Volume : Volume_Level; Frequency : Audio_Frequency) is @@ -260,7 +261,7 @@ package body WM8994 is -- Chip_ID -- ------------- - function Chip_ID (This : in out WM8994_Device) return UInt16 is + function Chip_ID (This : in out Audio_CODEC) return UInt16 is begin return I2C_Read (This, WM8994_CHIPID_ADDR); end Chip_ID; @@ -269,7 +270,7 @@ package body WM8994 is -- Play -- ---------- - procedure Play (This : in out WM8994_Device) is + procedure Play (This : in out Audio_CODEC) is begin This.Set_Mute (Mute_Off); end Play; @@ -278,7 +279,7 @@ package body WM8994 is -- Pause -- ----------- - procedure Pause (This : in out WM8994_Device) is + procedure Pause (This : in out Audio_CODEC) is begin -- Pause the audio playing This.Set_Mute (Mute_On); @@ -291,7 +292,7 @@ package body WM8994 is -- Resume -- ------------ - procedure Resume (This : in out WM8994_Device) is + procedure Resume (This : in out Audio_CODEC) is begin This.Set_Mute (Mute_Off); end Resume; @@ -300,7 +301,7 @@ package body WM8994 is -- Stop -- ---------- - procedure Stop (This : in out WM8994_Device; Cmd : Stop_Mode) is + procedure Stop (This : in out Audio_CODEC; Cmd : Stop_Mode) is begin if Output_Enabled then -- Mute the output first @@ -337,7 +338,7 @@ package body WM8994 is ---------------- procedure Set_Volume - (This : in out WM8994_Device; + (This : in out Audio_CODEC; Volume : Volume_Level) is begin @@ -365,7 +366,7 @@ package body WM8994 is -- Set_Mute -- -------------- - procedure Set_Mute (This : in out WM8994_Device; Cmd : Mute) is + procedure Set_Mute (This : in out Audio_CODEC; Cmd : Mute_Modes) is begin if Output_Enabled then case Cmd is @@ -388,8 +389,8 @@ package body WM8994 is --------------------- procedure Set_Output_Mode - (This : in out WM8994_Device; - Device : Output_Device) + (This : in out Audio_CODEC; + Device : Analog_Outputs) is begin case Device is @@ -446,7 +447,7 @@ package body WM8994 is ------------------- procedure Set_Frequency - (This : in out WM8994_Device; + (This : in out Audio_CODEC; Freq : Audio_Frequency) is begin @@ -508,7 +509,7 @@ package body WM8994 is -- Reset -- ----------- - procedure Reset (This : in out WM8994_Device) is + procedure Reset (This : in out Audio_CODEC) is begin I2C_Write (This, WM8994_SW_Reset, 16#0000#); Output_Enabled := False; diff --git a/components/src/audio/W8994/wm8994.ads b/components/src/audio/W8994/wm8994.ads index eaa7a8a9f..37bc3c6b0 100644 --- a/components/src/audio/W8994/wm8994.ads +++ b/components/src/audio/W8994/wm8994.ads @@ -1,6 +1,6 @@ ------------------------------------------------------------------------------ -- -- --- Copyright (C) 2015-2024, AdaCore -- +-- Copyright (C) 2015-2026, AdaCore -- -- -- -- Redistribution and use in source and binary forms, with or without -- -- modification, are permitted provided that the following conditions are -- @@ -38,10 +38,13 @@ with HAL.Time; package WM8994 is - -- TODO: see page 144 Datasheet WM8994_Rev4.6, from Cirrus Logic regarding - -- "For suppression of pop noise ..." + type Audio_CODEC + (Port : not null Any_I2C_Port; + I2C_Addr : UInt10; + Time : not null HAL.Time.Any_Delays) + is tagged limited private; - type Output_Device is + type Analog_Outputs is (No_Output, Speaker, Headphone, @@ -53,8 +56,6 @@ package WM8994 is Microphone, Input_Line); - WM8994_ID : constant := 16#8994#; - type Audio_Frequency is (Audio_Freq_8kHz, Audio_Freq_11kHz, @@ -88,7 +89,18 @@ package WM8994 is Audio_Freq_88kHz => 88_200, Audio_Freq_96kHz => 96_000); - type Mute is + Max_Volume : constant := 16#3F#; + + subtype Volume_Level is UInt16 range 0 .. Max_Volume; + + procedure Initialize + (This : in out Audio_CODEC; + Input : Input_Device; + Output : Analog_Outputs; + Volume : Volume_Level; + Frequency : Audio_Frequency); + + type Mute_Modes is (Mute_On, Mute_Off); @@ -103,48 +115,33 @@ package WM8994 is -- resuming from this mode, the codec is set to default configuration -- so users should re-initialize the codec. - Max_Volume : constant := 16#3F#; - - subtype Volume_Level is UInt16 range 0 .. Max_Volume; - - type WM8994_Device - (Port : not null Any_I2C_Port; - I2C_Addr : UInt10; - Time : not null HAL.Time.Any_Delays) - is tagged limited private; - - procedure Initialize - (This : in out WM8994_Device; - Input : Input_Device; - Output : Output_Device; - Volume : Volume_Level; - Frequency : Audio_Frequency); + WM8994_ID : constant := 16#8994#; - function Chip_ID (This : in out WM8994_Device) return UInt16; + function Chip_ID (This : in out Audio_CODEC) return UInt16; - procedure Play (This : in out WM8994_Device); + procedure Play (This : in out Audio_CODEC); - procedure Pause (This : in out WM8994_Device); + procedure Pause (This : in out Audio_CODEC); - procedure Resume (This : in out WM8994_Device); + procedure Resume (This : in out Audio_CODEC); - procedure Stop (This : in out WM8994_Device; Cmd : Stop_Mode); + procedure Stop (This : in out Audio_CODEC; Cmd : Stop_Mode); - procedure Set_Volume (This : in out WM8994_Device; Volume : Volume_Level); + procedure Set_Volume (This : in out Audio_CODEC; Volume : Volume_Level); - procedure Set_Mute (This : in out WM8994_Device; Cmd : Mute); + procedure Set_Mute (This : in out Audio_CODEC; Cmd : Mute_Modes); - procedure Set_Output_Mode (This : in out WM8994_Device; - Device : Output_Device); + procedure Set_Output_Mode (This : in out Audio_CODEC; + Device : Analog_Outputs); - procedure Set_Frequency (This : in out WM8994_Device; + procedure Set_Frequency (This : in out Audio_CODEC; Freq : Audio_Frequency); - procedure Reset (This : in out WM8994_Device); + procedure Reset (This : in out Audio_CODEC); private - type WM8994_Device + type Audio_CODEC (Port : not null Any_I2C_Port; I2C_Addr : UInt10; Time : not null HAL.Time.Any_Delays) From 60c8961b7e4667f2584a98a0db34097fad88af32 Mon Sep 17 00:00:00 2001 From: Pat Rogers Date: Sat, 21 Mar 2026 17:03:49 -0500 Subject: [PATCH 11/18] Fix cache line alignment in Cache_Maintenance The generic Cache_Maintenance procedure used the raw Start address as the initial DCCMVAC write address without first aligning it down to a cache line boundary. If Start was not 32-byte aligned, the first cache line was only partially cleaned. Additionally, Len was not extended to account for the trimmed prefix bytes, leaving the final partial cache line unflushed. Fix by aligning Op_Addr down to the nearest cache line boundary and extending Op_Size by the corresponding offset, ensuring all cache lines covering [Start, Start+Len) are cleaned. correct new copyright date formatting for readability --- arch/ARM/cortex_m/src/cache/cortex_m-cache.adb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/ARM/cortex_m/src/cache/cortex_m-cache.adb b/arch/ARM/cortex_m/src/cache/cortex_m-cache.adb index eada3cf3c..b8238d680 100644 --- a/arch/ARM/cortex_m/src/cache/cortex_m-cache.adb +++ b/arch/ARM/cortex_m/src/cache/cortex_m-cache.adb @@ -1,7 +1,7 @@ ------------------------------------------------------------------------------ -- -- --- Copyright (C) 2015-2016, AdaCore -- +-- Copyright (C) 2015-2026, AdaCore -- -- -- -- Redistribution and use in source and binary forms, with or without -- -- modification, are permitted provided that the following conditions are -- @@ -90,24 +90,24 @@ package body Cortex_M.Cache is if not D_Cache_Enabled then return; end if; - declare function To_U32 is new Ada.Unchecked_Conversion (System.Address, UInt32); - - Op_Size : Integer_32 := Integer_32 (Len); - Op_Addr : UInt32 := To_U32 (Start); - Reg : UInt32 with Volatile, Address => Reg_Address; - + Aligned_Addr : constant UInt32 := To_U32 (Start) and not (Data_Cache_Line_Size - 1); + Aligned_Size : constant UInt32 := UInt32 (Len) + (To_U32 (Start) - Aligned_Addr); + Op_Size : Integer_32 := Integer_32 (Aligned_Size); + -- Op_Size is extended by the number of bytes trimmed from the start, + -- ensuring the final partial line is covered + Op_Addr : UInt32 := Aligned_Addr; + -- Op_Addr starts at Start rounded down to the nearest cache line + Reg : UInt32 with Volatile, Address => Reg_Address; begin DSB; - while Op_Size > 0 loop Reg := Op_Addr; Op_Addr := Op_Addr + Data_Cache_Line_Size; Op_Size := Op_Size - Integer_32 (Data_Cache_Line_Size); end loop; - DSB; ISB; end; From 0915f17303ff39fe6a6fe05ebf89ad895b7b7205 Mon Sep 17 00:00:00 2001 From: Pat Rogers Date: Sat, 21 Mar 2026 17:29:44 -0500 Subject: [PATCH 12/18] Fix display coherency problem when D-cache is enabled Fixes the case in which the LTDC displayed content would occasionally slew to the left and then snap back immediately. Affects: stm32-dma2d_bitmap, framebuffer_ltdc DMA2D_Fill_Rect was called without Synchronous => True, allowing DMA2D writes to the hidden framebuffer to still be in progress when Internal_Update_Layer flushed and handed the buffer to LTDC. This caused occasional display corruption ("slewing") as LTDC scanned out a partially-written buffer. Fix Fill_Rect to use Synchronous => True, consistent with Fill. Add Clean_DCache in Internal_Update_Layer covering the hidden buffer before Set_Frame_Buffer, ensuring CPU-written dirty cache lines are flushed to physical memory before LTDC DMA reads them. --- boards/stm32_common/dma2d/stm32-dma2d_bitmap.adb | 6 ++++-- boards/stm32_common/ltdc/framebuffer_ltdc.adb | 9 ++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/boards/stm32_common/dma2d/stm32-dma2d_bitmap.adb b/boards/stm32_common/dma2d/stm32-dma2d_bitmap.adb index aa7b44ee7..6c2e3d2be 100644 --- a/boards/stm32_common/dma2d/stm32-dma2d_bitmap.adb +++ b/boards/stm32_common/dma2d/stm32-dma2d_bitmap.adb @@ -153,7 +153,8 @@ package body STM32.DMA2D_Bitmap is X => Area.Position.X, Y => Area.Position.Y, Width => Area.Width, - Height => Area.Height); + Height => Area.Height, + Synchronous => True); else DMA2D_Fill_Rect (DMA_Buf, @@ -161,7 +162,8 @@ package body STM32.DMA2D_Bitmap is X => Area.Position.Y, Y => Buffer.Width - Area.Position.X - Area.Width, Width => Area.Height, - Height => Area.Width); + Height => Area.Width, + Synchronous => True); end if; else Parent (Buffer).Fill_Rect (Area); diff --git a/boards/stm32_common/ltdc/framebuffer_ltdc.adb b/boards/stm32_common/ltdc/framebuffer_ltdc.adb index b27d5540a..c49af8282 100644 --- a/boards/stm32_common/ltdc/framebuffer_ltdc.adb +++ b/boards/stm32_common/ltdc/framebuffer_ltdc.adb @@ -1,6 +1,6 @@ ------------------------------------------------------------------------------ -- -- --- Copyright (C) 2015-2016, AdaCore -- +-- Copyright (C) 2015-2026, AdaCore -- -- -- -- Redistribution and use in source and binary forms, with or without -- -- modification, are permitted provided that the following conditions are -- @@ -32,6 +32,7 @@ with STM32.DMA2D.Interrupt; with STM32.DMA2D.Polling; with STM32.SDRAM; use STM32.SDRAM; +with Cortex_M.Cache; package body Framebuffer_LTDC is @@ -377,12 +378,18 @@ package body Framebuffer_LTDC is null; when 1 => Display.Buffers (LCD_Layer, 2).Wait_Transfer; + Cortex_M.Cache.Clean_DCache + (Display.Buffers (LCD_Layer, 2).Addr, + Display.Buffers (LCD_Layer, 2).Buffer_Size); STM32.LTDC.Set_Frame_Buffer (Layer => LCD_Layer, Addr => Display.Buffers (LCD_Layer, 2).Addr); Display.Current (LCD_Layer) := 2; when 2 => Display.Buffers (LCD_Layer, 1).Wait_Transfer; + Cortex_M.Cache.Clean_DCache + (Display.Buffers (LCD_Layer, 1).Addr, + Display.Buffers (LCD_Layer, 1).Buffer_Size); STM32.LTDC.Set_Frame_Buffer (Layer => LCD_Layer, Addr => Display.Buffers (LCD_Layer, 1).Addr); From bf9fccf93e00637d95a4f2fb508c4740e604f420 Mon Sep 17 00:00:00 2001 From: Pat Rogers Date: Mon, 23 Mar 2026 15:06:02 -0500 Subject: [PATCH 13/18] use new name for WM8994_Audio_Device --- boards/stm32_common/stm32f746disco/audio.adb | 36 +++++++++---------- boards/stm32_common/stm32f746disco/audio.ads | 34 +++++++++--------- .../stm32f746disco/stm32-board.ads | 2 +- 3 files changed, 36 insertions(+), 36 deletions(-) diff --git a/boards/stm32_common/stm32f746disco/audio.adb b/boards/stm32_common/stm32f746disco/audio.adb index 75d2d4ffd..e3ae6bd9d 100644 --- a/boards/stm32_common/stm32f746disco/audio.adb +++ b/boards/stm32_common/stm32f746disco/audio.adb @@ -1,6 +1,6 @@ ------------------------------------------------------------------------------ -- -- --- Copyright (C) 2016, AdaCore -- +-- Copyright (C) 2016-2026, AdaCore -- -- -- -- Redistribution and use in source and binary forms, with or without -- -- modification, are permitted provided that the following conditions are -- @@ -61,7 +61,7 @@ package body Audio is procedure Initialize_Audio_DMA; -- Configure the DMA channel to the SAI peripheral - procedure Initialize_SAI_Out (Freq : Audio_Frequency; Sink : Audio_Output_Device); + procedure Initialize_SAI_Out (Freq : Audio_Frequency; Sink : Audio_Outputs); procedure Initialize_Audio_I2C; -- Initialize the I2C Port to send commands to the driver @@ -74,10 +74,10 @@ package body Audio is ---------------- procedure Initialize - (This : in out WM8994_Audio_Device; + (This : in out WM8994_Audio_CODEC; Volume : Audio_Volume; Frequency : Audio_Frequency; - Sink : Audio_Output_Device) + Sink : Audio_Outputs) is begin STM32.SAI.Deinitialize (Audio_SAI, SAI_Out_Block); @@ -96,11 +96,11 @@ package body Audio is This.Device.Reset; This.Device.Initialize (Input => WM8994.No_Input, - Output => WM8994.Output_Device (Sink), + Output => WM8994.Analog_Outputs (Sink), Volume => As_Device_Volume (Volume), Frequency => WM8994.Audio_Frequency (Frequency)); - This.Output := WM8994.Output_Device (Sink); + This.Sink := WM8994.Analog_Outputs (Sink); -- For sake of any individual calls to Set_Frequency, assuming the STM -- code is correct that we also need to set the clocks when setting the -- frequency @@ -111,7 +111,7 @@ package body Audio is ---------------- procedure Set_Volume - (This : in out WM8994_Audio_Device; + (This : in out WM8994_Audio_CODEC; Volume : Audio_Volume) is begin @@ -123,12 +123,12 @@ package body Audio is ------------------- procedure Set_Frequency - (This : in out WM8994_Audio_Device; + (This : in out WM8994_Audio_CODEC; Frequency : Audio_Frequency) is - use type WM8994.Output_Device; + use type WM8994.Analog_Outputs; begin - if This.Output = WM8994.No_Output then + if This.Sink = WM8994.No_Output then raise Constraint_Error with "No prior call to Initialize"; end if; @@ -139,7 +139,7 @@ package body Audio is -- clock configuration too. Set_Audio_Clock (Frequency); STM32.SAI.Disable (Audio_SAI, SAI_Out_Block); - Initialize_SAI_Out (Frequency, Audio_Output_Device (This.Output)); + Initialize_SAI_Out (Frequency, Audio_Outputs (This.Sink)); STM32.SAI.Enable (Audio_SAI, SAI_Out_Block); end Set_Frequency; @@ -161,7 +161,7 @@ package body Audio is -- HSE/PLLM = 1MHz = PLLI2S VCO Input Configure_SAI_I2S_Clock (Audio_SAI, - PLLI2SN => 429, -- VCO Output = 429MHz + PLLI2SN => 429, -- VCO Sink = 429MHz PLLI2SQ => 2, -- SAI Clk(First level) = 214.5 MHz PLLI2SDIVQ => 19); -- I2S Clk = 215.4 / 19 = 11.289 MHz @@ -169,7 +169,7 @@ package body Audio is Audio_Freq_48kHz | Audio_Freq_96kHz => Configure_SAI_I2S_Clock (Audio_SAI, - PLLI2SN => 344, -- VCO Output = 344MHz + PLLI2SN => 344, -- VCO Sink = 344MHz PLLI2SQ => 7, -- SAI Clk(First level) = 49.142 MHz PLLI2SDIVQ => 1); -- I2S Clk = 49.142 MHz @@ -229,7 +229,7 @@ package body Audio is procedure Initialize_SAI_Out (Freq : Audio_Frequency; - Sink : Audio_Output_Device) + Sink : Audio_Outputs) is Active_Slots : SAI_Slots; begin @@ -298,7 +298,7 @@ package body Audio is ------------------- procedure Start_Playing - (This : in out WM8994_Audio_Device; + (This : in out WM8994_Audio_CODEC; Buffer : Audio_Buffer) is begin @@ -325,7 +325,7 @@ package body Audio is -- Pause -- ----------- - procedure Pause (This : in out WM8994_Audio_Device) is + procedure Pause (This : in out WM8994_Audio_CODEC) is begin This.Device.Pause; DMA_Pause (Audio_SAI, SAI_Out_Block); @@ -335,7 +335,7 @@ package body Audio is -- Resume -- ------------ - procedure Resume (This : in out WM8994_Audio_Device) is + procedure Resume (This : in out WM8994_Audio_CODEC) is begin This.Device.Resume; DMA_Resume (Audio_SAI, SAI_Out_Block); @@ -345,7 +345,7 @@ package body Audio is -- Stop -- ---------- - procedure Stop (This : in out WM8994_Audio_Device) is + procedure Stop (This : in out WM8994_Audio_CODEC) is begin This.Device.Stop (WM8994.Stop_Power_Down_Sw); DMA_Stop (Audio_SAI, SAI_Out_Block); diff --git a/boards/stm32_common/stm32f746disco/audio.ads b/boards/stm32_common/stm32f746disco/audio.ads index 2054e5d39..593110e3d 100644 --- a/boards/stm32_common/stm32f746disco/audio.ads +++ b/boards/stm32_common/stm32f746disco/audio.ads @@ -1,6 +1,6 @@ ------------------------------------------------------------------------------ -- -- --- Copyright (C) 2016-2024, AdaCore -- +-- Copyright (C) 2016-2026, AdaCore -- -- -- -- Redistribution and use in source and binary forms, with or without -- -- modification, are permitted provided that the following conditions are -- @@ -41,11 +41,11 @@ with WM8994; package Audio is - type WM8994_Audio_Device (Port : not null Any_I2C_Port) is + type WM8994_Audio_CODEC (Port : not null Any_I2C_Port) is tagged limited private; - type Audio_Output_Device is new WM8994.Output_Device with - Static_Predicate => Audio_Output_Device in + type Audio_Outputs is new WM8994.Analog_Outputs with + Static_Predicate => Audio_Outputs in Headphone | Speaker | Both; type Audio_Frequency is new WM8994.Audio_Frequency; @@ -56,17 +56,17 @@ package Audio is with Component_Size => 16, Alignment => 2; procedure Initialize - (This : in out WM8994_Audio_Device; + (This : in out WM8994_Audio_CODEC; Volume : Audio_Volume; Frequency : Audio_Frequency; - Sink : Audio_Output_Device); + Sink : Audio_Outputs); -- This routine initializes the hardware and configures the volume, -- sampling frequency, and output device (the sink). This routine must be -- called, before any others. The routines for setting the volume and -- the output frequency are optional. procedure Start_Playing - (This : in out WM8994_Audio_Device; + (This : in out WM8994_Audio_CODEC; Buffer : Audio_Buffer); -- Start playing, for the first time, content from the specified buffer. -- This routine must be called, perhaps just once but more than once if the @@ -80,40 +80,40 @@ package Audio is -- no more music to be played, or Stop or Pause is called. procedure Pause - (This : in out WM8994_Audio_Device); + (This : in out WM8994_Audio_CODEC); -- After calling Pause, only Resume should be called for resuming play (do -- not call Start_Playing again). procedure Resume - (This : in out WM8994_Audio_Device); + (This : in out WM8994_Audio_CODEC); -- Procedure Resume should be called only when the audio is playing or -- paused (not stopped). procedure Stop - (This : in out WM8994_Audio_Device); + (This : in out WM8994_Audio_CODEC); -- Stops the hardware and update/play process. Once called, you must call -- Start_Playing again if you want to restart the output. procedure Set_Volume - (This : in out WM8994_Audio_Device; + (This : in out WM8994_Audio_CODEC; Volume : Audio_Volume); procedure Set_Frequency - (This : in out WM8994_Audio_Device; + (This : in out WM8994_Audio_CODEC; Frequency : Audio_Frequency); private Audio_I2C_Addr : constant I2C_Address := 16#34#; - type WM8994_Audio_Device + type WM8994_Audio_CODEC (Port : not null Any_I2C_Port) is tagged limited record - Device : WM8994.WM8994_Device (Port, Audio_I2C_Addr, Ravenscar_Time.Delays); - Output : WM8994.Output_Device := WM8994.No_Output; - -- The initial value of Output is overwritten by Initialize. The value + Device : WM8994.Audio_CODEC (Port, Audio_I2C_Addr, Ravenscar_Time.Delays); + Sink : WM8994.Analog_Outputs := WM8994.No_Output; + -- The initial value of Sink is overwritten by Initialize. The value -- No_Output will trigger a C_E if ever referenced, so it is used as a - -- check that Initialize has been called. We need the component Output + -- check that Initialize has been called. We need the component Sink -- itself for the sake of a clean parameter profile for Set_Frequency, -- otherwise clients would have to pass another parameter to specify -- the output device selection again (after having done so when calling diff --git a/boards/stm32_common/stm32f746disco/stm32-board.ads b/boards/stm32_common/stm32f746disco/stm32-board.ads index 3bb8eb2f3..b6590ad87 100644 --- a/boards/stm32_common/stm32f746disco/stm32-board.ads +++ b/boards/stm32_common/stm32f746disco/stm32-board.ads @@ -156,7 +156,7 @@ package STM32.Board is Audio_DMA_Out_Stream : DMA_Stream_Selector renames Stream_4; Audio_DMA_Out_Channel : DMA_Channel_Selector renames Channel_3; - Audio_Device : aliased Audio.WM8994_Audio_Device (Audio_I2C'Access); + Audio_Device : aliased Audio.WM8994_Audio_CODEC (Audio_I2C'Access); -------------------------- -- micro SD card reader -- From cdad25a68b57ea37f9c3299c3791fdd2fa7c0b0f Mon Sep 17 00:00:00 2001 From: Pat Rogers Date: Mon, 23 Mar 2026 19:04:57 -0500 Subject: [PATCH 14/18] Fix SDRAM timing setup parameters We now compute them from the datasheet constants. Specifically, in procedure Initialize: * ExitSelfRefreshDelay, SelfRefreshTime, and RowCycleDelay were all derived from a single SDRAM_Min_Delay_In_ns constant, collapsing three distinct timing constraints (TXSR, TRAS, TRC) into one value. SelfRefreshTime was also hardcoded to 4 cycles, valid only at 90 MHz SDCLK. * Replace with per-parameter ceiling division over named board constants (SDRAM_TXSR_In_Ns, SDRAM_TRAS_In_Ns, SDRAM_TRC_In_Ns) so each constraint is satisfied independently at any clock frequency. STM32.Board spec: * add new SDRAM constants for the sake of the SDRAM initialization --- boards/stm32_common/sdram/stm32-sdram.adb | 28 ++++++++----------- .../stm32f746disco/stm32-board.ads | 6 ++-- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/boards/stm32_common/sdram/stm32-sdram.adb b/boards/stm32_common/sdram/stm32-sdram.adb index 5e40c73bf..9b7250a24 100644 --- a/boards/stm32_common/sdram/stm32-sdram.adb +++ b/boards/stm32_common/sdram/stm32-sdram.adb @@ -1,6 +1,6 @@ ------------------------------------------------------------------------------ -- -- --- Copyright (C) 2015-2016, AdaCore -- +-- Copyright (C) 2015-2026, AdaCore -- -- -- -- Redistribution and use in source and binary forms, with or without -- -- modification, are permitted provided that the following conditions are -- @@ -141,9 +141,7 @@ package body STM32.SDRAM is SDRAM_Conf : FMC_SDRAM_Init_Config; SDCLK : constant Unsigned_32 := Unsigned_32 (STM32.Device.System_Clock_Frequencies.SYSCLK / 2); - SDPeriod_In_ns : constant Unsigned_32 := - 1_000_000_000 / SDCLK; - Refresh_Delay : Unsigned_32; + SDPeriod_In_Ns : constant Unsigned_32 := 1_000_000_000 / SDCLK; begin if Initialized then @@ -171,22 +169,19 @@ package body STM32.SDRAM is -- 100 MHz of SD clock frequency (200MHz / 2) -- 1 Clock cycle = 1 / 100MHz = 10ns - Refresh_Delay := - (SDRAM_Min_Delay_In_ns - SDPeriod_In_ns + 1) / SDPeriod_In_ns; - Timing_Conf := ( -- 2 Clock cycles for Load to Active delay LoadToActiveDelay => 2, - -- min = 60ns: 6 * 10.0 - ExitSelfRefreshDelay => FMC_SDRAM_Timing (Refresh_Delay), - - -- in range [42ns, 120k ns] => using 4 * 11.1 ns - SelfRefreshTime => 4, - - -- min = 60ns - RowCycleDelay => FMC_SDRAM_Timing (Refresh_Delay), + -- Each timing parameter is computed as a cycle count by dividing the + -- required minimum time (in ns) by the SDCLK period, using ceiling + -- division to ensure the minimum is always satisfied regardless of + -- clock frequency. The timing constants are defined in STM32.Board + -- and reflect the IS42S32400F SDRAM datasheet specifications. + ExitSelfRefreshDelay => FMC_SDRAM_Timing ((SDRAM_TXSR_In_Ns + SDPeriod_In_Ns - 1) / SDPeriod_In_Ns), + SelfRefreshTime => FMC_SDRAM_Timing ((SDRAM_TRAS_In_Ns + SDPeriod_In_Ns - 1) / SDPeriod_In_Ns), + RowCycleDelay => FMC_SDRAM_Timing ((SDRAM_TRC_In_Ns + SDPeriod_In_Ns - 1) / SDPeriod_In_Ns), -- min = 20ns WriteRecoveryTime => 2, @@ -241,8 +236,7 @@ package body STM32.SDRAM is begin Initialize; Rounded_Size := Amount + Align; - Rounded_Size := - Rounded_Size - Rounded_Size rem Align; + Rounded_Size := Rounded_Size - Rounded_Size rem Align; G_Base_Addr := G_Base_Addr + Rounded_Size; diff --git a/boards/stm32_common/stm32f746disco/stm32-board.ads b/boards/stm32_common/stm32f746disco/stm32-board.ads index b6590ad87..5c70ca68f 100644 --- a/boards/stm32_common/stm32f746disco/stm32-board.ads +++ b/boards/stm32_common/stm32f746disco/stm32-board.ads @@ -1,6 +1,6 @@ ------------------------------------------------------------------------------ -- -- --- Copyright (C) 2015-2018, AdaCore -- +-- Copyright (C) 2015-2026, AdaCore -- -- -- -- Redistribution and use in source and binary forms, with or without -- -- modification, are permitted provided that the following conditions are -- @@ -116,7 +116,9 @@ package STM32.Board is SDRAM_Read_Pipe : constant STM32.FMC.FMC_SDRAM_Read_Pipe_Delay := STM32.FMC.FMC_ReadPipe_Delay_0; SDRAM_Refresh_Cnt : constant := 1539; - SDRAM_Min_Delay_In_ns : constant := 60; + SDRAM_TRAS_In_Ns : constant := 42; -- IS42S32400F min self-refresh time + SDRAM_TRC_In_Ns : constant := 60; -- IS42S32400F min row cycle time + SDRAM_TXSR_In_Ns : constant := 70; -- IS42S32400F min exit self-refresh delay --------- -- I2C -- From 1fd40623e5576591789625ffbb1aaa42af0ae1eb Mon Sep 17 00:00:00 2001 From: Pat Rogers Date: Mon, 23 Mar 2026 15:18:34 -0500 Subject: [PATCH 15/18] Add support for Ethernet RMII * add new declarations for Ethernet Physical Layer I/O Pins * add new procedures for enabling RMII clocks and pins --- .../stm32f746disco/stm32-board.adb | 28 ++++++++++++- .../stm32f746disco/stm32-board.ads | 40 +++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/boards/stm32_common/stm32f746disco/stm32-board.adb b/boards/stm32_common/stm32f746disco/stm32-board.adb index 12fce7f83..9d37c76b7 100644 --- a/boards/stm32_common/stm32f746disco/stm32-board.adb +++ b/boards/stm32_common/stm32f746disco/stm32-board.adb @@ -1,6 +1,6 @@ ------------------------------------------------------------------------------ -- -- --- Copyright (C) 2015, AdaCore -- +-- Copyright (C) 2015-2026, AdaCore -- -- -- -- Redistribution and use in source and binary forms, with or without -- -- modification, are permitted provided that the following conditions are -- @@ -103,4 +103,30 @@ package body STM32.Board is Configure_IO (User_Button_Point, (Mode_In, Resistors => Floating)); end Configure_User_Button_GPIO; + ----------------------------- + -- Enable_RMII_Pins_Clocks -- + ----------------------------- + + procedure Enable_RMII_Pins_Clocks is + begin + Enable_Clock (GPIO_A); + Enable_Clock (GPIO_C); + Enable_Clock (GPIO_G); + end Enable_RMII_Pins_Clocks; + + ------------------------- + -- Configure_RMII_Pins -- + ------------------------- + + procedure Configure_RMII_Pins is + begin + Configure_IO (All_RMII_Pins, + Config => (Mode => Mode_AF, + Resistors => Floating, + AF_Output_Type => Push_Pull, + AF_Speed => Speed_100MHz, + AF => GPIO_AF_ETH_11)); + -- All are AF_11, per RM0385 Rev 8, pg 1531 + end Configure_RMII_Pins; + end STM32.Board; diff --git a/boards/stm32_common/stm32f746disco/stm32-board.ads b/boards/stm32_common/stm32f746disco/stm32-board.ads index 5c70ca68f..0d81b29f3 100644 --- a/boards/stm32_common/stm32f746disco/stm32-board.ads +++ b/boards/stm32_common/stm32f746disco/stm32-board.ads @@ -206,4 +206,44 @@ package STM32.Board is -- for polling the button, and necessary for having the button generate -- interrupts. + -------------------------------------- + -- Ethernet Physical Layer I/O Pins -- + -------------------------------------- + + -- Serial Management Interface (SMI) comm pins for connecting the MAC with + -- the PHY for RMII. See RM0385 Rev 8, pg 1533. + RMII_REF_CLK : GPIO_Point renames PA1; + RMII_MDIO : GPIO_Point renames PA2; + RMII_MDC : GPIO_Point renames PC1; + + -- RMII pins. See RM0385 Rev 8, pp. 1536 and 1538 for overview, and the + -- actual board's User Manual (eg, UM1907 STM32F746G-DISCO Appendix A: + -- IO Assignment) for the pins. + RMII_CRS_DV : GPIO_Point renames PA7; + RMII_RXD0 : GPIO_Point renames PC4; + RMII_RXD1 : GPIO_Point renames PC5; + RMII_RXER : GPIO_Point renames PG2; + RMII_TX_EN : GPIO_Point renames PG11; + RMII_TXD0 : GPIO_Point renames PG13; + RMII_TXD1 : GPIO_Point renames PG14; + + -- Note: On this board, these are the only pins that can perform these + -- functions. + + All_RMII_Pins : constant GPIO_Points := (RMII_REF_CLK, + RMII_MDIO, + RMII_CRS_DV, + RMII_MDC, + RMII_RXD0, + RMII_RXD1, + RMII_RXER, + RMII_TX_EN, + RMII_TXD0, + RMII_TXD1); + + -- These need to be two separate routines due to hardware initialization + -- issues with the Ethernet device. + procedure Enable_RMII_Pins_Clocks; + procedure Configure_RMII_Pins; + end STM32.Board; From 58061c212e1b4067450437818627d5ed11373685 Mon Sep 17 00:00:00 2001 From: Pat Rogers Date: Mon, 23 Mar 2026 13:48:59 -0500 Subject: [PATCH 16/18] change procedure name Start_Playing back to Play correct letter casing fix words changed in comments due to refactoring --- boards/stm32_common/stm32f746disco/audio.adb | 10 +++++----- boards/stm32_common/stm32f746disco/audio.ads | 12 +++++------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/boards/stm32_common/stm32f746disco/audio.adb b/boards/stm32_common/stm32f746disco/audio.adb index e3ae6bd9d..cefb2a307 100644 --- a/boards/stm32_common/stm32f746disco/audio.adb +++ b/boards/stm32_common/stm32f746disco/audio.adb @@ -161,7 +161,7 @@ package body Audio is -- HSE/PLLM = 1MHz = PLLI2S VCO Input Configure_SAI_I2S_Clock (Audio_SAI, - PLLI2SN => 429, -- VCO Sink = 429MHz + PLLI2SN => 429, -- VCO Output = 429MHz PLLI2SQ => 2, -- SAI Clk(First level) = 214.5 MHz PLLI2SDIVQ => 19); -- I2S Clk = 215.4 / 19 = 11.289 MHz @@ -169,11 +169,11 @@ package body Audio is Audio_Freq_48kHz | Audio_Freq_96kHz => Configure_SAI_I2S_Clock (Audio_SAI, - PLLI2SN => 344, -- VCO Sink = 344MHz + PLLI2SN => 344, -- VCO Output = 344MHz PLLI2SQ => 7, -- SAI Clk(First level) = 49.142 MHz PLLI2SDIVQ => 1); -- I2S Clk = 49.142 MHz - when Audio_Freq_12khz | Audio_Freq_24khz | Audio_Freq_88khz => + when Audio_Freq_12kHz | Audio_Freq_24kHz | Audio_Freq_88kHz => raise Program_Error with "freq not yet implemented"; -- FIXME! end case; @@ -297,7 +297,7 @@ package body Audio is -- Start_Playing -- ------------------- - procedure Start_Playing + procedure Play (This : in out WM8994_Audio_CODEC; Buffer : Audio_Buffer) is @@ -319,7 +319,7 @@ package body Audio is if not Enabled (Audio_SAI, SAI_Out_Block) then Enable (Audio_SAI, SAI_Out_Block); end if; - end Start_Playing; + end Play; ----------- -- Pause -- diff --git a/boards/stm32_common/stm32f746disco/audio.ads b/boards/stm32_common/stm32f746disco/audio.ads index 593110e3d..12342b09a 100644 --- a/boards/stm32_common/stm32f746disco/audio.ads +++ b/boards/stm32_common/stm32f746disco/audio.ads @@ -65,17 +65,15 @@ package Audio is -- called, before any others. The routines for setting the volume and -- the output frequency are optional. - procedure Start_Playing + procedure Play (This : in out WM8994_Audio_CODEC; Buffer : Audio_Buffer); - -- Start playing, for the first time, content from the specified buffer. - -- This routine must be called, perhaps just once but more than once if the - -- other routines below are called. The effect is to tell the underlying - -- WM8994 codec where the buffer to be played is located, and cause the - -- codec to start playing the contents. + -- Start playing content from the specified buffer. The effect is to tell + -- the underlying WM8994 CODEC where the buffer to be played is located, + -- and cause the CODEC to start playing the contents. -- -- NB: playing continues after the call returns. An additional mechanism, - -- outside this package, updates the content of the buffer while the codec + -- outside this package, updates the content of the buffer while the CODEC -- is playing it. That update/play process continues until either there is -- no more music to be played, or Stop or Pause is called. From b87f449ea223d2f7dc018170be0a69c28e72c413 Mon Sep 17 00:00:00 2001 From: Pat Rogers Date: Tue, 24 Mar 2026 10:34:22 -0500 Subject: [PATCH 17/18] use a "private with" for Ravenscar_Time --- boards/stm32_common/stm32f746disco/audio.ads | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/boards/stm32_common/stm32f746disco/audio.ads b/boards/stm32_common/stm32f746disco/audio.ads index 12342b09a..d56ed81c7 100644 --- a/boards/stm32_common/stm32f746disco/audio.ads +++ b/boards/stm32_common/stm32f746disco/audio.ads @@ -32,13 +32,13 @@ -- @author MCD Application Team -- ------------------------------------------------------------------------------ -with HAL; use HAL; -with HAL.I2C; use HAL.I2C; -with Ravenscar_Time; +with HAL; use HAL; +with HAL.I2C; use HAL.I2C; with Interfaces; use Interfaces; - with WM8994; +private with Ravenscar_Time; + package Audio is type WM8994_Audio_CODEC (Port : not null Any_I2C_Port) is From d5ceeecc622b1e81bbf3ebf820c61c292bcd6f51 Mon Sep 17 00:00:00 2001 From: Pat Rogers Date: Fri, 27 Mar 2026 19:10:31 -0500 Subject: [PATCH 18/18] Ensure loop does not go forever --- arch/ARM/STM32/drivers/stm32-rng-polling.adb | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/arch/ARM/STM32/drivers/stm32-rng-polling.adb b/arch/ARM/STM32/drivers/stm32-rng-polling.adb index 29282b9f4..47f367eff 100644 --- a/arch/ARM/STM32/drivers/stm32-rng-polling.adb +++ b/arch/ARM/STM32/drivers/stm32-rng-polling.adb @@ -1,6 +1,6 @@ ------------------------------------------------------------------------------ -- -- --- Copyright (C) 2015, AdaCore -- +-- Copyright (C) 2015-2026, AdaCore -- -- -- -- Redistribution and use in source and binary forms, with or without -- -- modification, are permitted provided that the following conditions are -- @@ -50,9 +50,7 @@ package body STM32.RNG.Polling is begin Enable_RNG_Clock; Enable_RNG; - - -- Discard the first randomly generated number, according to STM32F4 - -- docs. + -- Discard the first generated number, according to STM32F4 docs. Discard := Random; end Initialize_RNG; @@ -61,10 +59,17 @@ package body STM32.RNG.Polling is ------------ function Random return UInt32 is + Max_Attempts : constant := 1000; + -- The above is arbitrary. It needs to be long enough that normal + -- behavior will not be flagged. Longer than that is fine. The point + -- is to not hang forever. begin - while not RNG_Data_Ready loop - null; - end loop; + Await_Ready : for K in 1 .. Max_Attempts loop + exit when RNG_Data_Ready; + if K = Max_Attempts then + raise Program_Error with "RNG data not ready"; + end if; + end loop Await_Ready; return RNG_Data; end Random;