首页 文章

stm32f103内存寻址

提问于
浏览
0

我使用足够的启动文件在keil中编写了stm32f103c8t6板的代码 . 我使用数据表中的信息直接写入内存地址 . 但是st-link上传似乎将hex文件上传到了worng地址,例如:GPIOA = 0X4001 0800这是根据stm数据表 . 但是stlink显示设备数据范围从0x0800 0000到0x0800 03d4 . 我的代码是一个简单的程序,用于在portA1处使LED闪烁 . 我将LED连接到10k电阻上 . 当我使用指针指定内存位置时,为什么stm分配错误的地址,或者可能有任何其他错误 . 代码如下 .

void delay(int a);

int main(void)
{
unsigned int* GPIO_A;
GPIO_A = (unsigned int*)0x40010800 ; // Assigning GPIOA to the correct   memory location

unsigned int* GPIO_A_CRL;
GPIO_A_CRL = GPIO_A + 0x00 ; // Assigning GPIO_A_CRL to the correct memory location

/*unsigned int* GPIO_A_IDR;
GPIO_A_IDR = GPIO_A + 0X08 ; // Assigning GPIO_A_IDR to the correct memory location  */

unsigned int* GPIO_A_BSRR;
GPIO_A_BSRR = GPIO_A + 0X10 ; // Assigning GPIO_A_BSRR to the correct memory location

unsigned int* GPIO_A_BRR;
GPIO_A_BRR = GPIO_A + 0X14 ; // Assigning GPIO_A_BSRR to the correct memory   location

 unsigned int* RCC_APB2ENR;
 RCC_APB2ENR = (unsigned int*)(0x40021000 + 0X18) ; // Assigning        RCC_APB2ENR to the correct memory location

*RCC_APB2ENR = 0X04; // Set clock for GPIOA

*GPIO_A_CRL = 0X00008888 ; // Defining pin modes for GPIO_A_CRL

while(1)  // infinite loop
{
    *GPIO_A_BSRR = 0X00000002;  // Set bit 1 to 1
    delay(2); // delay
    *GPIO_A_BRR = 0x00000002;  // reset bit 1 to reset value(0)
    delay(2); // delay
}

}
void delay(int a)
{
long b = a*1000000;
for(int i=0;i<b;i++)
   {
    int c=1;
   }
}

