cancel
Showing results for 
Search instead for 
Did you mean: 

Multiple software reset conditions.

root
Associate II
Posted on September 09, 2011 at 10:35

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.
6 REPLIES 6
Posted on September 09, 2011 at 14:20

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.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
root
Associate II
Posted on September 09, 2011 at 17:38

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,#0

cploop:

        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       done

copy:

        subs    r7,r7,#1

        ldrb    r1,[r6,r7]

        strb    r1,[r5,r7]

        bne     copy

        adds    r3,r3,#16

        b       cploop

clear:

        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

        .end

Thomas.

root
Associate II
Posted on September 13, 2011 at 16:10

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 ...
root
Associate II
Posted on December 12, 2011 at 13:54

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.
enrico239955_st
Associate II
Posted on August 14, 2012 at 09:27

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!

Posted on August 14, 2012 at 16:29

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.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..