• We’re currently investigating an issue related to the forum theme and styling that is impacting page layout and visual formatting. The problem has been identified, and we are actively working on a resolution. There is no impact to user data or functionality, this is strictly a front-end display issue. We’ll post an update once the fix has been deployed. Thanks for your patience while we get this sorted.

My MCU hangs when i jump to an address in flash memory.. (SOLVED !)

Hi, i made a small bootloader that can load an application through xmodem 1k and store that application in flash memory.
Programming works, i have made a small memory dump function to compare the content of the memory with the application binfile. I verified it with a hexviewer and the data is the same. The application i made is really simple, it just makes a pin low so a led will start to emit light. And then hangs into a loop. I have done this in assembly as a test. But as soon as i jump to the application address, my MCU stops responding. Unfortunately i have no JTAG device so i cannot see what is going on.

The clock and both uarts are running as is the PIO controller that controls the state of the output pins. This is all setup in the bootloader.
I have one uart setup as a debug uart where all data is dumped to, to see what is going on. The other connects to TERA TERM so i have a small terminal emulator in the bootloader with some commands such as to upload the application bin file and to start the application.

The first 64KB is for the bootloader and the application starts at address 0x00110000. The flash memory has a size of 256KB, so i have enough space.
The flash starts at 0x00100000.

I have tried everything, but i do not know why it hangs. I tested for misalignment by reading the data at 32bits wide to see if that goes wrong but it is ok.

My MCU is a sam7s256.

What could i have forgotten ?

Here are some code snippets :
I tried it both in c and with inline assembly. But it does not work.

Code:
#define APP_START_ADDRESS		(*((volatile uint32_t *) 0x00110000)) // =FLASH BASE + 64k.

Code:
static void (*fp)(void); //Execute from address. 

void StartApplication(void)
{

	uint32_t *p;

			AT91C_BASE_AIC->AIC_EOICR = 0xFFFFFFFF;   //Disable all interrupts.
			AT91C_BASE_AIC->AIC_IDCR  = 0xFFFFFFFF;
			AT91C_BASE_PIOA->PIO_SODR = LED1 | LED2 | LED3 | LED4;  				//set leds off.
			
  p = (uint32_t *)&APP_START_ADDRESS;
	Sci1_Puts("Start address = ");
	Sci1DumpHex2((uint32_t)p);
	Sci1_Puts("\r\nExecute...");
	

	asm volatile(
			"mov	r0, #1114112					\r\n"
			"mov		  lr,pc							\r\n"		
			"mov			pc,r0							\r\n"		
			
			);

/*
  fp = (void (*)(void))*p;
  fp();

*/

A 32 bit read of the address works :
Code:
void Test(void)
{
	uint32_t *pointer;
	uint32_t	t;	
	
	pointer = (uint32_t *)&APP_START_ADDRESS;

	Sci1_Puts("DUMP address = ");
	Sci1DumpHex2((uint32_t)pointer);
	Sci1_Puts("\r\n");
	Sci1_Puts("DUMP data = ");
	t = *pointer;
	Sci1DumpHex2(t);
	Sci1_Puts("\r\n");


}
 
Last edited:
What does the linker script show for the memory region at 0x0011000?

And is your programmer programming the whole flash memory with the bootloader and the app?
 
Last edited:
@ uclabachelor :
My programmer does not program the entire flash only the flash pages needed.
Anyway, after programming the application, it should still function.

@ nickbits:
I tried that but it does not function either.
It is as if my memory controller does a program abort. But it should not for these are valid memory addresses and it does not have any memory protection.

I devised a test.
I made a void function with no arguments called TEST in side my bootloader program.

Code:
void TEST (void)
{
	uint32_t *pointer;
	uint32_t	t;	
	
	pointer = (uint32_t *)&APP_START_ADDRESS;
	Sci1_Puts("TEST\r\n");
	Sci1_Puts("DUMP address = ");
	Sci1DumpHex2((uint32_t)pointer);
	Sci1_Puts("\r\n");
	Sci1_Puts("DUMP data = ");
	t = *pointer;
	Sci1DumpHex2(t);
	Sci1_Puts("\r\n");
	
	while (1);

}
I looked the address of the function TEST up in the map file.

I then modified my StartApplication function to jump to that address :
0x001014e0.

Code:
void StartApplication(void)
{

	uint32_t *p;

			AT91C_BASE_AIC->AIC_EOICR = 0xFFFFFFFF;   //Disable all interrupts.
			AT91C_BASE_AIC->AIC_IDCR  = 0xFFFFFFFF;
			AT91C_BASE_PIOA->PIO_SODR = LED1 | LED2 | LED3 | LED4;  				//set leds off.
			
  //p = (uint32_t *)&APP_START_ADDRESS;
	
	p = (uint32_t *)0x001014e0 ;
	Sci1_Puts("Start address = ");
	Sci1DumpHex2((uint32_t)p);
	Sci1_Puts("\r\nExecute...");
	

/*
	asm volatile(
			"mov	r0, #1114112					\r\n"
			"mov		  lr,pc							\r\n"		
			"mov			pc,r0							\r\n"		
			
			);
*/

  fp = (void (*)(void))*p;
  fp();


}

I checked the map file after compilation and linking again to make sure the address is still the same.
I then programmed this bootloader version into my my controller and i did a Start application which should jump to the address 0x001014e0.
But it does the same thing it hangs.


Maybe it is the call stack. I just do not get it yet. :hmm:

map file :

Code:
*menu.o(.text)
 .text          0x001014cc      0x324 ./src/menu.o
                0x001014cc                ResetMcu
                0x001014e0                TEST
                0x00101538                HexDump2048
                0x0010160c                Testje
                0x00101658                StartApplication
                0x001016c4                WriteHex00
                0x00101718                WriteHex55
                0x00101770                menutext

Start address = 00 10 14 E0
Execute...
 
Last edited:
Still have not solved it.

The inline assembly with direct loading to the pc is not a good idea.

This is a more proper way :

Code:
	asm volatile(
			"mov	r0, #1114112		\r\n"
			"bx		r0					 \r\n"		
		
			
			);

But it also does not work...

:|
 
yaaaaaaaahhhoooooooooooooooooooooo!!!! 🙂

I looked through bootloader examples on the internet and i found this code :


Code:
	void(*fncall)(void)=(void*)p;
	fncall();
Where p holds the address of the function.

So i implemented it and removed the static declaration of the function pointer, see my first post.

Code:
	uint32_t *p;

			AT91C_BASE_AIC->AIC_EOICR = 0xFFFFFFFF;   //Disable all interrupts.
			AT91C_BASE_AIC->AIC_IDCR  = 0xFFFFFFFF;
			AT91C_BASE_PIOA->PIO_SODR = LED1 | LED2 | LED3 | LED4;  				//set leds off.
			
  //p = (uint32_t *)&APP_START_ADDRESS;
	
	p = (uint32_t *)0x001014e0 ;
	Sci1_Puts("Start address = ");
	Sci1DumpHex2((uint32_t)p);
	Sci1_Puts("\r\nExecute...");
	
	
	void(*fncall)(void)=(void*)p;
	fncall();

And now it works. 🙂
 
But i do not understand why the static declaration of the functionpointer does not work ? :hmm:


This does not work :
Code:
static void (*fp)(void); //Execute from address. 

void StartApplication(void)
{
  uint32_t *p;
			
  p = (uint32_t *)&APP_START_ADDRESS;
	
  fp = (void (*)(void))*p;
  fp();

This works :

Code:
void StartApplication(void)
{
	uint32_t *p;
		
  p = (uint32_t *)&APP_START_ADDRESS;
	
	void(*fncall)(void)=(void*)p;
	fncall();
}

Can anybody explain to me what could be going wrong ?
I am still a bit fresh with function pointers... :|
 
Meh, the jump to my TEST function inside my bootloader program works.
But when i jump to the application start address 0x00110000, the mcu hangs
again.

What is going on here ?
 
I think the GCC linker is changing the jump address. That can be the only explanation. It works within the bootloader program but not outside it.

But how do i solve that ?
 
When i look in the listfile , everything is correct. The address must be modified when the linker is busy with it. But i cannot see that in the map file.

Code:
320              		.loc 1 45 0
 321 01d0 1138A0E3 		mov	r3, #1114112	@ tmp142,
 322 01d4 0FE0A0E1 		mov	lr, pc
 323 01d8 13FF2FE1 		bx	r3	@ tmp142
 
I placed some volatile keywords but that does not help either.

Code:
void StartApplication(void)
{
	volatile uint32_t *p;

			AT91C_BASE_AIC->AIC_EOICR = 0xFFFFFFFF;   //Disable all interrupts.
			AT91C_BASE_AIC->AIC_IDCR  = 0xFFFFFFFF;
			AT91C_BASE_PIOA->PIO_SODR = LED1 | LED2 | LED3 | LED4;  				//set leds off.
			
	p = (uint32_t *)&APP_START_ADDRESS;
	
	Sci1_Puts("Start address = ");
	Sci1DumpHex2((uint32_t)p);
	Sci1_Puts("\r\nExecute...");

	volatile void(*fncall)(void)=(void*)p;
	fncall();
}

Why is the linker modifying the application start address ? Does anybody know ?

Why does this work out of the box with commercial compilers but not with GCC compiler and linker ?

Is it a bug or is what ?
 
If the linker's modifying the address you probably can't just tell it to run a particular address in memory. In that case there should be some way of labeling the start point so that the linker sees it and the C file can call it. I assume you're writing the application in some separate assembly file?

Maybe if you compile a test application that includes a function call with -S (assembly code output), you can get an idea of the proper function calling convention?
 
Indeed.

What i understand of it is that the compiler creates from the different source files (modules) object files with temporary addresses.
The linker then creates one big elf file where all jump addresses are resolved and set correctly.

I suspect that the linker or compiler has a safety setting that jump addresses are not allowed outside the program code.
Since my program is 25K in size and I want to reach an address at Base address + 64k (0x00110000), this does not work.

Indeed I need to modify the linker file to allow a jump to address 0x00110000.
I did an attempt yesterday by padding another 64K of .text to my existing 25k to be able to reach that address but it failed miserably.
I stopped because I was tired and have a cold.
 
What i think is because i use the MEMORY command, is that i am limited to what is available.

i think if i add another section :

Code:
.padding :
{
.=.+65535;
. = ALIGN(4);
} >ROM

maybe it should work. But i won't be able to test it until this evening.




Code:
/**************************************************************************
* W-ARM linker script V2.0 for SAM7 series  = ARM7TDMI 
***************************************************************************/

OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")     /* output format */
OUTPUT_ARCH(arm)        /* architecture */

ENTRY(_start)  /*First executable instruction can be found here */

MEMORY {    /* memory map of ARM MCU */
ROM (rx)  : ORIGIN = 0x00100000, LENGTH = 0x40000
RAM (rwx) : ORIGIN = 0x00200000, LENGTH = 0xF000
}

/* The sizes of the stacks used by the application. */
C_STACK_SIZE = 4096;
IRQ_STACK_SIZE = 80;
FIQ_STACK_SIZE = 36;
SVC_STACK_SIZE = 512;
ABT_STACK_SIZE = 12;
UND_STACK_SIZE = 0;


SECTIONS
{
	.reset :	/* Startup code (ROM vectors and reset handler) */ 
		{ 
		*startup.o (.text)
		. = ALIGN(4);
		} >ROM

	.fastcode :	/* All the instruction code in ROM copied to RAM are stored in ROM here */
		{
		__fastcode_load = LOADADDR (.fastcode);
		__fastcode_start = .;
		*isr_asm.o (.text)	/* RAM vectors and assembler parts of the interrupt routines are placed in the isr_asm.s file*/
		. = ALIGN (4);
		*isr.o (.text)			/* All interrupt service routine code is placed in the isr.c file*/
		. = ALIGN (4);
		*fastexec.o (.text)	/* All fast executing code is placed in the fastexec.c file */
		. = ALIGN (4);
		__fastcode_end = .;
		} >RAM AT>ROM

	.text :	/* All the instruction code not copied to RAM are stored in ROM here */
		{
		*inithardware.o (.text)
		*isr_ctrl.o (.text)
		*low_level_init.o (.text)
		*main.o (.text)
		*menu.o (.text)
		*os_functions.o (.text)
		*sci.o (.text)
		*semi_stdio.o (.text)
		*string.o (.text)
		*timer.o (.text)
		*xmodem.o (.text)
		. = ALIGN (4);
		} >ROM

	.data :	/* All global and static variables are stored here */
		{
		__data_load = LOADADDR (.data);
		__data_start = .;
		*(.data)
		. = ALIGN (4);
		__data_end = .;
		} >RAM AT>ROM

	.bss :	 /* Static variables initialized to 0x00*/
		{
		__bss_start = . ;
		*(.bss). = ALIGN (4);
		__bss_end = .;
		} >RAM

	.stack :	 /* All the stacks */
		{
		__stack_start = .;

		. += IRQ_STACK_SIZE;
		. = ALIGN (4);
		__irq_stack_top = . ;

		. += FIQ_STACK_SIZE;
		. = ALIGN (4);
		__fiq_stack_top = . ;

		. += SVC_STACK_SIZE;
		. = ALIGN (4);
		__svc_stack_top = . ;

		. += ABT_STACK_SIZE;
		. = ALIGN (4);
		__abt_stack_top = . ;

		. += UND_STACK_SIZE;
		. = ALIGN (4);
		__und_stack_top = . ;

		. += C_STACK_SIZE;
		. = ALIGN (4);
		__c_stack_top = . ;

		__stack_end = .;
		} >RAM

}

/*** EOF ***/
 
Last edited:
Another option i can try is to create a application.o.
It contains one function :

Code:
void application (void)


I add this to my linker script ;
Code:
.application:
{
.=0x00110000;
*application.o(.text)
. = ALIGN (4);
} > ROM

This way, the address 0x00110000 becomes visible for the linker.
And i should be able to jump to it.
After uploading an application, the contents of that address changes but that does not matter.
 
Damn it. How do i get that god forsaken linker LD to put my application at 0x00110000;

In the manpage of LD it says that when you do this :

Code:
. = 0x00110000;

That the linker will continue at that address.
But that is not the case. The counter [.] can only add and not set hard addresses.

I am getting tired and sad...

Has anybody some experience with linker LD ?
 
Okay, so you link to elf format, then what happens? Does your flash loader use elf? Or do you convert to a raw binary format and tell it where to load it? I assume the former since you said it knows what sections to write.

You say ld is modifying where things are, but the map file (which it's outputting) should reflect where things are. Are you sure that it's not actually the flash programmer that's putting things in a place where you aren't expecting it to?
 
Maybe this will work :

Code:
		. = ALIGN (0x00110000);
		*application.o (.text)
		. = ALIGN (4);

The map file seems to show the correct address.

Code:
 *application.o(.text)
 .text          0x00110000       0x20 ./src/application.o
                0x00110000                Application
                0x00110020                . = ALIGN (0x4)
 
I used an example makefile and changed it a tiny bit to suit my needs.

Code:
# Automatically generated by W-ARM !
# Do not edit this file with an editor that replaces tabs with spaces !
################################################################################

CC = arm-elf-gcc
AS = arm-elf-gcc -x assembler-with-cpp
CREATE_OUTPUT_FILE = arm-elf-objcopy -O binary

SRC = ./src/application.c ./src/fastexec.c ./src/inithardware.c ./src/isr.c ./src/isr_ctrl.c ./src/low_level_init.c ./src/main.c ./src/menu.c ./src/os_functions.c ./src/sci.c ./src/semi_stdio.c ./src/string.c ./src/timer.c ./src/xmodem.c
ASRC = ./src/isr_asm.s ./src/startup.s

USR_INC_DIR = ./inc
USR_LIB_DIR = 
################################################################################

INC_DIR  = $(patsubst %,-I%, $(USR_INC_DIR))
LIB_DIR  = $(patsubst %,-L%, $(USR_LIB_DIR))

OBJS = $(ASRC:.s=.o) $(SRC:.c=.o)

MCU_FLAGS = -mcpu=arm7tdmi

# optimisation level
OPT = -O1 

#Assemble assembly source files to object code   *.s to *.o  .
AS_FLAGS = $(MCU_FLAGS) -g -gdwarf-2 -Wa,-amhls=$(<:.s=.lst)

#compile and assemble C source files to object code   *.c to *.o  .
CP_FLAGS = $(MCU_FLAGS) $(OPT) -gdwarf-2 -fomit-frame-pointer -Wall -Wstrict-prototypes -fverbose-asm -Wa,-ahlms=$(<:.c=.lst)

# link all objects to elf file   *.o to *.elf .
LD_FLAGS = $(MCU_FLAGS) -nostartfiles -T./prj/warm_ld.ld -Wl,-Map=./output/bootloader_xmodem.map,--cref,--no-warn-mismatch $(LIB_DIR)

# Generate dependency information
CPFLAGS += -MD -MP -MF .dep/$(@F).d

# Eye candy.
begin:
	@echo
	@echo ---------------- begin ----------------
	@echo

finished:
	@echo
	@echo Errors none. 
	@echo
	@echo Output format = binary
	@echo
	@echo Project name = bootloader_xmodem
	@echo

end:
	@echo
	@echo ---------------- end ----------------
	@echo

clean_message:
	@echo
	@echo Cleaning directories of current project : bootloader_xmodem
	@echo

# Display compiler version information.
gccversion:
	@$(CC) --version

#Excute from here.
all: begin gccversion ROM finished move_files end

#copy files to new destination.
move_files:
	@cp ./src/*.lst ./list/
	@cp ./src/*.o  ./object/
	@-rm -f ./src/*.lst
	@-rm -f ./src/*.o

# create output files.
ROM: $(OBJS) ./output/bootloader_xmodem.elf ./output/bootloader_xmodem.bin

%o : %c
	$(CC) -c $(CP_FLAGS) -I . $(INC_DIR) $< -o $@
	
%o : %s
	$(AS) -c $(AS_FLAGS) $< -o $@

%elf: $(OBJS)
	$(CC) $(OBJS) $(LD_FLAGS) $(LIBS) -o $@

%bin: %elf
	$(CREATE_OUTPUT_FILE) $< $@



clean: begin gccversion deletefiles clean_message end

deletefiles:
	@-rm -f $(OBJS)
	@-rm -f $(SRC:.c=.c.bak)
	@-rm -f $(SRC:.c=.lst)
	@-rm -f $(ASRC:.s=.s.bak)
	@-rm -f $(ASRC:.s=.lst)
	@-rm -fR .dep
	@-rm -f ./output/bootloader_xmodem.elf 
	@-rm -f ./output/bootloader_xmodem.map 
	@-rm -f ./output/bootloader_xmodem.bin 
	@-rm -f ./list/*.lst
	@-rm -f ./object/*.o

#
# Include the dependency files, should be the last of the makefile
#
-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*)

# Listing of phony targets.
.PHONY : all begin finish end sizebefore sizeafter gccversion build elf hex lss sym clean clean_list program

# *** EOF ***
 
No, i convert it to a pure binary with objcopy.

Instead of doing that, try having the link script specify to output binary directly. Change the OUTPUT_FORMAT specifier to:

OUTPUT_FORMAT(binary);

It's probably not ld that was putting things where you didn't expect but objcopy. This method is what I've used for all of my MCU flash images.

Anyway, when you said this:

My programmer does not program the entire flash only the flash pages needed.
What did it mean exactly? Just that you give it an offset and it programs from there? It sounded to me like you were saying it knows where there are gaps in the file, something it wouldn't get from raw binary.
 
Back
Top