簡體   English   中英

stm32f103存儲器尋址

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM