2011-09-09 01:35 AM
Hello,
I'm developping an application with bootloader. Today I'm using USART1 to communicate with the host PC, and I'm using a software reset to enter bootloader mode on demand (bootloader check if it's a software reset, if it is, it doesn't start the app code and start loader code).I don't use any interrupt in the bootloader, so once application download is complete, I can just set the stack and ''goto'' application entry address.Now my problem ... new version will include a USB connector (FS, not HS) for communication with the host PC (no need to buy an FTDI cable ...).So I will have to use interrupts in my bootloader (for USB, and because USART can't be blocking anymore ...).But if I use interrupts, I can't jump directly to user code, I must reset before, BUT if I do a software reset, the bootloader will not start application code (current behavior).So now I have to switch between two software reset sources, any idea ?Thomas.2011-09-09 05:20 AM
So now I have to switch between two software reset sources, any idea ?
Store a magic value in a fixed location in RAM, ie one that's free and within the scope of the device in use. *((unsigned int *)0x20004FF0) = 0x12345678; if (*((unsigned int *)0x20004FF0) == 0x12345678) { // Thing 1 } else if (*((unsigned int *)0x20004FF0) == 0x87654321) { // Thing 2 } // Normal App Be sure to clear/invalidate the value, change the scatter/linker file so it's not used for stack, etc. and that the C startup code does not zero everything. Equivalent code in assembler closer to the reset entry point is generally recommended.2011-09-09 08:38 AM
Hello Clive,
Already thought about that ... I'm using the default startup script from TASKING (soon 4.0r1 !).I think I'll need some help to modify it to not erase a specific address (not that good in Cortex ASM + it's full of pragmas / #defines).To get the variable not to get used for stack or another variable, I think I just have to declare the variable with a fixed address ( __at(0x20004FF0) ) and do the same with the same address in the bootloader / application.cstart_thumb2.asm looks like that :;; NOTE: To allow the use of this file for both ARMv6M and ARMv7M,;; we will only use 16-bit Thumb intructions. .extern _lc_ub_stack ; usr/sys mode stack pointer .extern _lc_ue_stack ; symbol required by debugger .extern _lc_ub_table ; ROM to RAM copy table .extern main .extern _Exit .extern exit .weak exit .global __get_argcv .weak __get_argcv .extern __argcvbuf .weak __argcvbuf ;;.extern __init_hardware .extern __init_vector_table .extern SystemInit .if @defined('__PROF_ENABLE__') .extern __prof_init .endif .if @defined('__POSIX__') .extern posix_main .extern _posix_boot_stack_top .endif .global _START .section .text.cstart .thumb_START: ;; anticipate possible ROM/RAM remapping ;; by loading the 'real' program address ldr r1,=_Next bx r1_Next: ;; initialize the stack pointer ldr r1,=_lc_ub_stack ; TODO: make this part of the vector table mov sp,r1 ;; call a user function which initializes hardware ;; such as ROM/RAM re-mapping or MMU configuration ;;;;bl __init_hardware ;ldr r0, =SystemInit ;bx r0 bl SystemInit ;; copy initialized sections from ROM to RAM ;; and clear uninitialized data sections in RAM ldr r3,=_lc_ub_table movs r0,#0cploop: ldr r4,[r3,#0] ; load type ldr r5,[r3,#4] ; dst address ldr r6,[r3,#8] ; src address ldr r7,[r3,#12] ; size cmp r4,#1 beq copy cmp r4,#2 beq clear b donecopy: subs r7,r7,#1 ldrb r1,[r6,r7] strb r1,[r5,r7] bne copy adds r3,r3,#16 b cploopclear: subs r7,r7,#1 strb r0,[r5,r7] bne clear adds r3,r3,#16 b cploop done: ;; initialize or copy the vector table bl __init_vector_table .if @defined('__POSIX__') ;; posix stack buffer for system upbringing ldr r0,=_posix_boot_stack_top ldr r0, [r0] mov sp,r0 .else ;; load r10 with end of USR/SYS stack, which is ;; needed in case stack overflow checking is on ;; NOTE: use 16-bit instructions only, for ARMv6M ldr r0,=_lc_ue_stack mov r10,r0 .endif .if @defined('__PROF_ENABLE__') bl __prof_init .endif .if @defined('__POSIX__') ;; call posix_main with no arguments bl posix_main .else ;; retrieve argc and argv (default argv[0]==NULL & argc==0) bl __get_argcv ldr r1,=__argcvbuf ;; call main bl main .endif ;; call exit using the return value from main() ;; Note. Calling exit will also run all functions ;; that were supplied through atexit(). bl exit __get_argcv: ; weak definition movs r0,#0 bx lr .ltorg .endsec .calls '_START', ' ' .calls '_START','__init_vector_table' .if @defined('__PROF_ENABLE__') .calls '_START','__prof_init' .endif .if @defined('__POSIX__') .calls '_START','posix_main' .else .calls '_START','__get_argcv' .calls '_START','main' .endif .calls '_START','exit' .calls '_START','',0 .endThomas.2011-09-13 07:10 AM
Hello,
Asked TASKING support for some help and they are still investigating but it seems I misunderstood the startup script ... it only erases global variables that are not initialized and initialize global variables that are ... initialized, yes.So the solution could be as simple as declaring a non global, non initialized variable at a fixed address.Regards,Thomas.PS : combination of this forum and TASKING support is a real life saver ...2011-12-12 04:54 AM
Hello,
Just to mention Clive's idea is working perfectly ... and in TASKING you only need to declare an exclusion for the memory area you want to use for this.Thomas.2012-08-14 12:27 AM
Hi anyone!
I am new to the STM32 and I have exactly the same problem like legrand. I newer used to concern about things like memory management, the compiler did all for me. But now I have to learn those things. My questions are: how do I say the compiler, which part of code he has to write in particular area of the memory? how do I tell, that a particular area of memory shouldnt be used for stack? thanks in advance!2012-08-14 07:29 AM
Going to depend on your toolchain, but typically you control placement by the linker using linker scripts or scatter files. GUI based tools like Keil have a dialog for putting in address spaces, and this creates a scatter file. You can define areas/sections for different types of data, and keep the stack separate.
There isn't any hardware method to protecting the stack, you need to have a good grasp about what stack depth you need, and can check it hasn't exceeded those limits by marking the stack, and end regions. One thing you could do with the User Stack is to place it at the bottom of RAM, ie 0x20000200, and let the processor Hard Fault when it melts through the bottom, ie 0x1FFFFFFF and below. The stack is typically placed above the heap/statics, if it descends too low it will corrupt your environment, and either behave oddly or crash. On the STM32F4 you could place the stack in the 64K CCM RAM separate from the application's RAM.