Keil uVision模拟器 - 为什么同一变量有两个地址?为什么它不是初始化为0?

时间:2017-10-25 01:24:58

标签: assembly memory arm bootloader keil

我正在为TM4C123GX发现板编写程序。我正在使用Keil uVision并使用模拟器进行调试。我正在尝试使用SysTick处理程序切换GPIODATA寄存器中的值以使外部LED闪烁。 TM4C使用地址掩码将位存储到GPIODATA,我使用变量(PB5_MASK)来保存掩码值。我的问题是

  1. 当我尝试从该变量读取时,除非我存储了一个值,否则我总是得到一个0,尽管它已经初始化(0xF0)。
  2. 当我在main中获取地址时,我得到0x2000.0004。但是当我在SysTick_Handler中获取相同变量的地址时,我得到0x2000.0000。
  3. 我的问题是:尽管给出了初始值(0xF0),为什么变量(PB5_MASK)初始化为0?为什么同一个变量(PB5_MASK)有两个地址(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
    

    这些是片段。如果需要整个代码,请告诉我。谢谢!

    编辑:这是一个类似问题的链接。我还必须在调试时输入自己更改的地址,但是没有解决方案有两个地址的变量

    ARM Assembly storing registers to memory

    编辑:因此,使用IMPORT / EXPORT解决了2个地址对同一变量的问题,但我仍然坚持使用未初始化的变量问题。

    我无法理解从哪里开始使用bootloader。我想要的是我的变量在RAM中初始化。我试着查看TivaWare附带的示例,我看到Reset_Handler调用__main,它调用其他子程序,如_main_after_scatter等。我找不到__main在哪里?我最初认为__main是我应该编写代码的地方(比如main())。 __main是一个只做它自己的子程序吗?如果是这样,我在哪里编写代码?抱歉有多个问题,但它们都是相关的。

1 个答案:

答案 0 :(得分:1)

正如彼得·科德斯在评论中指出的那样,你将变量定义为两次

默认情况下,装配模块中的对象是本地的。为了在两个或更多模块之间共享变量,您必须在一个编译单元中定义它,用GLOBALEXPORT标记符号(它们是相同的),然后使用{{1 }}或EXTERN在其他模块中,以使它们在那里可见。

关于您的其他问题,变量应在程序启动时 初始化。

这个嵌入式系统没有加载器,程序直​​接写入板载闪存,并从那里执行。代码和常量数据都在flash中,变量在RAM中静态分配,但是没有任何内容可以填充RAM中变量的初始值,除非你的代码这样做。

工具链供应商提供了一个启动功能,它正是这样做,将初始值从flash复制到ram,零变量没有显式初始化,做一些内务处理,并将控制转移到用户的IMPORT功能程序。这个启动函数在Keil工具链中被称为main,如果你想要初始化变量,你应该从重置处理程序调用它。