我使用足够的启动文件在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 回答
编译器/链接器未正确分配地址;你只是误解了内存映射以及编译器和链接器(甚至处理器)的工作方式 .
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 .
我认为您的数据范围是正确的 . 指针就像任何其他变量一样驻留在RAM中 . 它不是他们居住的地方,而是他们所指的,在你的情况下是GPIO . 代码看起来很正确,表示我没有检查地址是否适合您要写入的寄存器,或者您正在编写正确的值/寄存器 . 首先尝试启用时钟 . 如果有疑问,请查看ST的F3立方体下载中的GPIO示例 . 它使用它们的库函数,但你可以查看它们 . 它还提供了一个文件,其中包含我建议您使用的所有寄存器的定义 .
我有来自亚洲的ebay 2美元,它有相同的部分,并且在C端口13上有一个led .
这是一个完整的基于gnu工具链的示例,您可以将其更改为在端口d引脚0上运行(或将您的指令移至pc13)
flash.s
blinker01.c
flash.ld
然后检查列表
向量表必须位于正确的位置 . 向量必须是1的地址orred(gnu汇编程序中的.thumb_func使下一个标签成为函数,如果我们将该标签用于任何事情,则为我们做一件事) . 如果您的二进制文件不是以向量表开头,或者地址是偶数,则游戏结束时您将无法启动 .
如果你的工具可以处理那个二进制文件的英特尔十六进制版
srecord版本一样 .
如果你将你的领导转移到pc13,你可以理想地直接使用其中一个二进制文件 .
如果你有openocd,那么telnet到它(telnet localhost 4444)
它会开始闪烁LED