Loading...
 

SW4STM32 and SW4Linux fully supports the STM32MP1 asymmetric multicore Cortex/A7+M4 MPUs

   With System Workbench for Linux, Embedded Linux on the STM32MP1 family of MPUs from ST was never as simple to build and maintain, even for newcomers in the Linux world. And, if you install System Workbench for Linux in System Workbench for STM32 you can seamlessly develop and debug asymmetric applications running partly on Linux, partly on the Cortex-M4.
You can get more information from the ac6-tools website and download (registration required) various documents highlighting:

System Workbench for STM32


Moving ISRs to ITCM RAM

Hi folks,

I’m currently trying to move specific ISRs and time-critical DSP functions to ITCM RAM on an STM32F7. I’m having trouble getting my linker script to behave and was hoping someone might have a solution.

Setup:
- STM32F746ZG on a Nucleo-144 board
- SW4STM32 v1.13.1.201701261206 on Win7

There is surprisingly little info out there on getting this to work. Best I was able to find was here, 4-5 posts down: http://www.openstm32.org/tiki-view_forum_thread.php?comments_parentId=2381Question

Note that this is not about running code from FLASH via the ITCM bus - that is already working just fine, and significantly sped up my code execution vs using AXI - but rather moving specific functions to ITCM RAM to speed up ISRs when they fire.

The relevant sections of my linker script look like:

MEMORY
{
ITCM_RAM (rx) : ORIGIN = 0x00000000, LENGTH = 16K
RAM (xrw)  : ORIGIN = 0x20000000, LENGTH = 320K
FLASH (rx)  : ORIGIN = 0x00200000, LENGTH = 1024K /* Access FLASH via ITCM */
}

/* Define output sections */
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH

/* Copy specific fast-executing code into ITCM RAM */
.itcm_text :
{
. = ALIGN(4);
*(.itcm_text) /* Fast-executing code */
*(.itcm_text*) /* Fast-executing code */
. = ALIGN(4);
} >ITCM_RAM AT> FLASH


I then assign the functions to the itcm_text region with __attribute__((section(“.itcm_ram”)))

The compiler and linker try to do something with that section, but nothing actually ends up there. Looking at my output.map file, I see the section has been added but is empty. Excerpt below:

.isr_vector 0x00200000 0x1c8
0x00200000 . = ALIGN (0x4)
*(.isr_vector)
.isr_vector 0x00200000 0x1c8 startup/startup_stm32f746xx.o
0x00200000 g_pfnVectors
0x002001c8 . = ALIGN (0x4)

.itcm_text 0x00000000 0x0 load address 0x002001c8
0x00000000 . = ALIGN (0x4)
*(.itcm_text)
*(.itcm_text*)
0x00000000 . = ALIGN (0x4)


Any thoughts would be much appreciated!

Before I go on to give advice here, let me state for the record that i’ve never tried to do with an ARM core device and GCC what you’re describing here, but I’m familiar in a general sense with the concept of placing a section of code that is “loaded” in ROM/FLASH and then copied/relocated to RAM, and have done this with different toolchains and MCUs other than the STM32.

I think you have the linker script syntax correct - in particular, the bit at the end of the .itcm_text section declaration (>ITCM_RAM AT >FLASH) is critical. You want to make sure that your itcm-destined code is loaded into ROM (flash), but is located in ITCM_RAM.

I think what you’re looking for is the appropriate attribute syntax that you add to all functions that you want placed in a non-standard section. Here’s what it would look like:

int foo(int bar) __attribute__((section(".itcm_text")))
{
    // Code
}


You’ll need to add the attribute directive shown in the example above to each function or variable declaration that you want to have placed in the .itcm_text section.

You might want to modify your linker command file to add some symbol definitions that will make it easier for your code to find (and copy) the .itcm_text section to ITCM_RAM

.itcm_text :
{
. = ALIGN(4);
itcm_text_start = .;
*(.itcm_text) /* Fast-executing code */
*(.itcm_text*) /* Fast-executing code */
. = ALIGN(4);
itcm_text_end = .;
} >ITCM_RAM AT >FLASH


When it comes time to copy the ITCM code in ROM to ITCM_RAM, you should be able to do something like this:

// The "variables" referenced here don't actually contain anything meaningful - they are defined as symbols
// within the linker script. To extract the value assigned to each of these symbols, you need to take the
// address-of them (use the & address-of operator); e.g.:
// unsigned int section_start = (unsigned int) &itcm_text_start;

extern const unsigned char itcm_text_start;	// Make these uint8_t/char so they are treated as byte pointers when address-of'ed
extern const unsigned char itcm_text_end;

unsigned int itcm_text_size = (unsigned int) (&itcm_text_end - &itcm_text_start); // Pointer math should will work if these are declared as a char/byte type
unsigned char *itcm_ram_addr = ??? // Fill this in - could also get it from linker symbol if you add one
memcpy(itcm_ram_addr, &itcm_text_start, itcm_text_size);


Caveat: I’ve written the above “off the cuff” after doing a little research - I’ve not actually tried or tested any of it. I’ve probably got one or more of the details wrong. I may need to do something like this in one of my own projects I’ll be working on soon so I figured I’d start to research it now and possibly answer laltmann’s question at the same time.

Do you happen to know how can i do the same for methods of a C++ obejct? Put methods in ITCM for better performance?

France

Hi,

There is a typo in the original post: the attribute used for placing functions in ITCM must be attribute((.itcm_text)), not .itcm_ram. This may explain why the .itcm_text section is empty...

Bernard (Ac6)


Thanks MSchultz and dautrevaux. I had indeed made a typo - corrected that now, and my test function does now show up in the .itcm_text section of my output.map file. With a few more changes to the linker script I was able to get my function successfully moved into ITCM RAM and verified with the debugger that it was running from that location.

I changed my memory sections definition a bit as well to make sure that the code doesn’t clobber the ISR vector table, which is loaded into the start of ITCM RAM by the startup script. I allocated 1kB for that table and started my section after:

/* Specify the memory areas */
MEMORY
{
ITCM_ISR (rx) : ORIGIN = 0x00000000, LENGTH = 1K
ITCM_RAM (rx) : ORIGIN = 0x00000400, LENGTH = 15K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 320K
FLASH (rx) : ORIGIN = 0x00200000, LENGTH = 1024K
}

I also added the symbol definitions as suggested so that I can memcpy the right section into that portion of memory later on. But it took an additional symbol in order to actually find the function data in Flash, to know where to copy from.

I based this on how the .data section is handled. There’s an extra symbol before that section is defined:

/* used by the startup to initialize data */
_sidata = LOADADDR(.data);

That gets picked up by the startup script to know where to load initialization data from to populate the .data section of ram. So my linker script ends up looking like:

/* Copy specific fast-executing code to ITCM RAM */
itcm_data = LOADADDR(.itcm_text);
.itcm_text :
{
. = ALIGN(4);
itcm_text_start = .;
*(.itcm_text)
*(.itcm_text*)
. = ALIGN(4);
itcm_text_end = .;
} >ITCM_RAM AT> FLASH

Then at the start of main() I have the following:

/* Load functions into ITCM RAM */
extern const unsigned char itcm_text_start;
extern const unsigned char itcm_text_end;
extern const unsigned char itcm_data;
memcpy(&itcm_text_start, &itcm_data, (int) (&itcm_text_end - &itcm_text_start));

And with that I’m good to go! Thanks again for the help.


@laltmann care to share your entire linker script and startup code?