2015-12-15 09:10 AM
Hello,
I am having a bit of a mysterious bug in here. I am working on STM32F427 chip and tryin to write a bootloader. I have a problem with copying memory from FLASH to RAM. Looks like there is a specific memory address in RAM towards which I can't seem to write data properly. If in flash memory I have a value 0x12345678 then after copying it to RAM I get 0xXXXX5678 (XXXX- random stuff that was already in RAM). This is happening only in this one particular region and it doesn't help at all what kind of pointers I am using to write to it (uint8_t*, uint32_t*). I have even tried creating a temporary value in RAM and copying to the problematic memory region and the same problem appeared. Memory sections seem to be aligned in linker script (. = ALIGN(4);) and memory addresses coming out of it used in copying seem to be aligned as well. The weird thing is that I can move the whole RAM memory in linker from 0x20000000 to 0x20000200 and the problem is moving to the same address related to the beginning of RAM. I have replicated the same problem on the STM32F429 Discovery board with the same code. I have found two other threads with exactly the same issue but with no answers. https://community.arm.com/thread/8464 https://my.st.com/public/STe2ecommunities/mcu/Lists/stm81/Flat.aspx?RootFolder=https%3a%2f%2fmy.st.com%2fpublic%2fSTe2ecommunities%2fmcu%2fLists%2fstm81%2fMemory%20issue%20on%20STM8L151G6&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580001E3853D9DB932A46A3FE4CD15CAB46FB¤tviews=236 I am bit stuck over here and any help will be apprieciated. #stm32-ram2015-12-15 09:36 AM
I have found two other threads with exactly the same issue but with no answers.
Forums are filled with people who can't answer their own problems, and when they do figure stuff out often don't bother to post back. One of your cites is for a STM8 which is a wholly different compiler and chip architecture. The other really doesn't provide enough data to be able to actually replicate the issue by anyone else. I'd be very cautious of the IT command and it's ability to restart.Are you doing this in assembler, or C? If C which version, and does turning off optimization impact things? What does the compiled code (assembler) look like?If the issue moves with linker memory base it's honestly more suggestive of some other utilization of that memory area, check the .MAP, and check the stack location.Can you provide an example that sufficiently demonstrates the problem to a third party?2015-12-15 09:47 AM
> specific memory address in RAM
Namely? > it doesn't help at all what kind of pointers I am using to write to it (uint8_t*, uint32_t*) How EXACTLY do you do the ''write to [RAM] using pointer''? How do you verify the content of RAM?> I have replicated the same problem on the STM32F429 Discovery board with the same code.
Can you post it? JW2015-12-16 01:53 AM
My linker script:
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = 0x2002FFFF; /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0xA000; /* required amount of heap 40kB*/
_Min_Stack_Size = 0x2800; /* required amount of stack 10kB*/
/* Specify the memory areas */
MEMORY
{
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
RAM (xrw) : ORIGIN = 0x20000400, LENGTH = 192K
CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K
}
/* Define output sections */
SECTIONS
{
_isrVectorFlashB = LOADADDR(.isr_vector);
/* The startup code goes first into FLASH */
.isr_vector :
{
. = ALIGN(4);
_isrVectorRamB = .;
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
_isrVectorRamE = .;
} >RAM AT>FLASH
.startup :
{
. = ALIGN(4);
*(.text.Reset_Handler)
*(.text.copyFlashToRam)
*(.text.copyFunction)
*(.text.fillZeroBss)
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
. = ALIGN(4);
} >FLASH
_textFlashB = LOADADDR(.text);
.text :
{
. = ALIGN(4);
_textRamB = .;
*(.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 */
_textRamE = .;
} >RAM AT> FLASH
_rodataFlashB = LOADADDR(.rodata);
.rodata :
{
. = ALIGN(4);
_rodataRamB = .;
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
_rodataRamE = .;
} >RAM AT> FLASH
_armExtabFlashB = LOADADDR(.ARM.extab);
.ARM.extab : {
. = ALIGN(4);
_armExtabRamB = .;
*(.ARM.extab* .gnu.linkonce.armextab.*)
. = ALIGN(4);
_armExtabRamE = .;
} >RAM AT> FLASH
_armFlashB = LOADADDR(.ARM);
.ARM : {
. = ALIGN(4);
_armRamB = .;
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
. = ALIGN(4);
_armRamE = .;
} >RAM AT> FLASH
_preinitFlashB = LOADADDR(.preinit_array);
.preinit_array :
{
. = ALIGN(4);
_preinitRamB = .;
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(4);
_preinitRamE = .;
} >RAM AT> FLASH
_initFlashB = LOADADDR(.init_array);
.init_array :
{
. = ALIGN(4);
_initRamB = .;
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
_initRamE = .;
} >RAM AT> FLASH
_finiFlashB = LOADADDR(.fini_array);
.fini_array :
{
. = ALIGN(4);
_finiRamB = .;
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(4);
_finiRamE = .;
} >RAM AT> FLASH
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
_dataFlashB = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(4);
_dataRamB = .;
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
_dataRamE = .;
} >RAM AT> FLASH
_siccmram = LOADADDR(.ccmram);
_ccramFlashB = LOADADDR(.ccmram);
.ccmram :
{
. = ALIGN(4);
_ccmRamB = .;
*(.ccmram)
*(.ccmram*)
. = ALIGN(4);
_ccmRamE = .;
} >CCMRAM AT> FLASH
/* 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;
_bssRamB = .;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
_bssRamE = .;
} >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
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}
2015-12-16 01:55 AM
Startup file:
.section .text.Reset_Handler
.weak Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
ldr sp, =_estack /* set stack pointer */
//copying procedures from flash to ram
bl copyFlashToRam
//clearing bss section
bl fillZeroBss
/* Call the clock system intitialization function.*/
bl SystemInit
/* Call static constructors */
bl __libc_init_array
/* Call the application's entry point.*/
bl main
bx lr
.size Reset_Handler, .-Reset_Handler
And copying functions:
/**
* @brief Function is copying memory from FLASH to RAM.
*
* @param ramB: beginning of ram where flash memory should be stored
* @param flashB: beginning of copied flash memory
* @param flashE: end of copied flash memory
*
* @retval None
*/
__attribute__ ((__section__(''.startup'')))
void copyFunction(volatile uint32_t * ramB,
volatile uint32_t * ramE,
volatile uint32_t * flashB){
unsigned int ctr = 0;
uint32_t temp = 0xDEADBEEF;
while(ramB <
ramE
){
//copy memory
*ramB = *flashB;
//at address 0x20000604 copying fails, therefore breakpoint
if(ramB == (volatile uint32_t *)(0x20000600)){
asm(''nop'');
}
if(*ramB != *flashB){
//I am trying to play with different sources of memory to copy from (FLASH, RAM) to no avail
asm(''nop'');
*
ramB
=
0xDEADBEEF
;
*
ramB
=
temp
;
ctr++;
}else{
//everything went correct, therefore keep copying
ramB++;
flashB++;
ctr
=
0
;
}
if(ctr > 2){
//I give up, just get through with it
asm(''nop'');
ramB++;
flashB++;
}
}
}
/**
* @brief Function is copying memory from FLASH to RAM.
* @note This function is being called from startup file.
* @param None
* @retval None
*/
__attribute__ ((__section__(''.startup''))) void copyFlashToRam(void){
copyFunction(&_isrVectorRamB, &_isrVectorRamE, &_isrVectorFlashB);
copyFunction(&_textRamB, &_textRamE, &_textFlashB);
copyFunction(&_rodataRamB, &_rodataRamE, &_rodataFlashB);
copyFunction(&_armExtabRamB, &_armExtabRamE, &_armExtabFlashB);
copyFunction(&_armRamB, &_armRamE, &_armFlashB);
copyFunction(&_preinitRamB, &_preinitRamE, &_preinitFlashB);
copyFunction(&_initRamB, &_initRamE, &_initFlashB);
copyFunction(&_finiRamB, &_finiRamE, &_finiFlashB);
copyFunction(&_dataRamB, &_dataRamE, &_dataFlashB);
copyFunction(&_ccmRamB, &_ccmRamE, &_ccramFlashB);
}
2015-12-16 02:01 AM
Section of interest from output.map:
.text 0x200005ac 0x808c load address 0x080003a8
0x200005ac . = ALIGN (0x4)
0x200005ac _textRamB = .
*(.text)
.text 0x200005ac 0x54 c:/eclipse/plugins/fr.ac6.mcu.externaltools.arm-none.win32_1.1.0.201503101257/tools/compiler/bin/../lib/gcc/arm-none-eabi/4.8.4/armv7e-m/fpu/crtbegin.o
*(.text*)
.text.main 0x20000600 0x60 ./src/main.o
0x20000600 main
.text.SystemClock_Config
0x20000660 0x98 ./src/main.o
0x20000660 SystemClock_Config
.text.MX_GPIO_Init
0x200006f8 0x1fc ./src/main.o
.text.safeFree
0x200008f4 0x40 ./src/privateDefines.o
0x200008f4 safeFree
.text.safeMalloc
Code of main() function in flash before copying:
080003fc: push {r7, lr}
080003fe: sub sp, #8
08000400: add r7, sp, #0
08000402: nop
08000404: nop
08000406: bl 0x8003cb8
0800040a: bl 0x800045c
0800040e: bl 0x8000778
08000412: b.n 0x8000416
Code of main() in RAM after copying:
main:
20000600: push {r7, lr}
20000602: sub sp, #8
20000604: add r7, sp, #0
76 asm(''nop'');
20000606: movs r4, #5
77 asm(''nop'');
20000608: nop
82 HAL_Init();
2000060a: bl 0x20003ebc <
HAL_Init
>
86 SystemClock_Config();
2000060e: bl 0x20000660 <
SystemClock_Config
>
90 __SVC();
20000612: bl 0x2000097c <
__SVC
>
91 while((__get_CONTROL() & 0x01) != 0)
20000616: b.n 0x2000061a <
main
+26>
94 asm volatile (''NOP'');
2015-12-16 02:04 AM
In the output from disassembly there is clearly a bug at line 6, where should be NOP not MOVS command.
I am not using any optimisations, I am using GCC 4.8.4 toolchain for ARM. This is a disassembled copyFunction() (maybe it will be of some help):
copyFunction:
080001d1: push {r7}
080001d3: sub sp, #28
080001d5: add r7, sp, #0
080001d7: str r0, [r7, #12]
080001d9: str r1, [r7, #8]
080001db: str r2, [r7, #4]
60 unsigned int ctr = 0;
080001dc: movs r3, #0
080001de: str r3, [r7, #20]
61 uint32_t temp = 0xDEADBEEF;
080001e0: ldr r3, [pc, #108] ; (0x8000250 <
copyFunction
+128>)
080001e2: str r3, [r7, #16]
63 while(ramB <
ramE
){
080001e4: b.n 0x800023e <copyFunction+110>
66 *ramB = *flashB;
080001e6: ldr r3, [r7, #4]
080001e8: ldr r2, [r3, #0]
080001ea: ldr r3, [r7, #12]
080001ec: str r2, [r3, #0]
69 if(ramB == (volatile uint32_t *)(0x20000600)){
080001ee: ldr r2, [r7, #12]
080001f0: ldr r3, [pc, #96] ; (0x8000254 <
copyFunction
+132>)
080001f2: cmp r2, r3
080001f4: bne.n 0x80001f8 <
copyFunction
+40>
70 asm(''nop'');
080001f6: nop
73 if(*ramB != *flashB){
080001f8: ldr r3, [r7, #12]
080001fa: ldr r2, [r3, #0]
080001fc: ldr r3, [r7, #4]
080001fe: ldr r3, [r3, #0]
08000200: cmp r2, r3
08000202: beq.n 0x800021a <
copyFunction
+74>
75 asm(''nop'');
08000204: nop
76 *ramB = 0xDEADBEEF;
08000206: ldr r3, [r7, #12]
08000208: ldr r2, [pc, #68] ; (0x8000250 <
copyFunction
+128>)
0800020a: str r2, [r3, #0]
77 *ramB = temp;
0800020c: ldr r3, [r7, #12]
0800020e: ldr r2, [r7, #16]
08000210: str r2, [r3, #0]
78 ctr++;
08000212: ldr r3, [r7, #20]
08000214: adds r3, #1
08000216: str r3, [r7, #20]
08000218: b.n 0x800022a <
copyFunction
+90>
81 ramB++;
0800021a: ldr r3, [r7, #12]
0800021c: adds r3, #4
0800021e: str r3, [r7, #12]
82 flashB++;
08000220: ldr r3, [r7, #4]
08000222: adds r3, #4
08000224: str r3, [r7, #4]
83 ctr = 0;
08000226: movs r3, #0
08000228: str r3, [r7, #20]
86 if(ctr > 2){
0800022a: ldr r3, [r7, #20]
0800022c: cmp r3, #2
0800022e: bls.n 0x800023e <
copyFunction
+110>
88 asm(''nop'');
08000230: nop
89 ramB++;
08000232: ldr r3, [r7, #12]
08000234: adds r3, #4
08000236: str r3, [r7, #12]
90 flashB++;
08000238: ldr r3, [r7, #4]
0800023a: adds r3, #4
0800023c: str r3, [r7, #4]
63 while(ramB <
ramE
){
0800023e: ldr r2, [r7, #12]
08000240: ldr r3, [r7, #8]
08000242: cmp r2, r3
08000244: bcc.n 0x80001e6 <copyFunction+22>
93 }
08000246: adds r7, #28
08000248: mov sp, r7
0800024a: ldr.w r7, [sp], #4
0800024e: bx lr
08000250: bkpt 0x00ef
08000252: ; <
UNDEFINED
> instruction: 0xdead
08000254: lsls r0, r0, #24
08000256: movs r0, #0
2015-12-16 04:09 AM
Did you try this at default clock i.e. HCLK source HSI, no PLL?
JW2015-12-16 04:13 AM
This is just after power up on its default settings, without touching clocks, peripherals or anything chip related.
2015-12-16 06:41 AM
I have got answer from other forum and it looks like that memory gets corrupted only at addresses, where breakpoints are being placed! Good thing is that it is not a code related thing, and code can work properly, but how to make a debugging in such an environment?