reset vector

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

reset vector

1,019 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by IanB on Wed Sep 17 04:15:59 MST 2014
I've just been writing my first interrupt service routine in assembler. I learned the hard way (unexplained hard fault error, and much re-reading of Joseph Yiu's book) that bit zero of the interrupt vector must be set so that the processor knows it's a thumb instruction, and now it works.

So why has all my previous software worked - the reset vector has always been even? (Bit zero clear)
Labels (1)
0 Kudos
11 Replies

910 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by MarcVonWindscooting on Fri Oct 10 03:29:27 MST 2014
Yes I think the NOLOAD can do the trick. I'll give it a try.
Thanks!
0 Kudos

910 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Pacman on Wed Oct 08 11:12:49 MST 2014
When I started writing linker-scripts for the ARM architecture, I made a horrible mistake, which dragged me around in LD-land for a long time.
I finally got something working (by doing it the wrong way). Fortunately I got help from Erik Christiansen via the binutils mailing list.

Here's a snippet, that you might find useful:
    .ustack (NOLOAD) :  /* a user stack pseudo-section that only defines the user stack length */
    {
        . = ALIGN(4);
        _sustack = ABSOLUTE(.);
        *(.ustack .ustack.*)
        . = ALIGN(4);
        _eustack = ABSOLUTE(.);
    }
    _lustack = (_eustack - _sustack);


-Now I got the relative length between the stack end and the stack start.
Imagine this is not called ustack but iap_reserved instead.
Now combine with my .stackarea snippet and change ...
 _stack = ORIGIN(sram) + LENGTH(sram);

... to ...
 _stack = ORIGIN(sram) + LENGTH(sram) - _liap_reserved;

...Would that solve the problem ?
0 Kudos

910 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by MarcVonWindscooting on Wed Oct 08 05:16:16 MST 2014
Interesting discussion, here  :)

Slightly off-topic:
Depending on the need for IAP, you want to add an extra padding of 32bytes from the top of RAM. I've failed so far creating a suitable LD-script + object files, because that needs (in my opinion) a section called .iap_reserved (for example) that needs to be populated before .stack to know its size but on the other hand after .stack to fit into the right place in RAM |( ?? My approach was to put a 32byte-array in the IAP library module into section .iap_reserved, which gets pulled in as soon as I use IAP functionality.

Has anyone done this or something similar?
0 Kudos

910 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Pacman on Wed Oct 08 02:15:47 MST 2014

Quote: IanB
It decrements BEFORE it stores, so it should be vStackTop


Yes. I can confirm this, since I've used it in all my sources (and would probably have had some problems if it was wrong).

As an alternative to placing the stack at ramtop, you can also define a fixed stack size, by creating a .stackarea section.
This is how I do it in my linker-script:

    .stackarea _ebss (NOLOAD) :
    {
        . = ALIGN(8);
        _sstack = .;                /* _sstack is located immediately after the BSS */
        *(.stackarea .stackarea.*)

        . = ALIGN(8);
        _estack = .;                /* _estack points at _sstack + your_stack_size */
        . = ALIGN(4);
        _end = .;                   /* this symbol marks the end of application RAM */

        PROVIDE(end = .);
    } >sram

    _stack = ORIGIN(sram) + LENGTH(sram);   /* _stack is placed at ram-top and grows towards the BSS */


I then have the option to use _estack or _stack, depending on my mood.
Thus if I want an area that is protected from stack-overflow, I'd make a .stackarea section like the following:
    .section .stackarea,"",%nobits
    .space 4*64   /* size of stack */


-But I also have the option to use the _stack symbol instead. Then I can use the .stackarea to define a minimum stack size.
If there is not enough room for a stack of that size, I will get an error when I attempt to link, because the ram size is checked.

Sometimes you want to include a minimum stack size in your source files, but you should of course be aware that each time you add a .stackare, the stack grows.
-If you have a recursive subroutine, it's useful to define the required stack size for this routine in the same source.
main.s could then have a simple stack size of 16 words.
-But it depends on your coding style. Normally I would just go with ramtop.
0 Kudos

910 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by IanB on Tue Oct 07 09:00:22 MST 2014
Because I copied it from someone else who did it wrong.

- - - reads manual more carefully - - -

It decrements BEFORE it stores, so it should be vStackTop.

I stand corrected.
0 Kudos

910 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by TheFallGuy on Mon Oct 06 23:45:04 MST 2014
Why
vStackTop - 4
?
You are wasting the top 4 bytes of the stack...
0 Kudos

910 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Pacman on Mon Oct 06 21:01:28 MST 2014
For the people that just came across this thread: The above startup code is for Cortex-M0 devices (but will work on Cortex-M3 too).
Ian, I can see you've hand-picked the instructions. Very nice.


Quote: IanB
LPC Xpresso isn't quite the same as yours ...


No, it seems that some section names are different, but fortunately the difference is not too bad.

As for the .section directive, I tend to use a macro instead:

.macroSECTION name/* normal section (eg. executable) */
.section.\name,"ax",%progbits
.endm

.macroDSECTION name/* Data section */
.section.\name,"a",%progbits
.endm


