Putting STM32 code in ITCM with GUN GCC, calling other functions with wrong address - stm32

I wrote the following code and declared it in ITCM.
static void __attribute__((section(".itcm"))) TxMain(ULONG thread_input)
{
uint8_t i = 0;
for (;;)
{
i++;
if(i == 100){
i = 0;
tx_thread_sleep(100); /* go to sleep 100ms. */
}
}
}
My ld script has the following statement.
/* Specify the memory areas */
MEMORY
{
DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
RAM_D1 (xrw) : ORIGIN = 0x24000000, LENGTH = 512K
RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K
RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K
ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 2048K
}
/* Define output sections */
SECTIONS
{
.itcm :
{
. = ALIGN(4);
*(.itcm)
*(.itcm*)
. = ALIGN(4);
} >ITCMRAM
/* ... others ... */
}
When I run it, I check that TxMain is at 0xC, which is normal, but when I run tx_thread_sleep, it indicates that it is at 0x18, when in fact it is in Flash, i.e. at address 0x2000 ???? in the Flash,
screenshot with itcm exec
When itcm is not declared, the address is taken normally.
screenshot without itcm exec

Related

Strange LD behavior when section name is equal to output name

I have section in LDS script file
MEMORY
{
boot (r) : ORIGIN = 0x00000000, LENGTH = 0x10000
flash (rx) : ORIGIN = 0x00010000, LENGTH = 1080K
tcm (rw!x) : ORIGIN = 0x003F0000, LENGTH = 60k
itcm (rwx) : ORIGIN = 0x003FF000, LENGTH = 4k
ram (rw!x) : ORIGIN = 0x00400100, LENGTH = 192k - 0x100
}
SECTIONS
{
.tcm ALIGN(8) :
{
/* some other files */
*ate_app*.o(.bss .bss.* .scommon .sbss .dynbss COMMON)
/* some other files */
}>tcm AT>flash
/* other sections */
}
When my output file is ate_app.elf then linking fails with .tcm section overlap error.
When I change output name to qwerty.elf or change the ate_app.o directive to something else linking goes successfuly.
Why is this strange behavior?

STM32H7 bank swap break at address 0x81006fe

I am trying to do a bank swap with the ST32 H743ZI2. I wasted much of time to fix it but I didn't get it. Maybe because I'm new in STM32 controllers.
I copied the bank swap code from STM32CubeH7 Firmware Examples and did a few modifications regarding to gpio configuration in CubeMX. I did them because I want to implicate the code in a existing project without the stm32h7xx_nucleo headers.
Following the Code for Bank1:
HAL_FLASH_Unlock();
HAL_FLASH_OB_Unlock();
while (1)
{
/* Wait for BUTTON_USER is released */
if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == 1)
{
while (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == 1);
/* Get the Dual boot configuration status */
HAL_FLASHEx_OBGetConfig(&OBInit);
/* Get FLASH_WRP_SECTORS write protection status */
OBInit.Banks = FLASH_BANK_1;
HAL_FLASHEx_OBGetConfig(&OBInit);
/* Check Swap FLASH banks status */
if ((OBInit.USERConfig & OB_SWAP_BANK_ENABLE) == OB_SWAP_BANK_DISABLE)
{
/*Swap to bank2 */
/*Set OB SWAP_BANK_OPT to swap Bank2*/
OBInit.OptionType = OPTIONBYTE_USER;
OBInit.USERType = OB_USER_SWAP_BANK;
OBInit.USERConfig = OB_SWAP_BANK_ENABLE;
HAL_FLASHEx_OBProgram(&OBInit);
/* Launch Option bytes loading */
HAL_FLASH_OB_Launch();
/*
as the CPU is executing from the FLASH Bank1, and the I-Cache is enabled :
Instruction cache must be invalidated after bank switching to ensure that
CPU will fetch correct instructions from the FLASH.
*/
SCB_InvalidateICache();
HAL_NVIC_SystemReset();
}
else
{
/* Swap to bank1 */
/*Set OB SWAP_BANK_OPT to swap Bank1*/
OBInit.OptionType = OPTIONBYTE_USER;
OBInit.USERType = OB_USER_SWAP_BANK;
OBInit.USERConfig = OB_SWAP_BANK_DISABLE;
HAL_FLASHEx_OBProgram(&OBInit);
/* Launch Option bytes loading */
HAL_FLASH_OB_Launch();
/*
as the CPU is executing from the FLASH Bank1, and the I-Cache is enabled :
Instruction cache must be invalidated after bank switching to ensure that
CPU will fetch correct instructions from the FLASH.
*/
SCB_InvalidateICache();
}
}
else
{
#ifdef FLASH_BANK1
/* Toggle LED1 */
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
/*Turn Off LED2*/
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_1, 0);
#else
/* Toggle LED2 */
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_1);
/* Turn off LED1 */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, 0);
#endif
/* Insert 100 ms delay */
HAL_Delay(100);
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
The code for bank1 and bank2 are equal except linkerscript.
I split Flash in two areas which have 1024kb each. In following you can see the code for bank1.
/* Specify the memory areas */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
RAM_D1 (xrw) : ORIGIN = 0x24000000, LENGTH = 512K
RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K
RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K
ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
}
In linkerscript for bank2 I changed flash start address to 0x08100000.
Now I have following problem. If I load in order code for bank1 and code for bank2 press the Button1 and Press the Resetbutton I get following error message:
Break at address "0x81006fe" with no debug information available, or outside of program code.
I already successfully checked if there is placed some code with STM32 Utility.
If I load the codes in reverse order the banks get swapped once. Independently if Button1 gets pressed before system reset or not..
I already checked some forums without success.
Does anyone know where the problem could be?
There were two problems in code.
Linker script was splited up in two parts. Linker script had to rebuild in original state regarding to flash. The code for bank2(0x081000000) needs to locate with an extern software like stm32 utility now.
Vector table was relocate at wrong address in system_stm32h7xx.c

