3
\$\begingroup\$

My question is best explained by an example. There's an evaluation kit from Infineon that uses ARM Cortex-M4 and has a total of 80 kB of RAM. There is also 512 kB of Flash memory. [However, it seems that due to large areas within RAM being "reserved" (as per board's reference manual), the maximum RAM size is below 20 kB. What could be the cause of such behaviour?] After further investigation, the problem appears to be that the RAM allocated for program data passes the boundary between the two regions, and does so in a misaligned fashion. This may cause problems even if code size is well below RAM size.

To give a little context to the problem, here is the output of arm-none-eabi-size with SysV option enabled:

section               size        addr
.text                 5628   134217728
Stack                 2048   536854528
.data                  116   536856576
.bss                 16386   536856692
USB_RAM                  2   536873078
.no_init                32   536936384
.debug_aranges        2208           0
.debug_info          43565           0
.debug_abbrev         3389           0
.debug_line          11094           0
.debug_frame          9968           0
.debug_str           30489           0
.debug_loc           21316           0
.debug_ranges         2064           0
.build_attributes      472           0
Total               148777

Unless I am mistaking, the only parts that go into RAM are .bss, .data(as it goes both into RAM and Flash). The relevant linker map section is as follows (i.e. shows exactly the point where the .bss section goes out of its bounds):

.bss            0x1fffc874     0x4009 load address 0x0c0016a8
                0x1fffc874                . = ALIGN (0x4)
                0x1fffc874                __bss_start = .
 *(.bss)
 *(.bss*)
 .bss.resultsArray
                0x1fffc874     0x4000 ./main.o
                0x1fffc874                resultsArray
 .bss.resultsArrayIndex
                0x20000874        0x2 ./main.o
                0x20000874                resultsArrayIndex
 *fill*         0x20000876        0x2 
 .bss.oversamplingResult
                0x20000878        0x4 ./main.o
                0x20000878                oversamplingResult
 .bss.numberOfOversamplingSamplesCollected
                0x2000087c        0x1 ./main.o
                0x2000087c                numberOfOversamplingSamplesCollected

Note that per user manual, PSRAM ends at 0x1FFFFFFF and DSRAM begins at 0x20000000. Running this program generates a Bus Fault when the startup sequence reaches 0x1FFFFFFD. Reducing the size so that it fits in PSRAM makes the program compile and run without any Faults. The question is not as much about this particular program; instead, I am genuinely curious as to why so little RAM is available for the actual program variables and uninitialized data and everything else that goes into RAM?

Below is the screen capture from the reference manual outlining the memory organization at the boundary.

enter image description here

\$\endgroup\$
  • 2
    \$\begingroup\$ The listings you are showing have nothing to do with the actual RAM on the chip. It is just an output of some binary running on this chip. Some of the RAM might be reserved for the use of the bootloader/debugger or whatever which is preprogrammed on the board to make your life easier. \$\endgroup\$ – Eugene Sh. Mar 23 '16 at 19:02
  • \$\begingroup\$ To emphasise @EugeneSh. point. The way the program is arranged in memory is caused by the compiler, and more particularly the linker script. There appears to be over 60kiBytes available if you needed to use it. The Bus Fault at 0x1FFFFFFD may be coincidental, though I would expect there to be a straightforward explanation. The cause may be related to a library being linked, or the initialisation of part the chip, or something else very specific, and nothing to do with a lack of memory (unless the actual chip on the board is a lower spec, or broken). Change the linker script to test this. \$\endgroup\$ – gbulmer Mar 23 '16 at 19:24
  • 3
    \$\begingroup\$ How exactly are you trying to access 0x1FFFFFFD ? Only byte wide data access would be legal at that address, though execution at 0x1FFFFFFC with the thumb mode bit set should be legal. \$\endgroup\$ – Chris Stratton Mar 23 '16 at 19:30
  • \$\begingroup\$ @EugeneSh. I don't think I understand what you mean unfortunately. In the reference manual, the Boot ROM and other Flash are explicitly labelled, whereas the other areas are just marked as "reserved". Something tells me that this is a misleading observation of mine, however. Are you referring to some boot/debug algorithms that should not be changed and thus stored in the "reserved" regions? \$\endgroup\$ – fandor Mar 23 '16 at 19:52
  • 1
    \$\begingroup\$ 2718 page datasheet, care to narrow it down a bit? \$\endgroup\$ – pipe Mar 23 '16 at 21:15
5
\$\begingroup\$

