I'm trying to do a very simple program using ARM Thumb assembly, which will turn off the LED on my Arduino Due (The ATSAM3X8E pin linked to it seems to be pulled up internally by default). I'm doing this as a test before doing more complex things in assembly.
I've placed the inital SP value as well as all 15 mandatory system exception vectors in a section, and did a quick GPIO hardware registers initialization routine (Defines the pin as an output I can write to, disables the pull-up, so as long as I don't actually write into the output data register the output pin should remain off). (I didn't do any RAM loading routine because I don't have values other than read-only constants in the program at the moment, so no data section too).
I used the GNU Assembler, ld with a simple linker script that ensures the vector table is at the very beginning of the binary file, did a quick objcopy from the elf and got a nice raw binary that I flashed in the internal flash of the MCU using the BOSSA command-line. (See code below)
But nothing happened, the LED stayed high.
.thumb
.syntax unified
.section .vectors
.word 0x20001000 @StackTop, somewhere near the end of the SRAM
.word Reset_Handler
.word No_Handler @NMI_Handler
.word No_Handler @HardFault_Handler
.word No_Handler @MemFault_Handler
.word No_Handler @BusFault_Handler
.word No_Handler @UsageFault_Handler
.word 0
.word 0
.word 0
.word 0
.word No_Handler @SVC_Handler
.word No_Handler @DebugMon_Handler
.word 0
.word No_Handler @PendSV_Handler
.word No_Handler @SysTick_Handler
.word No_Handler @IRQ0
@... (same with all IRQ's until 28)
.word No_Handler @IRQ29
.section .text
.thumb_func
Reset_Handler:
BL init
BL main
B No_Handler
.thumb_func
No_Handler:
B No_Handler
.thumb_func
init:
LDR r0, =WDT_MR @Disable Watchdog Timer
LDR r1, [r0]
ORR r1, r1, #0x8000
STR r1, [r0]
LDR r0, =PIOB_WPMR @Disable GPIO Write Protection
LDR r1, [r0]
LDR r2, =PIOB_KEY
LDR r3, [r2]
ORR r1, r1, r3
STR r1, [r0]
LDR r0, =PIOB_PER @Disable peripeheral function (pure GPIO)
LDR r1, [r0]
LDR r2, =PIOB27
LDR r3, [r2]
ORR r1, r1, r3
STR r1, [r0]
LDR r0, =PIOB_OER @Define pin as output
LDR r1, [r0]
ORR r1, r1, r3
STR r1, [r0]
LDR r0, =PIOB_OWER @Allow writes to ODSR
LDR r1, [r0]
ORR r1, r1, r3
STR r1, [r0]
LDR r0, =PIOB_PUDR @Disable internal pull-up for the pin
LDR r1, [r0]
ORR r1, r1, r3
STR r1, [r0]
BX lr
.thumb_func
main:
@nothing much here
B main
WDT_MR: .word 0x400E1A54
PIOB_WPMR: .word 0x400E10E4
PIOB_KEY: .word 0x50494F00
PIOB_PER: .word 0x400E1000
PIOB_OER: .word 0x400E1010
PIOB_OWER: .word 0x400E10A0
PIOB_PUDR: .word 0x400E1060
PIOB_ODSR: .word 0x400E1038
PIOB27: .word 0x8000000 @ 0x1u<<27
I did the same thing in C with the exact same registers (but letting Microchip Studio use ARM GCC for me) and it worked this time. In case the error is in my custom linker script, here it is :
MEMORY
{
flash (rx) : ORIGIN = 0x00080000, LENGTH = 0x00080000
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00018000
}
SECTIONS
{
.text :
{
*(.vectors)
*(.text)
} > flash
}
What I'm afraid of is that the program does not actually seem to reach any of the initialization code.
CodePudding user response:
If I take a subset of your program
.thumb
.syntax unified
.section .vectors
.word 0x20001000
.word Reset_Handler
.section .text
.thumb_func
Reset_Handler:
BL init
BL main
B No_Handler
.thumb_func
No_Handler:
B No_Handler
.thumb_func
init:
LDR r0, =WDT_MR @Disable Watchdog Timer
LDR r1, [r0]
ORR r1, r1, #0x8000
STR r1, [r0]
BX lr
.thumb_func
main:
@nothing much here
B main
WDT_MR: .word 0x400E1A54
assemble and link it with your linker script, then disassemble.
Disassembly of section .text:
00080000 <Reset_Handler-0x8>:
80000: 20001000 andcs r1, r0, r0
80004: 00080009 andeq r0, r8, r9
00080008 <Reset_Handler>:
80008: f000 f804 bl 80014 <init>
8000c: f000 f808 bl 80020 <main>
80010: e7ff b.n 80012 <No_Handler>
00080012 <No_Handler>:
80012: e7fe b.n 80012 <No_Handler>
00080014 <init>:
80014: 4804 ldr r0, [pc, #16] ; (80028 <WDT_MR 0x6>)
80016: 6801 ldr r1, [r0, #0]
80018: f441 4100 orr.w r1, r1, #32768 ; 0x8000
8001c: 6001 str r1, [r0, #0]
8001e: 4770 bx lr
00080020 <main>:
80020: e7fe b.n 80020 <main>
00080022 <WDT_MR>:
80022: 400e1a54 andmi r1, lr, r4, asr sl
80026: 00220000 eoreq r0, r2, r0
8002a: Address 0x000000000008002a is out of bounds.
The first thing you have to examine is the vector table.
00080000 <Reset_Handler-0x8>:
80000: 20001000 andcs r1, r0, r0
80004: 00080009 andeq r0, r8, r9
00080008 <Reset_Handler>:
The first entry is the sp init value, and that looks fine, the second is the reset vector, and the lsbit must be set, and it is, that is correct, so you will not instantly fail, there is some hope.
As pointed out in comments though
00080014 <init>:
80014: 4804 ldr r0, [pc, #16] ; (80028 <WDT_MR 0x6>)
...
00080022 <WDT_MR>:
80022: 400e1a54 andmi r1, lr, r4, asr sl
Is NOT putting the value 0x400e1a54 in r0, but instead the ADDRESS OF WDT_MR in r0. Which the disassembler sort of mangled. But basically it puts 0x00080022 in r0. Which is not what you want.
So if I do this:
.thumb
.syntax unified
.section .vectors
.word 0x20001000
.word Reset_Handler
.section .text
.equ WDT_MR, 0x400E1A54
.thumb_func
Reset_Handler:
BL init
BL main
B No_Handler
.thumb_func
No_Handler:
B No_Handler
.thumb_func
init:
LDR r0, =WDT_MR @Disable Watchdog Timer
LDR r1, [r0]
ORR r1, r1, #0x8000
STR r1, [r0]
BX lr
.thumb_func
main:
@nothing much here
B main
.align
.word 0x12345678
And the .align at the bottom and that extra word (not really needed I assume) is to make the disassembly easier to read.
Gives this
00080014 <init>:
80014: 4804 ldr r0, [pc, #16] ; (80028 <main 0x8>)
80016: 6801 ldr r1, [r0, #0]
80018: f441 4100 orr.w r1, r1, #32768 ; 0x8000
8001c: 6001 str r1, [r0, #0]
8001e: 4770 bx lr
00080020 <main>:
80020: e7fe b.n 80020 <main>
80022: bf00 nop
80024: 12345678 eorsne r5, r4, #120, 12 ; 0x7800000
80028: 400e1a54 andmi r1, lr, r4, asr sl
And now 0x400e1a54 IS being loaded into r0, so that you can then control that register in the logic.
Visually inspect the disassemble to see if it is doing what you think it is doing.
WDT_MR in your code is a label, which is basically an address. So when you do ldr r0,=WDT_MR you are asking for the ADDRESS OF. Now here is another thing you could do:
.thumb
.syntax unified
.section .vectors
.word 0x20001000
.word Reset_Handler
.section .text
.thumb_func
Reset_Handler:
BL init
BL main
B No_Handler
.thumb_func
No_Handler:
B No_Handler
.thumb_func
init:
LDR r0, WDT_MR @Disable Watchdog Timer
LDR r1, [r0]
ORR r1, r1, #0x8000
STR r1, [r0]
BX lr
.thumb_func
main:
@nothing much here
B main
.align
WDT_MR: .word 0x400E1A54
so you were one character away from success
00080014 <init>:
80014: 4803 ldr r0, [pc, #12] ; (80024 <WDT_MR>)
80016: 6801 ldr r1, [r0, #0]
80018: f441 4100 orr.w r1, r1, #32768 ; 0x8000
8001c: 6001 str r1, [r0, #0]
8001e: 4770 bx lr
00080020 <main>:
80020: e7fe b.n 80020 <main>
80022: bf00 nop
00080024 <WDT_MR>:
80024: 400e1a54 andmi r1, lr, r4, asr sl
Now it is loading the value at that label not the address of the label. And I suspect this is actually what you want to do rather than the .equ thing. YMMV. if you do the .EQU thing then the assembler is creating the pool, if you do it then you can control where these things live.
Now you potentially had a second problem that was shown and talked about above, and I solved it:
00080022 <WDT_MR>:
80022: 400e1a54 andmi r1, lr, r4, asr sl
80026: 00220000 eoreq r0, r2, r0
8002a: Address 0x000000000008002a is out of bounds.
Had you gotten the ldr right you would have been doing a 32 bit load from 0x80022, which is not a 32 bit aligned address. Before a pool like that you want to align on at least a 4 byte boundary and for arm gas, the .align will suffice:
.thumb_func
main:
@nothing much here
B main
.align
WDT_MR: .word 0x400E1A54
00080020 <main>:
80020: e7fe b.n 80020 <main>
80022: bf00 nop
00080024 <WDT_MR>:
80024: 400e1a54 andmi r1, lr, r4, asr sl
Notice the nop the tool added as padding, if we were to:
.thumb_func
main:
@nothing much here
B main
adds r0,#1
.align
WDT_MR: .word 0x400E1A54
00080020 <main>:
80020: e7fe b.n 80020 <main>
80022: 3001 adds r0, #1
00080024 <WDT_MR>:
80024: 400e1a54 andmi r1, lr, r4, asr sl
It is still properly aligned.