STM32F103 Protect section of flash memory

I cannot protect the data in USER_FLASH when I disconnect the ST-Link, connect it and then program the microcontroller via OpenOCD.
I test it with the option (NOLOAD) in the linker script but the data always deleted.
STM32F103C8TX_FLASH.ld:
...
/* Memories definition */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 63K
USER_FLASH (xrw) : ORIGIN = 0x0800FC00, LENGTH = 1K
}
/* Sections */
SECTIONS
{
/* User data to be stored in the flash memory goes into USER_FLASH */
.user_data_flash (NOLOAD):
{
. = ALIGN(4);
*(.user_data_flash) /* .user_data_flash sections */
*(.user_data_flash*) /* .user_data_flash sections */
. = ALIGN(4);
} >USER_FLASH
...
The function works well while not disconnect the programmer:
void testFlash(void){
uint32_t temp = 0;
//writeFlash(test);
//Flash_Read_Data(0x0800FC00, temp);
temp = readFlashTest((uint32_t *)0x0800FC00);
temp = temp + 4;
writeFlash((uint32_t)temp);
}
uint32_t readFlashTest(uint32_t *mem){
uint32_t temp = 0;
HAL_FLASH_Unlock();
temp = *mem;
HAL_FLASH_Lock();
return temp;
} void writeFlash(uint32_t toWrite){
eraseFlash(); // Necesario si o si sino no escribe
HAL_FLASH_Unlock();
HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, 0x0800FC00, toWrite);
HAL_FLASH_Lock();
}
The solution is to set BOOT0 and BOOT1 to 1. This way, the boot mode is done from the Embedded SRAM, not from the Main Flash memory.

STM32H743ZI NUCLEO 144 & LWIP - Can't Ping The Board

