Hi,
I am using a memory-mapped record object and have come across an issue around the memory addresses assigned to an object of that record.
Suppose the following record declaration and representation clause:
type ADC_DR_Register is
record
DATA : Hal.UInt16;
Reserved : Hal.Uint16;
end record
with
Volatile_Full_Access,
Bit_Order => System.Low_Order_First,
Object_Size => 32;
for ADC_DR_Register use
record
DATA at 0 range 0 .. 15;
Reserved at 0 range 16 .. 31;
end record;
which is then memory-mapped to some peripheral address.
An object of that record is then declared (as the composite part of a different record) and subsequently the addresses assigned both to the record object itself and the first item declared in the record are printed:
Addr1 : System.Address := ADC_Registers.ADC_Periph.ADC_DR'Address with Volatile;
Addr2 : System.Address := ADC_Registers.ADC_Periph.ADC_DR.DATA'Address with Volatile;
Printing these in gdb yields:
(gdb) p Addr1
$1 = (system.address) 0x4001204c
(gdb) p Addr2
$2 = (system.address) 0x20004940
and contrary to what I intuitively believed would be the case, these addresses are different. This is flashed into an stm32f429 board (which is a cortex-M*-based board) so it looks like the object-based address Addr1 is correctly overlaid within the peripheral address space whereas the component-based one Addr2 seems to be in SRAM like any other declared non-memory-mapped object would be. Intuitively, it feels as if there’s some kind of handle or proxy in the middle which is indirectly delegating to one memory address or the other but I’m not too sure? ![]()
Not massively important, but for context, this is implementing a manual (i.e. non-ADL) ADC/DMA flow in the aforementioned board and it caused some interesting issues when running the code. Initially, I specified the DATA component as the value for the peripheral address in my DMA configuration as in:
-- Set peripheral address (the data register of the ADC module)
DMA_SxCR.DMA2_Controller.DMA_SPAR := Address_To_Integer (ADC_Registers.ADC_Periph.ADC_DR.DATA'Address);
Which, as demonstrated above, is the wrong address and had a somewhat interesting effect as what happens is that the DMA controller is hitting the SRAM address and not the peripheral one which means that the DATA register is never read which in turn means that the second channel conversion of the first ever scan causes an overrun (and the whole ADC/DMA flow stops and has to be reset).
After several days of intense debugging (that can be hard to spot!) and carefully going through the configuration on both sides again and again (I was definitely sure I’m missing something on that..) I thought of checking the addresses and finally spotted what was going on. Specifying Addr1 as the peripheral address results in the DMA controller reading from the correct address and the conversions/memory stores work just fine with no overrun errors.
I haven’t tried using a single scalar object for the representation of that register yet (which I assume should work?) but was keen to initially understand why this compiler behaviour occurs. Any pointers or references where this is detailed would be greatly appreciated.
(using a gnat_arm_elf = "=15.2.1" cross compiler)
Thanks!



