I'm writing an program in assembly for a TM4C123GX discovery board. I'm using Keil uVision and debugging with the simulator. I'm trying to use SysTick handler to toggle the value in GPIODATA register to have an external LED blink. TM4C uses an address mask to store bits to GPIODATA and I'm using a variable (PB5_MASK) to hold the value to mask. My problem is that
- When I try to read from that variable, I always get a 0 unless I store a value, despite it being initialized already (0xF0).
- When I get the address in main, I get 0x2000.0004. But when I get the address for the same variable in the SysTick_Handler, I get 0x2000.0000.
My questions are: Why is the variable (PB5_MASK) initialized as 0 despite given an initial value (0xF0)? And why does the same variable (PB5_MASK) have two addresses (0x2000.0000 & 0x2000.0004)?
my_Variables.s:
AREA My_Variables, CODE, READWRITE
PB5_MASK DCD 240;0x000000F0
END
main.s:
;Include constants I define to main
INCLUDE my_Constants.s
;Include variables I define to main
INCLUDE my_Variables.s
AREA |.text|, CODE, READONLY
;THUMB
EXPORT __main
ENTRY
;This subroutine initializes GPIO
GPIO_Init PROC
;Push LR onto stack first
PUSH {LR}
;write "high" to data register for port F pin 1 to turn on red LED. GPIODATA
LDR r0, =AHB_PORTB
LDR r1,[r0,#GPIODATAPB5]
;address for PB5_MASK here is 0x2000.0000, but...
LDR r2, =PB5_MASK ;get RAM address of PB5 mask (pointer)
;reads 0x0 unless I put in the value myself
LDR r3,[r2] ;get the value of PB5 mask
ORR r3, r3, #0xF0
STR r3,[r2]
ORR r1, r1, r3 ;Set PB5 to 'high'
STR r1,[r0,#GPIODATAPB5]
;LDR r1,[r0,#GPIODATAPB5]
;Pop LR and return to __main
POP {LR}
BX LR
ENDP
startup_rvmdk.s:
;includes constants I define to startup file
INCLUDE my_Constants.s
;Include variables I define to startup file
INCLUDE my_Variables.s
SysTick_Handler PROC
EXPORT SysTick_Handler
;write "high" to data register for port F pin 1 to turn on red LED. GPIODATA
LDR r0, =AHB_PORTB
;... address for PB5_MASK here is 0x2000.0004
LDR r1, =PB5_MASK ;Get RAM address of PB5 mask value
LDR r2,[r1] ;Grab value of PB5 mask
EOR r2, r2, #0xF0 ;Toggle mas to toggle PB5
STR r2,[r1] ;Store the toggled mask to properly toggle next time
STR r2,[r0,#GPIODATAPB5]
;LDR r2,[r0,#GPIODATAPB5]
;return to __main
BX LR
ENDP
These are snippets. If the entire code is needed please let me know. Thank you!
Edit: Here is a link to a similar problem. I also had to put in the addresses being changed myself when debugging, but there isn't a solution to a variable having two addresses
ARM Assembly storing registers to memory
Edit: So the 2-addresses-for-the-same-variable problem was fixed by using IMPORT/EXPORT, but I'm still stuck with the uninitialized variable problem.
I'm having trouble understanding where to begin with bootloaders. All I want is for my variables to be initialized in RAM. I tried looking at examples that came with TivaWare and I see that Reset_Handler calls __main, which calls other subroutines like _main_after_scatter, etc. I can't find __main anywhere though? I initialially thought __main was where I was supposed to write my code (like main() ). Is __main a subroutine that just does it's own thing? If so, where do I write my code? Sorry for the multiple questions, but they're all related.
INCLUDEing the same file twice? This would be like doingstatic int foo = 1234;in a C header file: each translation unit that includes that header will get their own copy of the variable. I don't know the keil tools, but can you usereadelfornmor equivalent to look at the symbol table and check for duplicates? - Peter Cordes