Hope all is going well.
I'm trying to ping STM32H743ZI NUCLEO 144 using LWIP middle-ware. Code generated by CubeMX.
Configurations:
Set the HCLK to 400 MHz
Enabled the CPU ICache and DCache (under Cortex_M7 Configuration)
Enabled MPU (Region0, Region1 & Region2)
Enabled LWIP
Selected LAN8742 as the Driver_PHY (under LwIP>Platform Settings)
DHCP disabled (IP, MASK: 255,255,255,000 , Gateway: Modem IP)
RTOS disabled
LWIP_HTTPD, LWIP_HTTPD_CGI enabled
LWIP_HTTPD_SSI enabled
LWIP_HTTPD_MAX_TAG_NAME_LEN set to 16
ICMP enabled (LWIP_BROADCAST_PING and LWIP_MULTICAST_PING in LwIP Key Options>IPMP Options).
Code Generated for Keil V5
MX_LWIP_Process added to the main function in While loop.
while(1)
{
MX_LWIP_Process();
}
I don't know how should I configure the CubeMX or change the generated code to be able to ping my board.
My_File
this will probably help you (it did for me):
Information about this issue can be found here.
https://community.st.com/s/article/FAQ-Ethernet-not-working-on-STM32H7x3
Memory buffers need to be assigned to RAM that can be accessed by the Ethernet
peripheral.
You may need to adjust the tour stack/heap size.
The default Ethernet GPIOs speed may be too low.
You may need to configure the MPU.
You may likely need to change your linker script.
On this page you will find good information:
https://github.com/MX-Master/STM32H7_Nucleo-H743ZI_Ethernet_LwIP
The HAL_Delay mentioned may not be required, though.
In the file lan8742.c (driver), I added an extra line for the LAN8742_Init function, around line 190, to set auto-negotiation:
// Link did not come up after HW reset.
pObj->IO.WriteReg(pObj->DevAddr, LAN8742_BCR, LAN8742_BCR_AUTONEGO_EN);
So that function looks like:
// Used in ethernetif.c, 363, static void low_level_init(struct netif *netif)
int32_t LAN8742_Init(lan8742_Object_t *pObj)
{
uint32_t tickstart = 0, regvalue = 0, addr = 0;
int32_t status = LAN8742_STATUS_OK;
if(pObj->Is_Initialized == 0)
{
if(pObj->IO.Init != 0)
{
/* GPIO and Clocks initialization */
pObj->IO.Init();
}
/* for later check */
pObj->DevAddr = LAN8742_MAX_DEV_ADDR + 1;
/* Get the device address from special mode register */
for(addr = 0; addr <= LAN8742_MAX_DEV_ADDR; addr ++)
{
if(pObj->IO.ReadReg(addr, LAN8742_SMR, &regvalue) < 0)
{
status = LAN8742_STATUS_READ_ERROR;
/* Can't read from this device address
continue with next address */
continue;
}
if((regvalue & LAN8742_SMR_PHY_ADDR) == addr)
{
pObj->DevAddr = addr;
status = LAN8742_STATUS_OK;
break;
}
}
if(pObj->DevAddr > LAN8742_MAX_DEV_ADDR)
{
status = LAN8742_STATUS_ADDRESS_ERROR;
}
/* if device address is matched */
if(status == LAN8742_STATUS_OK)
{
/* set a software reset */
if(pObj->IO.WriteReg(pObj->DevAddr, LAN8742_BCR, LAN8742_BCR_SOFT_RESET) >= 0)
{
/* get software reset status */
if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BCR, &regvalue) >= 0)
{
tickstart = pObj->IO.GetTick();
/* wait until software reset is done or timeout occurred */
while(regvalue & LAN8742_BCR_SOFT_RESET)
{
if((pObj->IO.GetTick() - tickstart) <= LAN8742_SW_RESET_TO)
{
if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BCR, &regvalue) < 0)
{
status = LAN8742_STATUS_READ_ERROR;
break;
}
}
else
{
status = LAN8742_STATUS_RESET_TIMEOUT;
}
}
}
else
{
status = LAN8742_STATUS_READ_ERROR;
}
}
else
{
status = LAN8742_STATUS_WRITE_ERROR;
}
}
}
// Jack 2019-03-25, Link did not come up after HW reset.
pObj->IO.WriteReg(pObj->DevAddr, LAN8742_BCR, LAN8742_BCR_AUTONEGO_EN);
if(status == LAN8742_STATUS_OK)
{
tickstart = pObj->IO.GetTick();
/* Wait for 2s to perform initialization */
while((pObj->IO.GetTick() - tickstart) <= LAN8742_INIT_TO)
{
}
pObj->Is_Initialized = 1;
}
return status;
}

Place bootloader after the Application in Flash Memory