Running this program generates a Bus Fault when the startup sequence reaches 0x1FFFFFFD

Usual startup routines write 4-byte words, but your address is not 4-byte aligned. Your linker script probably misses one ALIGN(4) statement (or similar if not LD).

Now the Cortex M4 should in theory split the unaligned write into two, but yours would wrap over two memory segments at different memory busses. It is possible that this particular case is not handled correctly in hardware, causing the address to flip over 0x00000000 instead of 0x20000000. Thus you try to write to flash at 0x00 => Bus fault. Correctly aligning your data should fix this problem.

\$\endgroup\$
  • \$\begingroup\$ Thank you for your response! I am unfortunately not sure what you mean by "wrap over two memory segments at different memory buses". What does it mean to "wrap over memory segments"? By the way, the linker script does include . = ALIGN(4) for the .bss section. At least at the place I am looking in - which is not necessarily correct☺ \$\endgroup\$ – fandor Mar 23 '16 at 21:46
5
\$\begingroup\$

Turbo J's answer is most likely correct, but I wanted to clarify what's going on with the RAMs and show you how to find this information in the documentation.

There are three RAM blocks on your MCU. The first is the program RAM (PSRAM). As is stated in the XMC4000 MCU reference manual's introduction (section 1.3):

Code RAM (PSRAM)

The Code RAM is intended for user code or Operating System data storage. The memory is accessed via the Bus Matrix and provides zero-wait-state access for the CPU for code execution or data access.

So the RAM is "intended" for program code, and (according to section 25.2.5) there's a special option to boot from PSRAM, but you can use it for whatever you want.

From the introduction again:

System RAM (DSRAM1)

The System RAM is intended for general user data storage. The System RAM is accessed via the Bus Matrix and provides zero-wait-state access for data.

Communication RAM (DSRAM2)

The Communication RAM is intended for use by communication interface units like the USB and Ethernet modules.

Now again, it says "intended", but elsewhere the document suggests that the RAM blocks are mostly interchangeable. Section 2.3.3 says:

The Code, SRAM, and external RAM regions can hold programs. However, it is recommended that programs always use the Code region. This is because the processor has separate buses that enable instruction fetches and data accesses to occur simultaneously.

This is talking about the ARM ICode and DCode interfaces. I'm not an expert on those, unfortunately, but basically it's a Harvard architecture.

ARM has posted the Cortex-M4 TRM online. It explains a helpful property of the DCode bus:

Control logic in this interface converts unaligned data and debug accesses into two or three aligned accesses, depending on the size and alignment of the unaligned access. This stalls any subsequent data or debug access until the unaligned access has completed.

According to another ARM TRM page, this comes with limitations:

Unaligned accesses that cross memory map boundaries are architecturally Unpredictable. The processor behavior is boundary dependent, as follows:

  • DCode accesses wrap within the region. For example, an unaligned halfword access to the last byte of Code space (0x1FFFFFFF) is converted by the DCode interface into a byte access to 0x1FFFFFFF followed by a byte access to 0x00000000. ...

Now, let's go back to the MCU reference manual one more time to see what the memory regions are on this particular implementation:

Memory region table

It lines up perfectly with the ARM example! (That's pretty common, actually.) So an unaligned access at 0x1ffffffd/e would wrap around to 0x00000000. What's at that address? The MCU reference manual's memory map comes to the rescue:

Memory map table

It's the boot ROM! If I had to guess, I'd say that writes to the boot ROM address space probably trigger an error. (Section 7.4 of the manual suggests it's an Unsupported Access Mode error.) You can experiment and find out if you'd like. Anyway, the moral of this story is: don't make your linker sections cross memory regions! (Ideally, put them in the RAM they're "intended" for.)

This stuff about unaligned accesses and memory regions is not as straightforward as one might like, but these are the sorts of things you have to deal with when using a high-end microcontroller. When in doubt, it's best to follow the manufacturer's recommendations for what goes where in memory.

\$\endgroup\$
  • 1
    \$\begingroup\$ Adam, I am genuinely thankful for your time that you took to answer this! Your answer is extremely helpful and hopefully not only for myself. Turbo J's and your suggestions are spot on - the issue seems to be that the manufacturer's linker script - which is strange - seems to combine PSRAM and DSRAM1 into a single contiguous memory region called "SRAM_combined", thus allowing data to be stored across the boundary. On top of that, an error in an address of an offset during start-up causes misalignment. \$\endgroup\$ – fandor Mar 24 '16 at 17:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.