stm32f103内存寻址

时间:2017-02-23 17:32:24

标签: embedded stm32

我使用足够的启动文件在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;
   }
}

2 个答案:

答案 0 :(得分:1)

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

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 :(得分: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