diff --git a/arch/ARM/STM32/drivers/flash/stm32-flash.adb b/arch/ARM/STM32/drivers/flash/stm32-flash.adb new file mode 100644 index 000000000..55ecd2a07 --- /dev/null +++ b/arch/ARM/STM32/drivers/flash/stm32-flash.adb @@ -0,0 +1,254 @@ +------------------------------------------------------------------------------ +-- -- +-- 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. -- +-- -- +------------------------------------------------------------------------------ + +with Memory_Barriers; + +with STM32_SVD.FLASH; + +package body STM32.Flash is + + FLASH_Periph : STM32_SVD.FLASH.FLASH_Peripheral renames + STM32_SVD.FLASH.FLASH_Periph; + + Whole_Flash : constant HAL.Flash.Memory_Region := (0, 16#F_FFFF#); + + subtype Memory_Region is HAL.UInt8_Array (1 .. 16#F_FFFF#); + + procedure Wait_Flash; + -- Spin CPU while the flash is busy + + --------------------- + -- Erasable_Region -- + --------------------- + + overriding function Erasable_Region + (This : in out Flash_Memory; + Region : HAL.Flash.Memory_Region) + return HAL.Flash.Memory_Region + is + Result : HAL.Flash.Memory_Region; + begin + case Region.From is + when 0 .. 16#FFFF# => + Result.From := Region.From / (16 * 1024) * 16 * 1024; + Result.To := Region.From + 16 * 1024 - 1; + when 16#1_0000# .. 16#1_FFFF# => + Result.From := 16#1_0000#; + Result.To := 16#1_FFFF#; + when 16#2_0000# .. 16#F_FFFF# => + Result.From := Region.From / (128 * 1024) * 128 * 1024; + Result.To := Region.From + 128 * 1024 - 1; + when others => + Result := Whole_Flash; + end case; + + return + (if Region.To in Result.From .. Result.To + then Result + else Whole_Flash); + end Erasable_Region; + + ----------- + -- Erase -- + ----------- + + overriding procedure Erase + (This : in out Flash_Memory; + Region : HAL.Flash.Memory_Region; + Success : out Boolean) + is + Sector : Natural range 0 .. 27; + Size : Positive; + begin + if Region = Whole_Flash then + raise Program_Error with "Unimplemented"; + end if; + + case Region.From is + when 16#0_0000# .. 16#0_FFFF# => + Size := 16 * 1024; + Sector := (Region.From - 16#0_0000#) / Size; + + when 16#1_0000# .. 16#1_FFFF# => + Size := 64 * 1024; + Sector := 4; + + when 16#2_0000# .. 16#F_FFFF# => + Size := 128 * 1024; + Sector := 5 + (Region.From - 16#2_0000#) / Size; + + when others => + Success := False; + return; + end case; + + Sector := Sector + (This.Bank - 1) * 16; + + Unlock; + + Wait_Flash; + + FLASH_Periph.SR.EOP := True; -- Clear interrupt flag + + FLASH_Periph.CR := + (LOCK => False, -- (No-)Lock + SER => True, -- Sector erase + SNB => STM32_SVD.FLASH.CR_SNB_Field (Sector), + PSIZE => 2, -- Parallelism size x32 + STRT => True, -- Start + EOPIE => False, -- interrupt on EOP bit = 1 + ERRIE => False, + others => <>); + + Success := True; + end Erase; + + overriding function Is_Busy (This : Flash_Memory) return Boolean is + (FLASH_Periph.SR.BSY); + + ----------- + -- Write -- + ----------- + + overriding procedure Write + (This : in out Flash_Memory; + Offset : Natural; + Data : HAL.UInt8_Array; + Success : out Boolean) + is + function Get_Word (J : Natural) return HAL.UInt32 is + (HAL.UInt32 (Data (Data'First + 4 * J)) + + HAL.Shift_Left (HAL.UInt32 (Data (Data'First + 4 * J + 1)), 8) + + HAL.Shift_Left (HAL.UInt32 (Data (Data'First + 4 * J + 2)), 16) + + HAL.Shift_Left (HAL.UInt32 (Data (Data'First + 4 * J + 3)), 24)); + + Memory : Memory_Region + with + Import, + Address => (if This.Bank = 1 then First_Bank else Second_Bank); + + Memory_32 : HAL.UInt32_Array (0 .. 16#F_FFFF# / 4) + with + Import, + Address => (if This.Bank = 1 then First_Bank else Second_Bank); + begin + Unlock; + + if Data'Length mod 4 = 0 then + for J in 0 .. Data'Length / 4 - 1 loop + Programming (By_Word => True); + Memory_32 (Offset + J) := Get_Word (J); + end loop; + else + for J in Data'Range loop + Programming (By_Word => False); + Memory (Offset + J - Data'First) := Data (J); + end loop; + end if; + + Lock; + + Success := True; + end Write; + + ---------- + -- Lock -- + ---------- + + procedure Lock is + begin + FLASH_Periph.CR := + (LOCK => True, -- Lock + others => <>); + end Lock; + + ----------------- + -- Programming -- + ----------------- + + procedure Programming (By_Word : Boolean) is + begin + Wait_Flash; + + FLASH_Periph.CR := + (LOCK => False, -- (No-)Lock + PG => True, -- Programming + PSIZE => (if By_Word then 2 else 0), -- Parallelism size x32/x8 + others => <>); + end Programming; + + ---------- + -- Read -- + ---------- + + overriding procedure Read + (This : in out Flash_Memory; + Offset : Natural; + Data : out HAL.UInt8_Array; + Success : out Boolean) + is + Memory : Memory_Region + with + Import, + Address => (if This.Bank = 1 then First_Bank else Second_Bank); + begin + Success := Offset in Memory'Range; + + if Success then + Data := Memory (Offset .. Offset + Data'Length - 1); + end if; + end Read; + + ------------ + -- Unlock -- + ------------ + + procedure Unlock is + begin + FLASH_Periph.KEYR := 16#4567_0123#; + Memory_Barriers.Data_Synchronization_Barrier; + FLASH_Periph.KEYR := 16#CDEF_89AB#; + Memory_Barriers.Data_Synchronization_Barrier; + Wait_Flash; + end Unlock; + + ---------------- + -- Wait_Flash -- + ---------------- + + procedure Wait_Flash is + begin + while FLASH_Periph.SR.BSY loop + null; + end loop; + end Wait_Flash; + +end STM32.Flash; diff --git a/arch/ARM/STM32/drivers/flash/stm32-flash.ads b/arch/ARM/STM32/drivers/flash/stm32-flash.ads new file mode 100644 index 000000000..803291259 --- /dev/null +++ b/arch/ARM/STM32/drivers/flash/stm32-flash.ads @@ -0,0 +1,95 @@ +------------------------------------------------------------------------------ +-- -- +-- 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. -- +-- -- +------------------------------------------------------------------------------ + +-- Embedded Flash memory for STM32F4xx with two banks. +-- +-- Embedded STM32 Flash memory has two 1M-byte banks. Each bank organized into +-- 12 sectors (4 x 16, 1 x 64, 7 x 128 kilo bytes). + +with HAL.Flash; +with System; + +package STM32.Flash is + pragma Preelaborate; + + subtype Flash_Bank is Natural range 1 .. 2; + + type Flash_Memory (Bank : Flash_Bank) is + limited new HAL.Flash.Flash_Memory with private; + + Bank_Size : constant := 2 ** 20; -- 1 MB per bank + First_Bank : constant System.Address := System'To_Address (16#0800_0000#); + Second_Bank : constant System.Address := System'To_Address (16#0810_0000#); + + overriding function Size (This : Flash_Memory) return Natural + is (Bank_Size); + + overriding function Is_Busy (This : Flash_Memory) return Boolean; + + overriding function Erasable_Region + (This : in out Flash_Memory; + Region : HAL.Flash.Memory_Region) + return HAL.Flash.Memory_Region; + + use type HAL.Flash.Memory_Region; + + overriding procedure Erase + (This : in out Flash_Memory; + Region : HAL.Flash.Memory_Region; + Success : out Boolean) + with Pre => Region = Erasable_Region (This, Region); + + overriding procedure Read + (This : in out Flash_Memory; + Offset : Natural; + Data : out HAL.UInt8_Array; + Success : out Boolean); + + overriding procedure Write + (This : in out Flash_Memory; + Offset : Natural; + Data : HAL.UInt8_Array; + Success : out Boolean); + -- The chip is able to write up to 256 bytes in one go if they are fitted + -- in aligned 256 bytes blocks. Otherwise, Write is split in several + -- commands and execution is blocked until all except the last one is + -- finished. + + procedure Lock; + procedure Unlock; + procedure Programming (By_Word : Boolean); + +private + + type Flash_Memory (Bank : Flash_Bank) + is limited new HAL.Flash.Flash_Memory with null record; + +end STM32.Flash; diff --git a/examples/STM32F429_Discovery/flash_f429disco.gpr b/examples/STM32F429_Discovery/flash_f429disco.gpr new file mode 100644 index 000000000..1fa65e772 --- /dev/null +++ b/examples/STM32F429_Discovery/flash_f429disco.gpr @@ -0,0 +1,15 @@ +with "../../boards/stm32f429_discovery/stm32f429_discovery_full.gpr"; + +project Flash_F429Disco extends "../shared/common/common.gpr" is + + for Runtime ("Ada") use STM32F429_Discovery_Full'Runtime("Ada"); + for Target use "arm-eabi"; + for Main use ("flash.adb"); + for Languages use ("Ada"); + for Source_Dirs use ("../shared/stm32_flash/src", "../../arch/ARM/STM32/drivers/flash"); + for Object_Dir use "../shared/stm32_flash/obj/stm32f429disco"; + for Create_Missing_Dirs use "True"; + + package Compiler renames STM32F429_Discovery_Full.Compiler; + +end Flash_F429Disco; diff --git a/examples/shared/stm32_flash/src/flash.adb b/examples/shared/stm32_flash/src/flash.adb new file mode 100644 index 000000000..931814fbe --- /dev/null +++ b/examples/shared/stm32_flash/src/flash.adb @@ -0,0 +1,156 @@ +------------------------------------------------------------------------------ +-- -- +-- 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. -- +-- -- +------------------------------------------------------------------------------ + +-- In this example we erase and flash the second bank of STM32 flash memory +-- when the button is pressed on reset. If the button is not pressed, the +-- program reads the flash memory and checks its content. If everything is +-- OK, the program blinks the green LED slowly (1 Hz), but otherwise it blinks +-- the LED faster (5 Hz). + +with Ada.Real_Time; + +with HAL.Flash; + +with STM32.Board; +with STM32.GPIO; + +with STM32.Flash; + +procedure Flash is + use type Ada.Real_Time.Time; + + procedure Write_Flash + (Flash : in out STM32.Flash.Flash_Memory; + Size : Positive; + Ok : out Boolean); + -- Read part of flash and check the content with expected values + + procedure Check_Flash + (Flash : in out STM32.Flash.Flash_Memory; + Size : Positive; + Ok : out Boolean); + -- Erase and write part of flash with some pattern + + ----------------- + -- Check_Flash -- + ----------------- + + procedure Check_Flash + (Flash : in out STM32.Flash.Flash_Memory; + Size : Positive; + Ok : out Boolean) + is + From : Natural := 0; + begin + Ok := True; + + while Ok and From < Size loop + declare + Ints : array (1 .. 64) of Natural; + Bytes : HAL.UInt8_Array (1 .. 256) + with Import, Address => Ints'Address; + begin + Flash.Read (From, Bytes, Ok); + + for J in Ints'Range loop + Ok := Ok and (Ints (J) = From + (J - 1) * 4); + end loop; + + From := From + Bytes'Length; + end; + end loop; + end Check_Flash; + + ----------------- + -- Write_Flash -- + ----------------- + + procedure Write_Flash + (Flash : in out STM32.Flash.Flash_Memory; + Size : Positive; + Ok : out Boolean) + is + Region : constant HAL.Flash.Memory_Region := + Flash.Erasable_Region ((From => 0, To => Size - 1)); + + From : Natural := 0; + begin + Flash.Erase (Region, Ok); + + while Ok and From < Size loop + declare + Ints : array (1 .. 64) of Natural; + Bytes : HAL.UInt8_Array (1 .. 256) + with Import, Address => Ints'Address; + begin + for J in Ints'Range loop + Ints (J) := From + (J - 1) * 4; + end loop; + + while Flash.Is_Busy loop + delay until Ada.Real_Time.Clock + + Ada.Real_Time.Microseconds (1); + end loop; + + Flash.Write (From, Bytes, Ok); + From := From + Bytes'Length; + end; + end loop; + end Write_Flash; + + Button : STM32.GPIO.GPIO_Point renames STM32.Board.User_Button_Point; + + Next : Ada.Real_Time.Time := Ada.Real_Time.Clock; + Span : Ada.Real_Time.Time_Span; + + Flash : STM32.Flash.Flash_Memory (2); + + Ok : Boolean := False; +begin + STM32.Board.Initialize_LEDs; + STM32.Board.Configure_User_Button_GPIO; + STM32.Board.Turn_On (STM32.Board.Green_LED); + + if Button.Set then + Write_Flash (Flash, 4096, Ok); + else + Check_Flash (Flash, 4096, Ok); + end if; + + Span := Ada.Real_Time.Milliseconds (if Ok then 500 else 100); + -- Blink slow or fast depending on Ok status + + loop + STM32.Board.Toggle (STM32.Board.Green_LED); + Next := Next + Span; + delay until Next; + end loop; +end Flash;