[英]stm32f103 memory addressing
我已經使用足夠的啟動文件在keil中為stm32f103c8t6板編寫了代碼。 我使用數據表中的信息直接寫到內存地址。 但是st-link上載似乎將十六進制文件上載到磨損的地址,例如:GPIOA = 0X4001 0800這是根據stm數據表得出的。 但是stlink顯示設備數據范圍從0x0800 0000到0x0800 03d4。 我的代碼是一個簡單的程序,用於使端口A1上的LED閃爍。 我跨過10k電阻器連接了LED。 當我使用指針指定內存位置時,為什么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;
}
}
編譯器/鏈接器的地址分配有誤。 您只是誤解了內存映射以及編譯器和鏈接器(甚至處理器)的工作方式。
0x08000000到0x080003d4是您的代碼的位置; 0X40010800是GPIOA存儲器映射寄存器的地址。
在STM32上,0x0800000是片上閃存的起始地址。 當處理器退出復位狀態時,它將從0x08000000加載堆棧指針寄存器,並從0x08000004加載程序計數器寄存器。 上面是中斷向量表 ,上面是您的代碼-或更確切地說是編譯器從您的源代碼生成的機器代碼。 您提到的啟動文件除其他外還定義了提到的復位和中斷向量。
指針GPIO_A
是在運行時在代碼中分配的, 指針變量的位置將在RAM中,盡管由於您對它進行了初始化並且從不對其進行修改,所以編譯器可能會優化將地址存儲在ROM中或用文字內聯替換。
與其定義自己的寄存器地址,不如使用供應商提供的處理器標頭(在這種情況下為stm32f10xx.h),更加簡單和安全。在為特定零件配置項目時,Keil工具鏈包括此文件。 它還包括STM32標准外設庫(或從此處下載),該庫簡化了低級外設訪問,並提供了包括GPIO在內的許多外設I / O示例。
要獲得有關STM32F1xx的完整程序員信息,僅依靠數據表是不夠的-僅僅告訴您部件的特定功能;僅提供英文版本。 您應該使用更全面的參考手冊 。
我認為您的數據范圍是正確的。 指針與其他變量一樣駐留在RAM中。 與它們所處的位置無關,而是它們指向的對象(在您的情況下是GPIO)很重要。 該代碼看起來是正確的,表示我尚未檢查您要寫入的寄存器的地址是否正確,或者您正在寫入正確的值/寄存器。 嘗試先啟用時鍾。 如有疑問,請查看從ST下載的F3多維數據集中的GPIO示例。 它使用了它們的庫函數,但是您可以在其中查看。 它還提供了一個文件,其中包含我建議您使用的所有寄存器的定義。
我有一個來自亞洲的ebay $ 2,具有相同的零件,並且在C端口13針上有一個LED。
這是一個完整的基於gnu工具鏈的示例,您可以將其更改為在端口d引腳0上操作(或將led移至pc13)
閃存
.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表示的地址(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
如果將led移到pc13,則理想情況下可以直接按原樣使用這些二進制文件之一。
如果您有openocd up,則使用telnet(telnet本地主機4444)
> halt
> flash write_image erase /path/to/blinker01.srec
> reset
它將開始閃爍LED
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.