This makes it a lot easier writing code that is scheduled for being executed in SRAM.
(eg. if you have sections like .fastcode, .ramcode or similar)
-The problem here is that the .section does not set the %progbits flag by default, so I experienced that my sections were just discarded.

In some applications I use loads of sections, because the data are generated dynamically and each data type will go into its own section.
This way I can make the assembler generate tables and arrays of special lengths automatically (this is neat for graphics and special kind of fixed length code blocks too).
0 Kudos

910 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by IanB on Sun Oct 05 05:38:18 MST 2014
I suppose I should post the code in case anyone else wants to use it:
.section .after_vectors
ResetISR:
.thumb_func
.type ResetISR,%function
.global  ResetISR

ResetHandler:   LDR R3,=__data_section_table
LDR R0,[R3]/* load address of .data section */
LDR R1,[R3,#4]/* start address of .data section */
LDR R2,[R3,#8]/* length of .data section */

copy_data:LDMIA R0!,{R3}
STMIA R1!,{R3}
SUBS R2,R2,#4
BNE copy_data

LDR R3,=__bss_section_table
LDR R0,[R3]/* start address of .bss section */
LDR R1,[R3,#4]/* length of .bss section */
MOVS R2,#0

zero_bss:STMIA R0!,{R2}
SUBS R1,R1,#4
BNE zero_bss

/*Set48MHzClock FUNCTION */
                LDR R3,=LPC_SYSCON_BASE+PDRUNCFG
                LDR R1,[R3]
                MOVS R2,#0b10110000
                BICS R1,R1,R2
                STR R1,[R3]

                /* Select PLL source as internal oscillator  */
                LDR R3,=LPC_SYSCON_BASE
                MOVS R2,#0
                STR R2,[R3,SYSPLLCLKSEL]

                /* Update SYSPLL setting (0->1 sequence)  */
                MOVS R2,#0
                STR R2,[R3,SYSPLLCLKUEN]
                MOVS R2,#1
                STR R2,[R3,SYSPLLCLKUEN]
.equ clockspeed, 48000000
                /* Set PLL to 48MHz generate from 12MHz               */
                MOVS R2,#0x23
                STR R2,[R3,SYSPLLCTRL]

                /* wait until PLL is locked                           */
Set48MHzClock:  LDR R2,[R3,SYSPLLSTAT]
                CMP R2,#0
                BEQ Set48MHzClock

                /* Switch main clock to PLL clock                     */
                MOVS R2,#3
                STR R2,[R3, MAINCLKSEL]

                /* Update Main Clock Select setting (0->1 sequence)   */
                MOVS R2,#0
                STR R2,[R3,MAINCLKUEN]
                MOVS R2,#1
                STR R2,[R3,MAINCLKUEN]
B main


This is the start of the vector table:
.section .isr_vector

.word   _vStackTop - 4                     /*  0 Top of Stack                                   */
.word   ResetISR                           /*  1 Reset Handler                                  */


use  _vStackTop instead of __top_RamLoc, because __top_RamLoc changes slightly with each different  device, by having a suffix indicating the ram size.

I'm also glad someone is teaching assembler.
If no-one was teaching assembler, who would write the next compiler?
0 Kudos

910 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Pacman on Fri Oct 03 03:48:27 MST 2014
It's great to hear that you could use the article. :)
I wrote it, because a teacher wanted to teach the pupils ARM (Cortex-M4) assembly language.
-That's one cool teacher! :)

Yes, I had problems also, until I used the .type directive. I should have mentioned it.
I better write some details in my docs, but not right now, as I'm almost falling asleep. ;)
0 Kudos

910 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by IanB on Tue Sep 30 09:29:59 MST 2014
As I mentioned on the LCD-Displays post, it was the ".thumb_func" - I had it for the reset vector but not the sys tick - I didn't know what it was doing at the time - I just copied it from somewhere without thinking!

Now I know.

When I put the startup routine in the normal .text section, it is happy, but if I put the startup routine in the .after_vectors section, then .thumb_func doesn't do its stuff unless it has a .type ResetISR,%function as well!

I've written a startup routine (based on your "Writing your own startup code for Cortex-M" article)  - LPC Xpresso isn't quite the same as yours but it was easy enough to figure it out from the disassembly listing.
I also included in it the code to set the oscillator to 48MHz (cribbed straight from Joseph Yiu's book).
0 Kudos

910 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Pacman on Thu Sep 18 21:40:02 MST 2014
I can't explain why it always worked for you (unless you've written 32-bit ARM code, that is - but that wouldn't work on Cortex-M).
(Have you tried reading back the exception vector block from the device, to check the bits ?)

If you're using the GNU Assembler, I recommend using the following two directives for each function you're writing:

    .type  myLabel,%function
    .thumb_func

.thumb_func makes any pointer-access to the function work correctly. Eg. the ldr instruction plus exception vectors.
I've written two convenience macros; FUNCTION and ENDFUNC; both takes the function name as parameter.
My macros handles the .global, (section), .func, .type, .thumb_func, .size and .endfunc directives; thus my sources look a bit more tidy.
0 Kudos