3 回答

  • 0

    编译器/链接器未正确分配地址;你只是误解了内存映射以及编译器和链接器(甚至处理器)的工作方式 .

    0x08000000到0x080003d4是您的代码的位置; 0X40010800是GPIOA存储器映射寄存器的地址 .

    在STM32上,0x0800000是片上闪存的起始地址 . 当处理器复位时,它从0x08000000加载堆栈指针寄存器,从0x08000004加载程序计数器寄存器 . 上面是interrupt vector table及以上,这将是您的代码 - 或者更确切地说是编译器从您的源代码生成的机器代码 . 您提到的启动文件定义了所提到的复位和中断向量 .

    指针 GPIO_A 在运行时在代码中分配,指针变量的位置将在RAM中,尽管由于你初始化并且从不修改它,编译器可能会优化将地址存储在ROM中或用文字内联替换它 .

    而不是定义自己的寄存器地址,使用供应商提供的处理器头(在本例中为stm32f10xx.h)会更简单,更安全 . 当您为特定部件配置项目时,Keil工具链包含此文件 . 它还包括STM32标准外设库(或从here下载),它简化了低级外设访问,并包含许多外围I / O示例,包括GPIO .

    有关STM32F1xx的完整编程器信息,仅依靠数据表是不够的 - 它只是告诉您器件的特定功能;你应该使用更全面的Reference Manual .

  • 1

    我认为您的数据范围是正确的 . 指针就像任何其他变量一样驻留在RAM中 . 它不是他们居住的地方,而是他们所指的,在你的情况下是GPIO . 代码看起来很正确,表示我没有检查地址是否适合您要写入的寄存器,或者您正在编写正确的值/寄存器 . 首先尝试启用时钟 . 如果有疑问,请查看ST的F3立方体下载中的GPIO示例 . 它使用它们的库函数,但你可以查看它们 . 它还提供了一个文件,其中包含我建议您使用的所有寄存器的定义 .

  • 0

    我有来自亚洲的ebay 2美元,它有相同的部分,并且在C端口13上有一个led .

    这是一个完整的基于gnu工具链的示例,您可以将其更改为在端口d引脚0上运行(或将您的指令移至pc13)

    flash.s

    .thumb
    
    .thumb_func
    .global _start
    _start:
    stacktop: .word 0x20001000
    .word reset
    .word hang
    .word hang
    .word hang
    .word hang
    .word hang
    .word hang
    .word hang
    
    .thumb_func
    reset:
        bl notmain
        b hang
    
    .thumb_func
    hang:   b .
    

    blinker01.c

    #define GPIOCBASE 0x40011000
    #define RCCBASE 0x40021000
    #define RCC_APB2ENR   (*((volatile unsigned int *)(RCCBASE+0x18)))
    #define GPIO_CONTROL (*((volatile unsigned int *)(GPIOCBASE+0x04)))
    #define GPIO_BSRR    (*((volatile unsigned int *)(GPIOCBASE+0x10)))
    void notmain ( void )
    {
        volatile unsigned int ra;
    
        RCC_APB2ENR|=1<<4; //enable port c
        GPIO_CONTROL=(GPIO_CONTROL&(~0xF<<20))|(0x1<<20);
        while(1)
        {
            GPIO_BSRR=1<<(13+0);
            for(ra=0;ra<200000;ra++) continue;
            GPIO_BSRR=1<<(13+16);
            for(ra=0;ra<200000;ra++) continue;
        }
    }
    

    flash.ld

    MEMORY
    {
        rom : ORIGIN = 0x08000000, LENGTH = 0x1000
        ram : ORIGIN = 0x20000000, LENGTH = 0x1000
    }
    
    SECTIONS
    {
        .text : { *(.text*) } > rom
        .rodata : { *(.rodata*) } > rom
        .bss : { *(.bss*) } > ram
    }
    
    arm-none-eabi-as --warn --fatal-warnings -mcpu=cortex-m3 flash.s -o flash.o
    arm-none-eabi-gcc -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding  -mthumb -mcpu=cortex-m3 -march=armv7-m -c blinker01.c -o blinker01.o
    arm-none-eabi-ld -o blinker01.elf -T flash.ld flash.o blinker01.o
    arm-none-eabi-objdump -D blinker01.elf > blinker01.list
    arm-none-eabi-objcopy blinker01.elf blinker01.bin -O binary
    

    然后检查列表

    08000000 <_start>:
     8000000:   20001000    andcs   r1, r0, r0
     8000004:   08000025    stmdaeq r0, {r0, r2, r5}
     8000008:   0800002b    stmdaeq r0, {r0, r1, r3, r5}
     800000c:   0800002b    stmdaeq r0, {r0, r1, r3, r5}
     8000010:   0800002b    stmdaeq r0, {r0, r1, r3, r5}
     8000014:   0800002b    stmdaeq r0, {r0, r1, r3, r5}
     8000018:   0800002b    stmdaeq r0, {r0, r1, r3, r5}
     800001c:   0800002b    stmdaeq r0, {r0, r1, r3, r5}
     8000020:   0800002b    stmdaeq r0, {r0, r1, r3, r5}
    
    08000024 <reset>:
     8000024:   f000 f802   bl  800002c <notmain>
     8000028:   e7ff        b.n 800002a <hang>
    
    0800002a <hang>:
     800002a:   e7fe        b.n 800002a <hang>
    

    向量表必须位于正确的位置 . 向量必须是1的地址orred(gnu汇编程序中的.thumb_func使下一个标签成为函数,如果我们将该标签用于任何事情,则为我们做一件事) . 如果您的二进制文件不是以向量表开头,或者地址是偶数,则游戏结束时您将无法启动 .

    如果你的工具可以处理那个二进制文件的英特尔十六进制版

    :020000040800F2
    :1000000000100020250000082B0000082B0000082D
    :100010002B0000082B0000082B0000082B00000814
    :100020002B00000800F002F8FFE7FEE74FF4005550
    :1000300000204FF00054154A154E1368154943F03F
    :10004000100313603268144B02F07F4242F48012B6
    :1000500082B032600D600190019A9A420FD90C6013
    :100060000190019A9A42F5D8019A01320192019ABF
    :100070009A42F9D90D600190019A9A42EFD8019AFB
    :1000800001320192019A9A42F9D9E8E71810024028
    :0C00900004100140101001403F0D03005F
    :0400000508000000EF
    :00000001FF
    

    srecord版本一样 .

    S0110000626C696E6B657230312E73726563CB
    S3150800000000100020250000082B0000082B0000081F
    S315080000102B0000082B0000082B0000082B00000806
    S315080000202B00000800F002F8FFE7FEE74FF4005542
    S3150800003000204FF00054154A154E1368154943F031
    S31508000040100313603268144B02F07F4242F48012A8
    S3150800005082B032600D600190019A9A420FD90C6005
    S315080000600190019A9A42F5D8019A01320192019AB1
    S315080000709A42F9D90D600190019A9A42EFD8019AED
    S3150800008001320192019A9A42F9D9E8E7181002401A
    S3110800009004100140101001403F0D030051
    S70508000000F2
    

    如果你将你的领导转移到pc13,你可以理想地直接使用其中一个二进制文件 .

    如果你有openocd,那么telnet到它(telnet localhost 4444)

    > halt
    > flash write_image erase /path/to/blinker01.srec
    > reset
    

    它会开始闪烁LED

相关问题