I wrote a Bootloader for my STM32F042k6 board that functions pretty well. On System Reset the Bootloader is launched and can later jump to the Application. That was great:). Now I wish to do the opposite in my Flash. I wish Launch my Bootloader at a start address other than 0x08000000 lets say at 0x08007000. When I do the modifications in the Linker Script the Programm cannot be debugged. In simple words I wish to place my bootloader at the end of my Flash. Without forget that the Bootloader is always the first Code to run after Reset. Thanks in advance for your help and comments
Here is my Linker Script:
/* Entry Point */
ENTRY(Boot_Reset_Handler)
/* Highest address of the user mode stack */
_estack = 0x20001800; /* end of 6K RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0; /* required amount of heap */
_Min_Stack_Size = 0x80; /* required amount of stack */
/* Specify the memory areas */
MEMORY
{
BOOTLOADER (rx) : ORIGIN = 0x08007000, LENGTH = 4K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 28K
RAM (xrw) : ORIGIN = 0x200000C0, LENGTH = 6K - 192
MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K
}
/* Define output sections */
SECTIONS
{
/* The startup code goes first into BOOTLOADER */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >BOOTLOADER
/* The program code and other data goes into BOOTLOADER */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >BOOTLOADER
/* Constant data goes into BOOTLOADER */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >BOOTLOADER
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >BOOTLOADER
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >BOOTLOADER
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >BOOTLOADER
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >BOOTLOADER
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
} >BOOTLOADER
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM AT> BOOTLOADER
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(4);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(4);
} >RAM
/* MEMORY_bank1 section, code must be located here explicitly */
/* Example: extern int foo(void) __attribute__ ((section (".mb1text"))); */
.memory_b1_text :
{
*(.mb1text) /* .mb1text sections (code) */
*(.mb1text*) /* .mb1text* sections (code) */
*(.mb1rodata) /* read-only data (constants) */
*(.mb1rodata*)
} >MEMORY_B1
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}
You're out of luck I'm afraid, your processor will always start running code from the address 0x00000000 (sort of, it will look at 0x00000004 to see where the reset vector is).
There are a number of boot pins which change whether flash or RAM is aliased at address 0x00000000, but you can't choose which area of flash, it will always be 0x08000000 onwards. If you want to your custom bootloader, and have it be the first thing run, it needs to be at the start of flash.
What is the problem you're trying to solve by moving the bootloader? There is probably another possible solution.
I'm afraid you're looking after a solution for the wrong problem. Programs loaded by a bootloader can be debugged. I'm doing it all the time.
So something goes wrong before your application hits the first breakpoint set by the debugger.
A probably incomplete list of things to check
The bootloader does something that makes debugging impossible
disables the SWD pins
does not jump to the application reset handler
starts a watchdog
does not disable all possible interrupts
does not return to thread mode
wrong value in the stack pointer
loading the application in the debugger damages the bootloader
e.g. erases the wrong flash sectors
the application startup code fails
problem with the application linker script
sets wrong value in the stack pointer
sets wrong value in NVIC->VTOR - check this one first if you're using HAL
Normally, bootloader is the first piece of code that first executed. And with this way, it is not possible to relocate the bootloader to other memory partition.
However, there is another concept that able to relocate the bootloader to any memory address. That is the bootloader is only for update software later. With this approach, your main software will be the boot code. And when there is request to update, you jump to bootloader and do update software then reboot for normal operation. The drawback of this approach is that if the updated software fail, there isn't any recovery mechanism and you need to reflash by flashing tools.
The Microsoft Jacdac project places a bootloader in the last 4K of the STM32G0 flash, which has 32K to start with. I found this out the hard way when I tried to use the last page of flash for persistent storage.
The linker.ld file for the bootloader created during build has the content:
MEMORY {
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 8K
FLASH (rx) : ORIGIN = 0x8000000 + 32K - 4K, LENGTH = 4K
}
INCLUDE jacdac-stm32x0/ld/gcc_arm_bl_at_end.ld
The file jacdac-jacdac-stm32x0/ld/gcc_arm_bl_at_end.ld can be found on GitHub at: https://github.com/microsoft/jacdac-stm32x0/blob/05f7b6913a0f6cfcd7a15252daff773ead2834da/ld/gcc_arm_bl_at_end.ld