I am trying to map a register (SYSCFG_EXTICR1
) on a STM32F42xxx board and have come across some odd behaviour with the actual problem being that the desired pin isn’t mapped to external board interrupt.
Consider the following mapping:
with Common_Types;
with System;
package SYSCFG is
Base_Address : constant := 16#40013800#;
EXTICR_Offset : constant := 16#08#;
type EXTI_Port is (PA,
PB,
PC,
PD,
PE,
PF,
PG,
PH,
PI) with size => 4;
for EXTI_Port use (
PA => 2#0000#,
PB => 2#0001#,
PC => 2#0010#,
PD => 2#0011#,
PE => 2#0100#,
PF => 2#0101#,
PG => 2#0110#,
PH => 2#0111#,
PI => 2#1000#);
type SYSCFG_EXTICR_Register is
record
EXTIO : EXTI_Port;
EXTI1 : EXTI_Port;
EXTI2 : EXTI_Port;
EXTI3 : EXTI_Port;
Unmapped1 : Common_Types.Arbitrary_Unmapped_Space (1 .. 15);
EXTI4 : EXTI_Port;
EXTI5 : EXTI_Port;
EXTI6 : EXTI_Port;
EXTI7 : EXTI_Port;
Unmapped2 : Common_Types.Arbitrary_Unmapped_Space (1 .. 15);
EXTI8 : EXTI_Port;
EXTI9 : EXTI_Port;
EXTI10 : EXTI_Port;
EXTI11 : EXTI_Port;
Unmapped3 : Common_Types.Arbitrary_Unmapped_Space (1 .. 15);
EXTI12 : EXTI_Port;
EXTI13 : EXTI_Port;
EXTI14 : EXTI_Port;
EXTI15 : EXTI_Port;
Unmapped4 : Common_Types.Arbitrary_Unmapped_Space (1 .. 15);
end record with Volatile, Object_Size => 128;
for SYSCFG_EXTICR_Register use
record
EXTIO at 0 range 0 .. 3;
EXTI1 at 0 range 4 .. 7;
EXTI2 at 0 range 8 .. 11;
EXTI3 at 0 range 12 .. 15;
Unmapped1 at 0 range 16 .. 31;
EXTI4 at 4 range 0 .. 3;
EXTI5 at 4 range 4 .. 7;
EXTI6 at 4 range 8 .. 11;
EXTI7 at 4 range 12 .. 15;
Unmapped2 at 4 range 16 .. 31;
EXTI8 at 8 range 0 .. 3;
EXTI9 at 8 range 4 .. 7;
EXTI10 at 8 range 8 .. 11;
EXTI11 at 8 range 12 .. 15;
Unmapped3 at 8 range 16 .. 31;
EXTI12 at 12 range 0 .. 3;
EXTI13 at 12 range 4 .. 7;
EXTI14 at 12 range 8 .. 11;
EXTI15 at 12 range 12 .. 15;
Unmapped4 at 12 range 16 .. 31;
end record;
-- Access points
SYSCFG_EXTICR_Reg : SYSCFG_EXTICR_Register with Address => System'To_Address (Base_Address + EXTICR_Offset);
SYSCFG_EXTICR_Reg_Unmapped : SYSCFG_EXTICR_Register;
end SYSCFG;
where Common_Types
is just some package with well, common types so Common_Types.Arbitrary_Unmapped_Space
is:
type Arbitrary_Unmapped_Space is array (Positive range <>) of Boolean with Component_Size => 1, Unreferenced;
Based on the Reference Manual the mapping must be something like:
and the base address:
(This configuration is to do with mapping external pins to board interrupts and there are four registers available which all only use the lower 16 bits to configure a specific pin against an external interrupt. I’ve mapped all of these registers in one go using a single record)
Now consider the following code:
1. SYSCFG.SYSCFG_EXTICR_Reg.EXTI4 := SYSCFG.PB; -- After running this EXTI4 should be set to PB! (i.e. the pin we're trying to map is PB4)
2. SYSCFG.SYSCFG_EXTICR_Reg_Unmapped.EXTI4 := SYSCFG.PB;
3. SYSCFG.SYSCFG_EXTICR_Reg.Unmapped4 (1) := True;
4. SYSCFG.SYSCFG_EXTICR_Reg_Unmapped.EXTI4 := SYSCFG.PB; -- Not relevant just needed a hook to put a breakpoint to.
Putting a breakpoint in line 1 and printing the value of EXTI4 and dumping the raw memory in gdb, I’m getting:
(gdb) set lang ada
(gdb) p SYSCFG.SYSCFG_EXTICR_Reg.EXTI4
$1 = pa
which is correct as the line hasn’t been executed yet.
Now, executing line 1 and priting the value still gives PA
! :
(gdb) n
(gdb) p SYSCFG.SYSCFG_EXTICR_Reg.EXTI4
$2 = pa
Dumping the raw bytes also shows the same (using byte-size chunks as I think gdb will print scalars with a size greater than a byte in big-endian, but might be wrong):
(gdb) x/16tb 0x40013808
0x40013808: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0x40013810: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
My initial thought was that there’s something up with the way the compiler has laid out the record (i.e. maybe in big-endian rather than little-endian and setting the variable hits the register area which should be left untouched) so I set out to prove this theory but initially I wanted to prove that an unmapped record behaves as expected hence the SYSCFG_EXTICR_Reg_Unmapped
variable in the SYSCFG
package above. So, prior to executing line 2 above I printed the EXTI4 value:
(gdb) p SYSCFG.SYSCFG_EXTICR_Reg_Unmapped.EXTI4
$3 = pa
and then executing line 2 and printing the value and dumping the raw values yields the correct result:
(gdb) n
(gdb) p SYSCFG.SYSCFG_EXTICR_Reg_Unmapped.EXTI4
$4 = pb
(gdb) x/16tb SYSCFG.SYSCFG_EXTICR_Reg_Unmapped'Address
0x20001548 <syscfg__syscfg_exticr_reg_unmapped>: 00000000 00000000 00000000 00000000 00000001 00000000 00000000 00000000
0x20001550 <syscfg__syscfg_exticr_reg_unmapped+8>: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
where the first bit of the second word has been set correctly (this is little-endian, mind you).
So, clearly, something is wrong with the memory-mapping…As I said, I tried proving that by attempting to set a bit in the unmapped area shown above and executed line 3 but still got the same result (i.e. all bits zero) though come to think of it, if the record had been laid out in big-endian then setting any bit in the unmapped area should have no effect at all.
I am building this in Alire and some bits of the configuration are
(aaa.gpr):
for Target use "arm-eabi";
for Runtime ("ada") use "ravenscar-full-stm32f429disco";
package Compiler is
for Default_Switches ("ada") use Microcontrollers_Config.Ada_Compiler_Switches;
end Compiler;
............
(aaa_config.gpr):
Ada_Compiler_Switches := External_As_List ("ADAFLAGS", " ");
Ada_Compiler_Switches := Ada_Compiler_Switches &
(
"-Og" -- Optimize for debug
,"-ffunction-sections" -- Separate ELF section for each function
,"-fdata-sections" -- Separate ELF section for each variable
,"-g" -- Generate debug info
.... rest of the formatting switches
the configured toolchain is:
gnat_native=14.2.1
gprbuild=22.0.1
Interestingly enough, the exact same mapping when passed through an older gprbuild i.e.:
gprbuild --version
GPRBUILD Community 2021 (20210519) (x86_64-pc-linux-gnu)
works fine and the interrupt handler is triggered indeed when the voltage on the pin drops below a certain level using a potentiometer (i.e. falling-edge).
Any ideas what might be going on or any further troubleshooting tips?
Apologies for the long post.
Thanks.