0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Cortex-M3精通之路-1(匯編啟動(dòng)文件)

云深之無(wú)跡 ? 來(lái)源:云深之無(wú)跡 ? 2023-05-28 11:32 ? 次閱讀

源碼分析寫了一堆,但是每次都分析不完就鴿了,氣死我了。也思考了很久究竟寫一些怎么樣的文章。

我想通了,要寫一個(gè)合集,精通Cortex-M3!

基本上你加上幾個(gè)實(shí)戰(zhàn)的項(xiàng)目就穩(wěn)了。

其次就是廣泛性,M3會(huì)了,M0難嗎?M0+呢?不言而喻了。我準(zhǔn)備從一個(gè)工程入手,一行一行的代碼,多方權(quán)威資料查詢寫出這個(gè)合集,首先這篇是匯編的啟動(dòng)文件,要求對(duì)讀者的要求是較高的,建議細(xì)細(xì)閱讀。

精通ARM Cortex-M意味著對(duì)ARM Cortex-M內(nèi)核及相關(guān)微控制器有深入全面的理解和高超的開發(fā)技能。具體需要:

1. 深入理解ARM Cortex-M內(nèi)核架構(gòu),包括核心模塊如內(nèi)存保護(hù)單元、中斷控制器、定時(shí)器等,以及指令系統(tǒng)和編程模型。

2. 熟悉各系列ARM Cortex-M內(nèi)核如M0/M3/M4/M7的具體特征與差異,尤其是外設(shè)配置與編程方法。

3.掌握主流MCU廠商基于ARMCortex-M內(nèi)核的微控制器產(chǎn)品,如STM32、Kinetis、EFM32等的詳細(xì)特性和使用方法。

4. 精通CMSIS標(biāo)準(zhǔn),熟練使用其提供的寄存器訪問(wèn)函數(shù)、外設(shè)驅(qū)動(dòng)、啟動(dòng)文件、調(diào)試工具等,快速開發(fā)MCU應(yīng)用程序。

5. 具有豐富的開發(fā)經(jīng)驗(yàn),能夠熟練完成MCU資源配置、時(shí)鐘選擇、中斷服務(wù)程序編寫、外設(shè)驅(qū)動(dòng)開發(fā)等,并對(duì)各種復(fù)雜問(wèn)題進(jìn)行快速解決。

6. 具備一定的創(chuàng)新能力,能基于對(duì)內(nèi)核和MCU的深入理解進(jìn)行功能優(yōu)化與改進(jìn),開發(fā)出技術(shù)水平更高的程序。

ARM官網(wǎng)找的圖

6b0e107e-fcc0-11ed-90ce-dac502259ad0.png

這個(gè)就是M3內(nèi)核的特性

6b2aec12-fcc0-11ed-90ce-dac502259ad0.png

一個(gè)和別的內(nèi)核的對(duì)比圖

6b59fe9e-fcc0-11ed-90ce-dac502259ad0.png

Corstone-101,官網(wǎng)看見的

我真服了,全網(wǎng)找不到這個(gè)開發(fā)板啥樣子??

Corstone-101是Arm推出的一款入門級(jí)的MCU開發(fā)板,目的是幫助工程師輕松學(xué)習(xí) Arm Cortex-M系列MCU。

Corstone-101開發(fā)板的主要特性:-

- MCU:采用Arm Cortex-M3內(nèi)核的STM32F103RB芯片

-集成CMSIS-DAP debug probe,支持無(wú)縫調(diào)試- 板載各類外設(shè)和接口:LCD顯示屏、LED、按鍵、USB轉(zhuǎn)串口、MicroSD卡槽等

- Arm Mbed OS預(yù)裝,可直接進(jìn)行MCU軟件開發(fā)

-免費(fèi)開源的課程教材,包括從零開始快速入門stm32的開發(fā)環(huán)境搭建,到深入學(xué)習(xí)stm32的定時(shí)器、串口、DMA等。

-低成本,入門友好,非常適合Cortex-M內(nèi)核和MCU開發(fā)入門Corstone-101的主要特點(diǎn)是:

1)集成度高:MCU、Debug probe、豐富外設(shè)、Mbed OS軟件平臺(tái)均集成在一塊開發(fā)板上,使用非常方便。

2)教學(xué)優(yōu)勢(shì):提供極為詳盡的中文視頻教程和文檔,可以零基礎(chǔ)快速學(xué)習(xí)stm32和MCU開發(fā)。

3) 低成本:Corstone-101開發(fā)板定價(jià)非常低,大約250元人民幣,非常適合入門體驗(yàn)。

4) Mbed OS支持:基于Mbed OS,可以使用其豐富的庫(kù)函數(shù)包以及在線編譯環(huán)境快速開發(fā)應(yīng)用程序,降低學(xué)習(xí)門檻。

250這個(gè)價(jià)格,我還是覺得不夠低成本哈。

6b745122-fcc0-11ed-90ce-dac502259ad0.png

倒是和我說(shuō)的差不多

本來(lái)今天就是要說(shuō)這個(gè)CMSIS的,但是這個(gè)已經(jīng)是抽象的高層了,所以先寫匯編。

CMSIS是ARM Cortex-M系列內(nèi)核的設(shè)備抽象層,全稱為Cortex Microcontroller Software Interface Standard。它定義了一套標(biāo)準(zhǔn)的軟件接口,用于開發(fā)基于ARM Cortex-M內(nèi)核的MCU設(shè)備的固件。主要包含:

- 設(shè)備寄存器及外設(shè)訪問(wèn)函數(shù)庫(kù):提供標(biāo)準(zhǔn)的API訪問(wèn)MCU內(nèi)核寄存器和外設(shè),屏蔽不同芯片的寄存器差異。

- 啟動(dòng)文件和鏈接腳本:提供標(biāo)準(zhǔn)的MCU啟動(dòng)和內(nèi)存布局文件,用于引導(dǎo)程序運(yùn)行和鏈接。

- 中斷服務(wù)例程:提供標(biāo)準(zhǔn)的中斷服務(wù)例程入口定義,用于編寫設(shè)備特定的中斷服務(wù)程序。

- 調(diào)試寄存器訪問(wèn)宏:標(biāo)準(zhǔn)宏定義訪問(wèn)用于MCU調(diào)試的寄存器。

- 標(biāo)準(zhǔn)外設(shè)驅(qū)動(dòng)庫(kù):為常用外設(shè)提供跨MCU通用的驅(qū)動(dòng)庫(kù),如GPIO、USART等。

CMSIS的主要目的是降低基于Cortex-M內(nèi)核MCU的開發(fā)復(fù)雜度,屏蔽芯片差異,實(shí)現(xiàn)跨MCU的代碼可重用性。

開發(fā)者可以專注于應(yīng)用程序本身的開發(fā),而不需過(guò)多關(guān)注具體MCU的配置細(xì)節(jié)。目前,主流的MCU廠商如ST、NXP、TI等都提供了基于CMSIS標(biāo)準(zhǔn)的固件庫(kù)和例程,使用這些CMSIS標(biāo)準(zhǔn)的固件庫(kù)可以輕松配置和訪問(wèn)MCU資源,開發(fā)出高質(zhì)量的程序。

CMSIS本質(zhì)上是一個(gè)標(biāo)準(zhǔn)的固件庫(kù)和軟件接口。它提供:

1. 標(biāo)準(zhǔn)的寄存器外設(shè)訪問(wèn)函數(shù)庫(kù),相當(dāng)于一個(gè)硬件抽象層,屏蔽不同MCU的寄存器差異,實(shí)現(xiàn)統(tǒng)一的訪問(wèn)接口。

2. 標(biāo)準(zhǔn)的啟動(dòng)文件、鏈接腳本和外設(shè)驅(qū)動(dòng),支持MCU啟動(dòng)、內(nèi)存配置和常用外設(shè)的使用。

3. 標(biāo)準(zhǔn)的中斷服務(wù)例程入口定義和調(diào)試宏定義。

4. 其他工具和示例程序等。

所以,CMSIS為MCU開發(fā)提供了一系列標(biāo)準(zhǔn)化和統(tǒng)一的固件基礎(chǔ)設(shè)施,開發(fā)者可以直接基于CMSIS開發(fā)應(yīng)用程序,而不需過(guò)多關(guān)注MCU本身的配置細(xì)節(jié)。這大大降低了基于ARM Cortex-M內(nèi)核MCU開發(fā)的難度,實(shí)現(xiàn)了跨MCU的代碼可重用性。但是,CMSIS本身并不是一個(gè)完整的MCU固件庫(kù)。它僅定義了一系列標(biāo)準(zhǔn),提供基本的訪問(wèn)接口和工具,但具體的 periperal drivers(外設(shè)驅(qū)動(dòng))和board support package(板級(jí)支持包)還需要芯片廠商及開發(fā)板廠商基于CMSIS標(biāo)準(zhǔn)開發(fā)和提供。所以,CMSIS給MCU開發(fā)帶來(lái)的主要價(jià)值在于:

1. 標(biāo)準(zhǔn)化:定義一套行業(yè)標(biāo)準(zhǔn)的軟件接口和規(guī)范。

2. 抽象化:提供硬件抽象層,屏蔽MCU差異,實(shí)現(xiàn)統(tǒng)一編程模型。

3. 可重用性:基于標(biāo)準(zhǔn)接口開發(fā)的代碼可以重用于不同的MCU,降低開發(fā)成本。

ARM Cortex-M3內(nèi)核適合使用CMSIS版本3.0及以上版本。CMSIS最初發(fā)布于2008年,當(dāng)時(shí)的版本為1.0,主要支持ARM Cortex-M0和M3內(nèi)核。隨著CMSIS標(biāo)準(zhǔn)的不斷發(fā)展和Cortex-M內(nèi)核系列的增加,CMSIS也在發(fā)布新版本以支持更多內(nèi)核和增加更多功能。主要版本發(fā)布情況如下:

- CMSIS 1.0:2008年,支持Cortex-M0和M3內(nèi)核。

- CMSIS 2.0:2010年,增加對(duì)Cortex-M4內(nèi)核的支持。- CMSIS 3.0:2012年,統(tǒng)一設(shè)備抽象層,增加debug和RTOS功能。

- CMSIS 3.1:2013年,添加CMSIS-DAP接口和新增Cortex-M7內(nèi)核支持。- CMSIS 3.2:2014年,新增配置 wizard 工具和ARM Compiler 6支持。

- CMSIS 5.0:2016年,重構(gòu)代碼結(jié)構(gòu),支持基于CMSIS-Core的Middleware組件。

- CMSIS 5.1:2017年,新增CMSIS-Driver概念,擴(kuò)充外設(shè)驅(qū)動(dòng)支持。所以,對(duì)于ARM Cortex-M3內(nèi)核,CMSIS 3.0版本及以后版本均有很好的支持,提供設(shè)備抽象層、debug工具、標(biāo)準(zhǔn)外設(shè)驅(qū)動(dòng)等,可以很好地滿足基于Cortex-M3內(nèi)核MCU開發(fā)的需求。

6ba33226-fcc0-11ed-90ce-dac502259ad0.png

我們來(lái)學(xué)學(xué)32里面的CMSIS里面的啟動(dòng)文件

startup_stm32f10x_cl.s是STM32F10x系列MCU的啟動(dòng)文件,由ARM官方提供。啟動(dòng)文件主要完成以下工作:

1. 設(shè)置堆棧指針(MSP),為中斷服務(wù)程序和中斷向量表預(yù)留堆??臻g。

2.檢查復(fù)位源,并清除相應(yīng)的復(fù)位標(biāo)志。

3.設(shè)置中斷向量表偏移地址,指向__Vectors段。

4.如果需要,設(shè)置中斷向量表在RAM中的拷貝。

5. 如果需要,設(shè)置FPU寄存器為默認(rèn)值。

6. 調(diào)用SystemInit()函數(shù)初始化系統(tǒng)時(shí)鐘和外設(shè)。

7.調(diào)用__main()函數(shù)進(jìn)入C代碼。啟動(dòng)文件一般由匯編語(yǔ)言編寫,需要做的工作主要是CPU及外設(shè)的最低層初始化配置,為后續(xù)C代碼的運(yùn)行做好準(zhǔn)備。

6bba22ec-fcc0-11ed-90ce-dac502259ad0.png

看這個(gè)代碼

Stack_SizeEQU0x00000400

這行定義了堆棧的大小為0x400字節(jié),即1024字節(jié)。

AREA STACK, NOINIT, READWRITE, ALIGN=3

這行指令定義了一個(gè)名為STACK的無(wú)初值段,屬性為可讀寫,并且地址對(duì)齊到4字節(jié)。這個(gè)段用于定義堆??臻g。

Stack_Mem SPACE Stack_Size

這行在STACK段內(nèi)分配了0x400字節(jié)的存儲(chǔ)空間,作為MCU的堆??臻g。

__initial_sp

這行將當(dāng)前位置的值定義為__initial_sp標(biāo)號(hào),該標(biāo)號(hào)的值為堆棧底地址,即堆棧指針SP的初始值。

所以,這段匯編代碼完成了以下工作:

1. 定義了1024字節(jié)的堆棧存儲(chǔ)空間Stack_Mem。

2.使用__initial_sp標(biāo)號(hào)來(lái)指向這個(gè)堆棧空間的底部,這就是SP寄存器的復(fù)位值。

3.啟動(dòng)文件會(huì)將MSP(主堆棧指針)初始化為__initial_sp的值,這樣堆??臻gStack_Mem就關(guān)聯(lián)到主堆棧,為中斷服務(wù)程序的執(zhí)行做好準(zhǔn)備。

4.該堆??臻g也會(huì)在復(fù)位后由C代碼繼續(xù)使用,以存儲(chǔ)函數(shù)調(diào)用的返回信息等。

該段代碼定義的堆??臻gStack_Mem所在的區(qū)域是MCU的內(nèi)存空間。

MCU的內(nèi)存空間一般可以分為以下幾個(gè)區(qū)域:

1.FLASH:程序存儲(chǔ)區(qū)域,用于存儲(chǔ)程序代碼。

2.SRAM:靜態(tài)RAM,用于數(shù)據(jù)存儲(chǔ)和堆??臻g。

3.HEAP:動(dòng)態(tài)內(nèi)存分配區(qū)域,一般也在SRAM中,用于malloc/free管理。

4.STACK:函數(shù)調(diào)用堆??臻g,用于存儲(chǔ)函數(shù)調(diào)用的返回地址、參數(shù)等信息,一般在SRAM頂部。

所以,對(duì)于Startup文件來(lái)說(shuō),在SRAM中預(yù)留一段空間作為堆棧區(qū)域,這個(gè)區(qū)域就是用來(lái)作為中斷服務(wù)程序和系統(tǒng)調(diào)用等的堆棧空間,用于保存CPU運(yùn)行現(xiàn)場(chǎng)等信息,這個(gè)區(qū)域就是我們這段代碼定義的Stack_Mem。

具體來(lái)說(shuō):

AREA STACK, NOINIT, READWRITE, ALIGN=3

這行定義了一個(gè)名為STACK的段,該段位于SRAM中,用于定義堆??臻g。

Stack_Mem SPACE Stack_Size

這行在該STACK段內(nèi)分配了Stack_Size字節(jié)的存儲(chǔ)空間,作為MCU的堆??臻g。

__initial_sp 該標(biāo)號(hào)的值為這個(gè)Stack_Mem的底部地址,即堆棧指針SP的初值。所以,總結(jié)來(lái)說(shuō):

1.該段代碼定義的堆??臻gStack_Mem位于MCU的內(nèi)存空間SRAM中。

2.它為中斷服務(wù)程序和函數(shù)調(diào)用預(yù)留了一片存儲(chǔ)區(qū)域。

3.這個(gè)存儲(chǔ)區(qū)域的底部地址被__initial_sp標(biāo)號(hào)指向,用于初始化SP寄存器的值。

4.然后SP寄存器(堆棧指針)在程序運(yùn)行過(guò)程中會(huì)根據(jù)推棧和出棧操作在這個(gè)區(qū)域中上移和下移。

堆棧底地址指的是堆??臻g的最低可用地址,它表示堆棧區(qū)域中最先分配的空間,用于存放最早推入堆棧的數(shù)據(jù)。

對(duì)于Startup文件來(lái)說(shuō),它使用__initial_sp標(biāo)號(hào)來(lái)標(biāo)記堆棧底地址,這就是SP寄存器(堆棧指針)的初始值。

具體代碼如下:

AREA STACK, NOINIT, READWRITE, ALIGN=3

Stack_Mem SPACE Stack_Size __initial_sp

這段代碼:

1. 定義了大小為Stack_Size的堆??臻gStack_Mem。

2.__initial_sp標(biāo)號(hào)的值指向Stack_Mem的最低地址,這就是堆棧底地址。3.啟動(dòng)文件會(huì)將SP寄存器初始化為__initial_sp的值,使其指向堆棧底,以便后續(xù)的推棧操作。

4.SP寄存器的值會(huì)隨著推棧和出棧操作在Stack_Mem區(qū)域內(nèi)增大和減小。所以,對(duì)這個(gè)堆??臻g來(lái)說(shuō):

1.堆棧底地址由__initial_sp標(biāo)號(hào)的值決定,它指向Stack_Mem的最低可用地址。

2.SP寄存器初值為__initial_sp,會(huì)從堆棧底開始向高地址生長(zhǎng),來(lái)保存推入堆棧的數(shù)據(jù)。

3.出棧操作會(huì)使SP寄存器的值減小,釋放堆棧頂?shù)臄?shù)據(jù),直到恢復(fù)到堆棧底。

4.堆??臻g的使用是從底至頂,底部空間存放最早的數(shù)據(jù)。所以,總結(jié)來(lái)說(shuō),堆棧底地址就是堆??臻g中最先被使用的那部分地址空間,它標(biāo)記了堆棧區(qū)域的起始,為堆棧的推棧和出棧操作提供基礎(chǔ)。

6bf08f4e-fcc0-11ed-90ce-dac502259ad0.png

堆!

這段代碼定義了MCU的堆空間以及相關(guān)標(biāo)號(hào)。

具體分析下

Heap_Size EQU 0x00000200

該行定義了堆大小為512字節(jié)(0x200)

AREA HEAP, NOINIT, READWRITE, ALIGN=3

該行指令定義一個(gè)名為HEAP的無(wú)初值段,具有讀寫屬性,地址按4字節(jié)對(duì)齊。這個(gè)段用于定義堆空間。

__heap_base 該標(biāo)號(hào)的值為HEAP段的起始地址,表示堆底地址。

Heap_Mem SPACE Heap_Size

該行在HEAP段中分配了0x200字節(jié)的存儲(chǔ)空間作為MCU的堆空間。

__heap_limit

該標(biāo)號(hào)的值為HEAP段結(jié)束地址,表示堆頂?shù)刂贰?/span>

所以,這段匯編代碼完成了以下工作:

1. 定義了512字節(jié)的堆存儲(chǔ)空間Heap_Mem。

2. 使用__heap_base標(biāo)號(hào)來(lái)標(biāo)記這個(gè)堆空間的起始地址,表示堆底。

3. 使用__heap_limit標(biāo)號(hào)來(lái)標(biāo)記這個(gè)堆空間的結(jié)束地址,表示堆頂。

4. 該堆空間在程序運(yùn)行過(guò)程中由malloc/free管理動(dòng)態(tài)內(nèi)存的分配與釋放。5. C語(yǔ)言中可以通過(guò)extern聲明__heap_base和__heap_limit,以獲取堆信息。

6. PRESERVE8指令用于強(qiáng)制8字節(jié)對(duì)齊。

THUMB指令指定該代碼區(qū)使用Thumb-2指令。

該段代碼定義的堆空間為MCU動(dòng)態(tài)內(nèi)存管理提供了存儲(chǔ)區(qū)域與邊界標(biāo)記。通過(guò)__heap_base和__heap_limit,C代碼可以方便獲取到這個(gè)堆空間的信息,為malloc/free調(diào)用服務(wù)。所以,這段匯編代碼對(duì)MCU的動(dòng)態(tài)內(nèi)存分配起到很關(guān)鍵的作業(yè)。

這里說(shuō)下如何訪問(wèn)??臻g。

對(duì)于啟動(dòng)文件定義的堆??臻gStack_Mem來(lái)說(shuō),如果要在C代碼中訪問(wèn)和使用這個(gè)區(qū)域,有以下幾種方法:

1. 使用全局變量在Startup文件中定義:

Stack_Mem SPACE Stack_Size __initial_sp

然后在C代碼中使用全局變量聲明:

6c1f0b62-fcc0-11ed-90ce-dac502259ad0.png

這樣stack_ptr變量就指向了堆棧頂,可以通過(guò)stack_ptr訪問(wèn)和修改堆??臻g中的數(shù)據(jù)。

2. 基址偏移Startup文件中Label Stack_Mem的地址為base_addr,則在C代碼中可以通過(guò):

unsigned int stack_ptr = (unsigned int )(base_addr + Stack_Size -

4);

來(lái)得到堆棧頂指針,以訪問(wèn)數(shù)據(jù)。需要知道Stack_Mem的絕對(duì)地址base_addr。

3. 定義指針數(shù)組在C代碼中聲明指針數(shù):

unsigned int Stack[Stack_Size];然后stack_ptr = &Stack[Sta

ck_Size - 1];

這種方法需要在鏈接過(guò)程中正確設(shè)置該指針數(shù)組與Startup文件中Stack_Mem區(qū)域的關(guān)聯(lián)。

4. 借助寄存器因?yàn)镾tartup文件已經(jīng)將SP寄存器初始化為__initial_sp,也就是Stack_Mem底部,所以我們可以通過(guò)SP寄存器讀寫這個(gè)區(qū)域:

6c31b1ae-fcc0-11ed-90ce-dac502259ad0.png

使用inline匯編直接通過(guò)SP寄存器讀寫堆??臻g。

好了,再說(shuō)堆空間的作用:

堆空間主要用于MCU的動(dòng)態(tài)內(nèi)存分配,它為malloc()和free()函數(shù)調(diào)用提供內(nèi)存池。具體來(lái)說(shuō),堆空間在MCU中的作用有:

1. 為動(dòng)態(tài)內(nèi)存申請(qǐng)?zhí)峁┐鎯?chǔ)空間:在程序運(yùn)行時(shí),可以通過(guò)malloc()函數(shù)向堆空間申請(qǐng)任意大小的內(nèi)存塊,以保存數(shù)據(jù)或創(chuàng)建對(duì)象。

2. 釋放不再使用的內(nèi)存:通過(guò)free()函數(shù)可以將堆空間中的內(nèi)存塊釋放,以便下次繼續(xù)使用。

3. 管理內(nèi)存碎片:堆空間可以由malloc()函數(shù)自動(dòng)管理內(nèi)存碎片,試圖利用所有的內(nèi)存空間。

4. 實(shí)現(xiàn)內(nèi)存動(dòng)態(tài)擴(kuò)展:如果堆空間初始分配的空間不足,還可以在運(yùn)行時(shí)通過(guò)sbrk()函數(shù)向操作系統(tǒng)申請(qǐng)更多內(nèi)存空間。

5. C++程序的new和delete操作也依賴于堆空間,用于創(chuàng)建和銷毀對(duì)象。

所以,簡(jiǎn)單來(lái)說(shuō),堆空間為動(dòng)態(tài)內(nèi)存分配提供內(nèi)存池,它最大的作用在于:

1. 滿足運(yùn)行時(shí)變化的內(nèi)存需求,程序不確定對(duì)象到底占用多少內(nèi)存空間,只能在運(yùn)行時(shí)進(jìn)行內(nèi)存分配。

2. 實(shí)現(xiàn)堆內(nèi)存的重復(fù)分配與釋放,節(jié)省內(nèi)存空間,避免內(nèi)存浪費(fèi)。

3. C++程序可以在堆上創(chuàng)建對(duì)象,并使用new和delete進(jìn)行內(nèi)存管理??傊?堆空間為程序運(yùn)行時(shí)的動(dòng)態(tài)內(nèi)存分配需求提供了支持,它的管理主要依賴malloc、free和new、delete函數(shù)。

堆棧的區(qū)別是什么?

堆空間和??臻g都是MCU內(nèi)存空間的一部分,但二者有以下主要區(qū)別:

1. 生長(zhǎng)方向不同:

堆空間:向高地址生長(zhǎng),使用malloc()函數(shù)申請(qǐng)內(nèi)存,按需動(dòng)態(tài)分配。

??臻g:向低地址生長(zhǎng),大小在編譯時(shí)確定,自動(dòng)分配。

2. 申請(qǐng)方式不同:堆空間:使用malloc()和free()函數(shù)顯式申請(qǐng)和釋放內(nèi)存。棧空間: FUN調(diào)用時(shí)自動(dòng)分配和釋放,不需要顯式控制。

3. 生命周期不同:

堆空間:使用完畢須手動(dòng)釋放,生命周期不確定,動(dòng)態(tài)決定。

??臻g:函數(shù)調(diào)用結(jié)束自動(dòng)釋放,生命周期與函數(shù)調(diào)用一致,編譯時(shí)決定。

4. 使用目的不同:

堆空間:用于動(dòng)態(tài)內(nèi)存分配,對(duì)象創(chuàng)建。

棧空間:用于存儲(chǔ)函數(shù)參數(shù)、局部變量、返回地址等,實(shí)現(xiàn)函數(shù)調(diào)用機(jī)制。

5. 空間大小不同:

堆空間:大小動(dòng)態(tài)變化,按需分配。

??臻g:大小在編譯時(shí)確定,固定分配。

所以,總結(jié)來(lái)說(shuō):

堆空間為動(dòng)態(tài)內(nèi)存分配和對(duì)象創(chuàng)建提供能力,大小和生命周期不定,需要手工管理。

??臻g為函數(shù)調(diào)用機(jī)制提供自動(dòng)分配和釋放的臨時(shí)存儲(chǔ)空間,大小和生命周期在編譯時(shí)決定,無(wú)需手工控制。

我直接回馬槍,堆空間如何訪問(wèn)呢?

1. 使用全局變量
在啟動(dòng)文件中定義:

6c5cf3a0-fcc0-11ed-90ce-dac502259ad0.png?

然后在C代碼中使用全局變量聲明:

6c7eb42c-fcc0-11ed-90ce-dac502259ad0.png
這樣heap_ptr變量就指向了堆底,通過(guò)它可以訪問(wèn)堆空間中的數(shù)據(jù)。
2. 基址偏移
啟動(dòng)文件中Label __heap_base和__heap_limit的地址分別為base_addr和limit_addr,則在C代碼中可以通過(guò):

6c9b4510-fcc0-11ed-90ce-dac502259ad0.png

來(lái)訪問(wèn)堆空間數(shù)據(jù),offset為任意偏移量。需要知道__heap_base和__heap_limit的絕對(duì)地址。
3. 定義指針數(shù)組
在C代碼中聲明指針數(shù)組:

6cb17cfe-fcc0-11ed-90ce-dac502259ad0.png

然后heap_ptr = Heap;
這種方法需要在鏈接過(guò)程中正確設(shè)置該指針數(shù)組與啟動(dòng)文件中Heap_Mem區(qū)域的關(guān)聯(lián)。
4. 借助malloc()函數(shù)
因?yàn)閱?dòng)文件已經(jīng)定義了__heap_base和__heap_limit來(lái)標(biāo)識(shí)堆空間的范圍,所以我們可以直接使用malloc()函數(shù)向這個(gè)區(qū)域申請(qǐng)內(nèi)存:

6cc45f4a-fcc0-11ed-90ce-dac502259ad0.png

malloc()函數(shù)會(huì)在Heap_Mem區(qū)域分配size大小的內(nèi)存,并返回其起始地址,通過(guò)ptr訪問(wèn)這片內(nèi)存。

6ce473fc-fcc0-11ed-90ce-dac502259ad0.png

接下來(lái)看這一段

這段代碼定義了STM32的矢量表。

矢量表包含了中斷服務(wù)程序的入口地址,以及系統(tǒng)使用的其他處理程序的入口地址。它位于地址0x00000000,并在復(fù)位后被映射到這個(gè)位置。所以,這段代碼完成的主要工作有:

1. 定義了名為RESET的只讀數(shù)據(jù)段,該段位置是0x00000000。

2. EXPORT指令導(dǎo)出了__Vectors、__Vectors_End和__Vectors_Size標(biāo)號(hào),以方便其他文件使用。

3. __Vectors標(biāo)號(hào)指向矢量表的起始地址。__Vectors_End和__Vectors_Size分別用于標(biāo)識(shí)矢量表的結(jié)束地址和大小。

4. 表起始地址存儲(chǔ)初始堆棧指針SP的值(__initial_sp標(biāo)號(hào))。

5. 接下來(lái)定義了各種異常和中斷處理程序的入口地址:

Reset_Handler:復(fù)位中斷服務(wù)程序

NMI_Handler:NMI中斷服務(wù)程序

HardFault_Handler:硬件故障中斷服務(wù)程序

......

SysTick_Handler:SysTick中斷服務(wù)程序

6. 一些入口保留為0,用于未來(lái)擴(kuò)展。

所以,這個(gè)矢量表完成了以下工作:

1. 定義了各種異常和中斷處理程序的入口地址,這些入口地址指向?qū)?yīng)中斷服務(wù)程序。

2. 矢量表位于地址0x00000000,并在MCU復(fù)位后被映射到這個(gè)位置。

3. 初始SP寄存器的值由矢量表的第一個(gè)字存儲(chǔ)。

4. 中斷發(fā)生時(shí),MCU會(huì)根據(jù)中斷類型在矢量表中找到對(duì)應(yīng)的入口地址,然后跳轉(zhuǎn)到此地址執(zhí)行中斷服務(wù)程序。矢量表是MCU中斷機(jī)制的基礎(chǔ),它為異常和中斷提供入口和服務(wù)程序。所以,這個(gè)矢量表定義對(duì)MCU的中斷配置和服務(wù)起到了基礎(chǔ)作用。

矢量表在MCU的內(nèi)存空間中保存。它以數(shù)組的形式保存,每個(gè)數(shù)組元素存儲(chǔ)一個(gè)函數(shù)入口地址。

具體來(lái)說(shuō):

1. 這個(gè)矢量表定義在啟動(dòng)文件中的RESET數(shù)據(jù)段中,該數(shù)據(jù)段位于內(nèi)存地址0x00000000處。

2. __Vectors標(biāo)號(hào)指向這個(gè)矢量表的數(shù)組起始地址,__Vectors_End標(biāo)號(hào)指向數(shù)組結(jié)束地址。

3. 數(shù)組每個(gè)元素大小為4字節(jié)(32位MCU),用于存儲(chǔ)一個(gè)函數(shù)入口地址。

4. 數(shù)組第一個(gè)元素存儲(chǔ)了初始SP值,接下來(lái)的元素存儲(chǔ)各種異常和中斷處理程序的入口地址。

5. 當(dāng)某個(gè)中斷發(fā)生時(shí),MCU會(huì)計(jì)算出中斷類型對(duì)應(yīng)的數(shù)組下標(biāo),然后跳轉(zhuǎn)到該下標(biāo)元素所指向的入口地址執(zhí)行中斷服務(wù)程序。

6. 這個(gè)數(shù)組實(shí)際上定義在編譯器產(chǎn)生的啟動(dòng)文件匯編代碼中。然后通過(guò)鏈接器與其他文件連接,最終在MCU的內(nèi)存空間布局中實(shí)現(xiàn)布局。

所以,總結(jié)來(lái)說(shuō):

1. 這個(gè)矢量表以數(shù)組的形式在MCU內(nèi)存中實(shí)現(xiàn),數(shù)組每個(gè)元素存儲(chǔ)一個(gè)入口地址。

2. 數(shù)組第一個(gè)元素存儲(chǔ)SP初值,其他元素存儲(chǔ)異常和中斷服務(wù)程序的入口地址。

3. 該數(shù)組位于地址0x00000000,在MCU上電復(fù)位后被映射到該位置。

4. 中斷發(fā)生時(shí),通過(guò)中斷類型計(jì)算數(shù)組下標(biāo),獲取中斷服務(wù)程序入口地址。

5. 該數(shù)組最終通過(guò)鏈接過(guò)程存放在MCU內(nèi)存的正確位置,并在程序運(yùn)行時(shí)被使用。這種數(shù)組的形式便于通過(guò)索引快速查找對(duì)應(yīng)的入口地址,實(shí)現(xiàn)MCU的異常和中斷機(jī)制。所以,矢量表采用這種數(shù)組結(jié)構(gòu)實(shí)際上加快了中斷響應(yīng)速度,提高了系統(tǒng)實(shí)時(shí)性。

6d2db9e0-fcc0-11ed-90ce-dac502259ad0.png

下面還有一段,其實(shí)和上面一樣,都是地址而已

6d868372-fcc0-11ed-90ce-dac502259ad0.png

接下來(lái)看這段

所有的單片機(jī),電腦,都會(huì)說(shuō)復(fù)位這個(gè)事情。那它為什么如此的重要?因?yàn)槲覀優(yōu)榱丝煽兀械某跏蓟覀冎?,運(yùn)行的規(guī)律知道,所以復(fù)位是為了可控而已。

復(fù)位中斷服務(wù)程序(Reset Handler)之所以存在,主要是為了實(shí)現(xiàn)MCU的初始化配置和C語(yǔ)言程序的啟動(dòng)。

具體來(lái)說(shuō),Reset Handler的作用有:

1. 完成MCU的初始化配置:設(shè)置時(shí)鐘,配置GPIO等,為程序正確運(yùn)行做準(zhǔn)備。這一般由啟動(dòng)文件中定義的SystemInit函數(shù)完成。

2. 跳轉(zhuǎn)到C語(yǔ)言程序的入口函數(shù)__main:C語(yǔ)言程序的執(zhí)行是從__main函數(shù)開始的,所以Reset Handler需要跳轉(zhuǎn)到__main函數(shù)。

3. 設(shè)置初始堆棧指針SP的值:在MCU上電復(fù)位后,SP寄存器的值是未知的,需要設(shè)置為一個(gè)正確的值,以便進(jìn)行后續(xù)的堆棧操作。這個(gè)值通常存儲(chǔ)在矢量表的第一個(gè)元素中。

4. 作為MCU的最高優(yōu)先級(jí)中斷服務(wù)程序:當(dāng)MCU上電或復(fù)位時(shí),首先會(huì)執(zhí)行Reset Handler來(lái)完成系統(tǒng)的初始化和C語(yǔ)言程序的啟動(dòng)。

5. 如果用戶定義了自己的Reset Handler,它將覆蓋啟動(dòng)文件中的定義,用戶程序?qū)挠脩舳x的Reset Handler開始執(zhí)行。

所以,簡(jiǎn)單來(lái)說(shuō),Reset Handler之所以存在,主要是為了:

1. 完成MCU的初始化配置,為正確運(yùn)行提供基礎(chǔ)。

2. 跳轉(zhuǎn)到C語(yǔ)言程序的入口,啟動(dòng)程序執(zhí)行。

3. 設(shè)置SP寄存器的初始值,為使用堆棧做準(zhǔn)備。

4. 作為上電復(fù)位中斷服務(wù)程序,首先被執(zhí)行。

5. 可以被用戶定義的Reset Handler覆蓋。如果沒有Reset Handler,MCU將啟動(dòng)在未初始化的狀態(tài),C語(yǔ)言程序也無(wú)法得到執(zhí)行,SP的值是未知的,這會(huì)導(dǎo)致程序運(yùn)行錯(cuò)誤或無(wú)法運(yùn)行。所以,Reset Handler對(duì)MCU的啟動(dòng)起到了基礎(chǔ)作用,它為C程序的執(zhí)行提供了啟動(dòng)條件和基本環(huán)境,是MCU上電必不可少的初始化代碼。

來(lái),這次有了前置知識(shí)再看代碼:

代碼定義了復(fù)位中斷服務(wù)程序Reset_Handler。具體分析如下:

__Vectors_Size EQU __Vectors_End - __Vectors

這行指令計(jì)算了矢量表的大小,用于其他文件使用。

AREA |.text|, CODE, READONLY

這行指令定義了一個(gè)只讀的代碼段,用于存放異常和中斷服務(wù)程序。

Reset_Handler PROC

這行指令定義了Reset_Handler的過(guò)程,表示復(fù)位中斷服務(wù)程序的起始。

EXPORT Reset_Handler [WEAK]

此行導(dǎo)出Reset_Handler過(guò)程,以便其他文件使用,并指定該過(guò)程為弱定義,意味著如果用戶定義了自己的Reset_Handler過(guò)程,那么編譯器會(huì)使用用戶定義的過(guò)程,而忽略此處的定義。

6d9fd0ca-fcc0-11ed-90ce-dac502259ad0.png

看這個(gè)

IMPORTSystemInit

此行導(dǎo)入SystemInit函數(shù),表示Reset_Handler過(guò)程調(diào)用該函數(shù)。

IMPORT __main

此行導(dǎo)入C語(yǔ)言程序的入口函數(shù)__main。

LDR R0, =SystemInit

此指令將SystemInit函數(shù)地址加載到R0寄存器。

BLX R0

此指令調(diào)用SystemInit函數(shù)。

LDR R0, =__main

此指令將__main函數(shù)地址加載到R0寄存器。

BX R0

此指令跳轉(zhuǎn)到__main函數(shù),執(zhí)行C語(yǔ)言程序。

ENDP

此行指令表示Reset_Handler過(guò)程的結(jié)束。

所以,這個(gè)Reset_Handler過(guò)程完成了以下工作:

1. 調(diào)用SystemInit函數(shù)完成系統(tǒng)初始化。

2. 跳轉(zhuǎn)到__main函數(shù),執(zhí)行C語(yǔ)言程序。

3. 作為復(fù)位中斷的中斷服務(wù)程序,在MCU上電復(fù)位后首先被執(zhí)行。

4. 如果用戶定義了自己的Reset_Handler,那么由于該過(guò)程被定義為弱定義,用戶定義會(huì)覆蓋此處定義,被執(zhí)行。該過(guò)程為C語(yǔ)言程序的執(zhí)行提供了啟動(dòng)入口,完成了MCU的初始化配置.

6dc9daaa-fcc0-11ed-90ce-dac502259ad0.png

接下來(lái)的代碼很多的一樣,拿兩個(gè)看

這段代碼定義了NMI中斷服務(wù)程序NMI_Handler和硬件故障中斷服務(wù)程序HardFault_Handler。

NMI_Handler PROC

此行定義NMI_Handler過(guò)程,表示NMI中斷服務(wù)程序的起始。

EXPORT NMI_Handler [WEAK]

此行導(dǎo)出NMI_Handler過(guò)程,指定為弱定義,意味著如果用戶定義了自己的NMI_Handler過(guò)程,編譯器會(huì)使用用戶定義的過(guò)程,忽略此處定義。

B . 此指令是一個(gè)空操作,不執(zhí)行任何動(dòng)作。

ENDP

此行表示NMI_Handler過(guò)程的結(jié)束。

HardFault_HandlerPROC

此行定義HardFault_Handler過(guò)程,表示硬件故障中斷服務(wù)程序的起始。EXPORT HardFault_Handler [WEAK]

此行導(dǎo)出HardFault_Handler過(guò)程,指定為弱定義,意味著如果用戶定義了自己的HardFault_Handler過(guò)程,編譯器會(huì)使用用戶定義的過(guò)程,忽略此處定義。

B . 此指令是一個(gè)空操作,不執(zhí)行任何動(dòng)作。

ENDP 此行表示HardFault_Handler過(guò)程的結(jié)束。

所以,這兩個(gè)中斷服務(wù)程序定義完成了:

1. 定義了對(duì)應(yīng)的中斷服務(wù)程序入口,但程序體為空。

2. 將這兩個(gè)過(guò)程定義為弱定義,意味著如果用戶定義了自己的服務(wù)程序,編譯器會(huì)使用用戶定義的過(guò)程。

3. 以空操作結(jié)束了這兩個(gè)過(guò)程。

之所以這兩個(gè)過(guò)程定義為空,主要是考慮到:

1. 出于兼容性考慮,啟動(dòng)文件需要定義所有標(biāo)準(zhǔn)的異常與中斷入口,但具體處理由用戶決定是否定義。

2. 對(duì)于一些使用不太頻繁或處理比較復(fù)雜的中斷,用戶可能按需選擇是否定義自己的服務(wù)程序。

3. 定義為空的中斷服務(wù)程序不會(huì)對(duì)程序產(chǎn)生任何影響,保證定義后的兼容性。

所以,這兩個(gè)定義主要是為了實(shí)現(xiàn)異常與中斷入口的完整定義,但具體處理交由用戶根據(jù)需要選擇是否定義,如果未定義則默認(rèn)為空操作。

6de2a4a4-fcc0-11ed-90ce-dac502259ad0.png

今日最后的代碼,我覺得全網(wǎng)我是最全的啟動(dòng)代碼解析

這段代碼主要用于定義堆棧的初始化。具體分析如下:

IF __MICROLIB

此行條件指令檢查__MICROLIB宏是否被定義。如果定義,執(zhí)行IF內(nèi)語(yǔ)句,否則執(zhí)行ELSE內(nèi)語(yǔ)句。

EXPORT __initial_sp

此行導(dǎo)出__initial_sp符號(hào),用于初始化SP寄存器。

EXPORT __heap_base

此行導(dǎo)出__heap_base符號(hào),用于標(biāo)識(shí)堆起始地址。

EXPORT __heap_limit

此行導(dǎo)出__heap_limit符號(hào),用于標(biāo)識(shí)堆結(jié)束地址。

IMPORT __use_two_region_memory

此行導(dǎo)入__use_two_region_memory符號(hào),用于檢查是否使用兩片內(nèi)存區(qū)域。

__user_initial_stackheap 此符號(hào)用于標(biāo)識(shí)初始化堆棧的過(guò)程。

LDR R0, = Heap_Mem 此指令將堆起始地址加載到R0寄存器。

這幾行指令完成堆起始地址,堆結(jié)束地址,棧起始地址以及棧結(jié)束地址的加載與設(shè)置。

BX LR此指令用于返回,結(jié)束初始化堆棧的過(guò)程。

ALIGN此行用于4字節(jié)對(duì)齊。

ENDIF 此行表示IF語(yǔ)句的結(jié)束。

END 此行表示文件的結(jié)束。

所以,這段代碼的主要工作是:

1. 如果定義了__MICROLIB宏,則直接導(dǎo)出__initial_sp等符號(hào),否則執(zhí)行初始化堆棧的過(guò)程。

2. __user_initial_stackheap過(guò)程用于根據(jù)傳入的Heap_Mem和Stack_Mem參數(shù)設(shè)置堆棧的參數(shù)。

3. 該過(guò)程判斷是否使用兩片區(qū)域設(shè)置堆棧參數(shù),如果使用則設(shè)置兩片區(qū)域的起始結(jié)束地址。

4. 這段代碼的目的是在啟動(dòng)文件中設(shè)置初始化堆棧所需要的參數(shù)與地址,為C語(yǔ)言程序的執(zhí)行提供堆棧環(huán)境。這段代碼的定義為用戶編寫的C語(yǔ)言程序提供了基本的堆棧初始化與設(shè)置,完成了與編譯器相關(guān)的參數(shù)定義,實(shí)現(xiàn)了C語(yǔ)言程序運(yùn)行所需要的內(nèi)存環(huán)境配置。

我再總結(jié)一下:

1. 定義了RESET只讀數(shù)據(jù)段,用于存放矢量表,該段位于地址0x00000000,在上電復(fù)位后被映射到該地址。

2. 定義并導(dǎo)出了__Vectors、__Vectors_End和__Vectors_Size等符號(hào),方便其他文件使用矢量表。

3. 矢量表首地址存儲(chǔ)初始SP值,其他地址存儲(chǔ)各種異常和中斷服務(wù)程序入口。

4. 定義了復(fù)位中斷服務(wù)程序Reset_Handler,它調(diào)用SystemInit完成系統(tǒng)初始化,然后跳轉(zhuǎn)到__main函數(shù)執(zhí)行C語(yǔ)言程序。

5. 定義了部分中斷服務(wù)程序如NMI_Handler和HardFault_Handler,但僅定義了入口,程序體為空,這主要考慮程序的兼容性與擴(kuò)展性。

6. 根據(jù)__MICROLIB的定義情況,選擇是否執(zhí)行__user_initial_stackheap過(guò)程來(lái)設(shè)置堆棧參數(shù),為C語(yǔ)言程序執(zhí)行提供堆棧環(huán)境。

7. 定義并導(dǎo)出了__initial_sp、__heap_base和__heap_limit等符號(hào),用于標(biāo)識(shí)SP、堆和棧的起始和結(jié)束地址。

8. 使用ALIGN指令實(shí)現(xiàn)了部分字節(jié)對(duì)齊,提高了程序的兼容性和效率。

9. 文件最后通過(guò)END指令實(shí)現(xiàn)了文件的結(jié)束。

所以,這個(gè)啟動(dòng)文件完成的主要工作是:

1. 完成MCU的復(fù)位向量表定義,為各種中斷提供入口與服務(wù)。

2. 定義復(fù)位中斷服務(wù)程序,完成系統(tǒng)初始化和C語(yǔ)言程序啟動(dòng)。

3. 定義部分中斷服務(wù)程序入口,但程序體為空,由用戶決定是否具體定義。

4. 根據(jù)情況設(shè)置堆棧參數(shù),為C語(yǔ)言程序執(zhí)行提供環(huán)境。

5. 定義各種導(dǎo)出符號(hào),方便其他文件使用。

6. 使用ALIGN實(shí)現(xiàn)部分字節(jié)對(duì)齊,提高效率。7. 標(biāo)識(shí)文件的結(jié)束。

頻繁的說(shuō)這個(gè)對(duì)齊,我補(bǔ)個(gè)對(duì)齊的作用:

字節(jié)對(duì)齊指的是存儲(chǔ)單元的地址要遵循某種邊界限制,即地址的低幾位要為0。

它的主要作用有:

1. 提高訪問(wèn)效率:當(dāng)數(shù)據(jù)的地址是某種邊界的整數(shù)倍時(shí),CPU可以以更大寬度的訪問(wèn)單元去訪問(wèn)數(shù)據(jù),這樣可以減少CPU讀取數(shù)據(jù)的次數(shù),提高訪問(wèn)效率。2. 減少存儲(chǔ)空間浪費(fèi):如果不對(duì)齊,在訪問(wèn)更大寬度的數(shù)據(jù)類型時(shí),CPU需要訪問(wèn)的數(shù)據(jù)可能超出實(shí)際需要,這會(huì)占用額外的存儲(chǔ)空間并影響總線帶寬,對(duì)齊可以避免這種浪費(fèi)。

3. 方便數(shù)據(jù)的轉(zhuǎn)換:在某些特定的地址處訪問(wèn)的數(shù)據(jù)可以直接轉(zhuǎn)換為其他數(shù)據(jù)類型,這可以提高處理效率,如果地址未對(duì)齊,這種直接轉(zhuǎn)換就無(wú)法實(shí)現(xiàn)。

總的來(lái)說(shuō),字節(jié)對(duì)齊主要帶來(lái)三個(gè)方面的好處:

1. 提高訪問(wèn)和處理數(shù)據(jù)的效率。

2. 避免存儲(chǔ)空間的浪費(fèi)。

3. 方便數(shù)據(jù)之間的直接轉(zhuǎn)換。

而對(duì)齊的基本實(shí)現(xiàn)方法是:

1. 指定對(duì)齊類型:如2字節(jié)對(duì)齊、4字節(jié)對(duì)齊等,這通常由編譯器來(lái)指定,可以通過(guò)定義宏的方式實(shí)現(xiàn)。

2. 數(shù)據(jù)聲明時(shí)通過(guò)對(duì)齊類型進(jìn)行限定:如int __align(4) num;表示num為4字節(jié)對(duì)齊。

3. 在某些關(guān)鍵數(shù)據(jù)聲明前通過(guò)專用指令進(jìn)行手動(dòng)對(duì)齊:如ALIGN 4對(duì)下一數(shù)據(jù)進(jìn)行4字節(jié)對(duì)齊。

4. 編譯器會(huì)自動(dòng)選擇合適的對(duì)齊方式來(lái)對(duì)數(shù)據(jù)進(jìn)行對(duì)齊,通常為最大數(shù)據(jù)類型的長(zhǎng)度,這樣可以發(fā)揮對(duì)齊帶來(lái)的所有好處。

6e0ba05c-fcc0-11ed-90ce-dac502259ad0.png

這幾個(gè)文件詳細(xì)的作用我之后的文章來(lái)說(shuō)

core_cm3.c是CMSIS標(biāo)準(zhǔn)定義的Cortex-M3內(nèi)核芯片支持包,它提供了以下內(nèi)容:

1. MCU寄存器結(jié)構(gòu)體定義:SCB, SysTick, NVIC等內(nèi)核寄存器的結(jié)構(gòu)體定義。

2. 系統(tǒng)時(shí)鐘配置函數(shù):CMU_ClkInit()、CMU_ClockSelectConfig()等。

3. 系統(tǒng)滴答配置函數(shù):SysTick_Config()用于配置SysTick定時(shí)器的溢出中斷周期。

4. 中斷配置函數(shù):NVIC_EnableIRQ()、NVIC_DisableIRQ()、NVIC_SetPriority()等,用于配置中斷優(yōu)先級(jí)與使能狀態(tài)。

5. 系統(tǒng)SoftReset和HardReset函數(shù):用于軟復(fù)位和硬復(fù)位MCU。

6. 內(nèi)部Flash配置函數(shù):用于配置Flash預(yù)取指緩存、等待信號(hào)以及訪問(wèn)權(quán)限等。

7. 函數(shù)調(diào)用棧配置函數(shù):用于配置PSP堆棧指針和MSP主堆棧指針。

8. 系統(tǒng)滴答定時(shí)器SysTick的中斷服務(wù)函數(shù)SysTick_Handler()。

9. 設(shè)備向量表__Vectors定義,里面包含SysTick和外設(shè)中斷服務(wù)程序入口,以及各類異常入口。

10. 用戶可根據(jù)需要實(shí)現(xiàn)的空操作清零函數(shù):Default_Handler()。

11. MPU配置函數(shù):用于配置內(nèi)存保護(hù)單元,設(shè)定不同存儲(chǔ)區(qū)域的訪問(wèn)權(quán)限。 所以,core_cm3.c文件為基于Cortex-M3內(nèi)核的MCU提供了系統(tǒng)級(jí)配置與接口,包括時(shí)鐘、中斷、內(nèi)存管理等方方面面。用戶可以直接調(diào)用這些函數(shù)接口來(lái)配置MCU,也可以根據(jù)需要修改或擴(kuò)充。這個(gè)文件遵循CMSIS標(biāo)準(zhǔn),具有很高的通用性,主要目的是降低不同MCU的移植difficulty,加速嵌入式工程師的開發(fā)工作。所以,它是開發(fā)基于ARM Cortex-M3內(nèi)核MCU的重要基石。

stm32f10x.h是ST公司為STM32F10x系列MCU提供的頂層頭文件,它包含以下內(nèi)容:

1. 對(duì)標(biāo)準(zhǔn)庫(kù)的引用,如stdint.h、stdbool.h等。

2. 對(duì)CMSIS標(biāo)準(zhǔn)的引用,引入CMSIS定義的一些數(shù)據(jù)類型、寄存器定義和函數(shù)原型。

3. MCU型號(hào)選擇,根據(jù)具體的芯片型號(hào)選擇正確的定義。

4. 外設(shè)時(shí)鐘使能宏定義,方便開啟或關(guān)閉外設(shè)時(shí)鐘。

5. 寄存器定義,定義MCU所有的內(nèi)核寄存器和外設(shè)寄存器結(jié)構(gòu)體。

6. 中斷編號(hào)定義,定義所有的中斷源所對(duì)應(yīng)的值。

7. 位帶操作宏定義,提供對(duì)寄存器位的設(shè)置、清除以及翻轉(zhuǎn)等操作。

8. FLASH和OTP操作函數(shù),提供FLASH讀、寫、擦除以及OTP讀寫的函數(shù)原型。

9. 復(fù)位和時(shí)鐘控制寄存器地址的定義以及函數(shù)原型。

10. GPIO通用IO口操作函數(shù)原型定義。

11. 中斷和事件管理函數(shù)原型定義,NVIC相關(guān)操作函數(shù)。

12. 其他外設(shè)(串口、SPI、I2CADC等)配置函數(shù)和外設(shè)特有的一些定義。所以,stm32f10x.h作為STM32F10x系列MCU的頂層頭文件,它包含了影響MCU所有外設(shè)和內(nèi)核的內(nèi)容,包括但不限于:寄存器定義、中斷定義、位帶操作、復(fù)位和時(shí)鐘配置、GPIO配置、串口配置等等。開發(fā)人員可以直接include這個(gè)頭文件,就可以使用里面定義的東西,非常方便。

system_stm32f10x.c文件主要包含STM32F10x系列MCU的系統(tǒng)時(shí)鐘配置函數(shù)。系統(tǒng)時(shí)鐘配置主要完成以下工作:

1. 根據(jù)外部晶振的頻率,配置PLL時(shí)鐘進(jìn)行倍頻,得到MCU內(nèi)核時(shí)鐘和AHB/APB總線時(shí)鐘。

2. 配置HSE(高速外部時(shí)鐘)作為系統(tǒng)時(shí)鐘,或者作為PLL的時(shí)鐘源。

3. 配置LSE(低速外部時(shí)鐘)作為RTC的時(shí)鐘源。

4. 選擇不同的預(yù)分頻因子,以滿足系統(tǒng)時(shí)鐘等于內(nèi)核時(shí)鐘的要求。

5. 配置各總線時(shí)鐘AHB, APB1和APB2的預(yù)分頻因子。

6. 根據(jù)配置的總線時(shí)鐘頻率,配置外設(shè)的時(shí)鐘。

7. 根據(jù)CPU工作頻率,設(shè)置Flash訪問(wèn)時(shí)間 FlashLatency。

所以,system_stm32f10x.c文件主要通過(guò)調(diào)用stm32f10x_clk.c和stm32f10x_rcc.c等文件里的函數(shù),來(lái)配置MCU的整個(gè)時(shí)鐘系統(tǒng),包括選擇PLL時(shí)鐘源、PLL倍頻系數(shù)、AHB/APB總線分頻系數(shù)以及外設(shè)時(shí)鐘使能等。這個(gè)文件實(shí)現(xiàn)了ClockConfiguration()函數(shù),該函數(shù)會(huì)在MCU啟動(dòng)時(shí)被startup_stm32f10x_xx.s的SystemInit()調(diào)用,從而完成MCU系統(tǒng)時(shí)鐘的初始化配置。

https://developer.arm.com/Processors/Cortex-M3
https://github.com/ARM-software/CMSIS-Drive


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • ARM
    ARM
    +關(guān)注

    關(guān)注

    134

    文章

    9009

    瀏覽量

    366101
  • Cortex
    +關(guān)注

    關(guān)注

    2

    文章

    201

    瀏覽量

    46389
  • 源碼
    +關(guān)注

    關(guān)注

    8

    文章

    630

    瀏覽量

    29074

原文標(biāo)題:Cortex-M3精通之路-1(匯編啟動(dòng)文件)

文章出處:【微信號(hào):TT1827652464,微信公眾號(hào):云深之無(wú)跡】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    適用于低功耗和無(wú)線通信距離要求較高應(yīng)用的智能通信模組-RF-SM-1077B1

    RF-SM-1077B1是RF-star推出的Sub-1G系列模塊,其芯片CC1310內(nèi)置高性能的ARM Cortex-M3 + ARM Cortex-M0雙核處理器,主MCU ARM
    的頭像 發(fā)表于 10-24 09:37 ?60次閱讀
    適用于低功耗和無(wú)線通信距離要求較高應(yīng)用的智能通信模組-RF-SM-1077B<b class='flag-5'>1</b>

    基于ARM Cortex-M3單片機(jī)研發(fā)的國(guó)產(chǎn)指紋芯片 - P1032BF1

    指紋芯片 - P1032BF1是一款基于ARM Cortex-M3的單片機(jī),專為Wi-Fi /藍(lán)牙通信控制而設(shè)計(jì);可應(yīng)用于智能鎖;支持大型程序代碼和擁有大型嵌入式SRAM,也可用于一般的MCU應(yīng)用。
    的頭像 發(fā)表于 07-10 09:22 ?463次閱讀
    基于ARM <b class='flag-5'>Cortex-M3</b>單片機(jī)研發(fā)的國(guó)產(chǎn)指紋芯片 - P1032BF<b class='flag-5'>1</b>

    求助,關(guān)于cortex-M3的壓棧問(wèn)題求解

    我們都知道cortex-m3中斷時(shí)是硬件自動(dòng)壓棧的,這樣可以減少中斷響應(yīng)和恢復(fù)時(shí)間。中斷硬件壓棧的寄存器為xPSR, PC, LR, R12, R0-R3,為什么其他寄存器不需要壓棧呢?
    發(fā)表于 04-28 08:18

    STM32F103VE添加DSP庫(kù)報(bào)錯(cuò)ld.exe: cannot find -l-mcpu=cortex-m3是什么原因呢?

    使用STM32F103VE芯片,在STM32cubeide里添加DSP庫(kù)后,編譯報(bào)錯(cuò)ld.exe: cannot find -l-mcpu=cortex-m3,請(qǐng)問(wèn)是什么原因呢?文件目錄以及配置如下
    發(fā)表于 03-15 08:14

    Cortex-M3芯片有哪些

    Cortex-M3芯片是一款基于ARM架構(gòu)的低功耗、高性能的嵌入式處理器。目前市面上有眾多廠商生產(chǎn)了基于Cortex-M3內(nèi)核的芯片,如意法半導(dǎo)體的STM32F系列、恩智浦半導(dǎo)體的LPC1800系列等。這些芯片廣泛應(yīng)用于工業(yè)控制、智能家居、物聯(lián)網(wǎng)等領(lǐng)域。
    的頭像 發(fā)表于 03-11 17:07 ?1420次閱讀

    Cortex-M3芯片怎么樣

    Cortex-M3芯片是一款高性能、低功耗的32位RISC處理器,特別適用于嵌入式系統(tǒng)和實(shí)時(shí)控制領(lǐng)域。其架構(gòu)采用哈佛結(jié)構(gòu),實(shí)現(xiàn)指令和數(shù)據(jù)存儲(chǔ)器的獨(dú)立訪問(wèn),提高了系統(tǒng)效率。Cortex-M3支持內(nèi)部和外部總線接口,提供了廣泛的外設(shè)連接和擴(kuò)展性支持。
    的頭像 發(fā)表于 03-08 16:00 ?1113次閱讀

    FM3 CY9BFx1xS/T系列Arm Cortex-M3微控制器Cypress

    和電動(dòng)工具配件到醫(yī)療器械、主要電器產(chǎn)品、數(shù)字消費(fèi)設(shè)備及辦公自動(dòng)化設(shè)備。FM3 CY9BFx1xS/T系列Arm Cortex-M3微控制器系統(tǒng)是高性能組,工作電壓范圍為 2.7V 至 5.5V。FM
    發(fā)表于 02-26 10:08

    強(qiáng)大的Arm? Cortex?-M3內(nèi)核(下)

    經(jīng)過(guò)前一期的芝識(shí)課堂,我們了解了東芝MCU產(chǎn)品所基于Arm Cortex-M3內(nèi)核的基本結(jié)構(gòu)和寄存器分配的細(xì)節(jié)。
    的頭像 發(fā)表于 01-25 09:25 ?957次閱讀
    強(qiáng)大的Arm? <b class='flag-5'>Cortex</b>?-<b class='flag-5'>M3</b>內(nèi)核(下)

    如何實(shí)現(xiàn)Cortex-M3與ADuC7061之間用IIC通訊?

    我想實(shí)現(xiàn)Cortex-M3與ADuC7061之間用IIC通訊,Cortex-M3用做主機(jī),ADuC7061用做從機(jī) 。我要實(shí)現(xiàn)收發(fā)數(shù)據(jù),ADuC7061應(yīng)該怎樣配置呢,思路是什么?
    發(fā)表于 01-15 06:13

    Cortex-M3 技術(shù)參考手冊(cè)

    電子發(fā)燒友網(wǎng)站提供《Cortex-M3 技術(shù)參考手冊(cè).pdf》資料免費(fèi)下載
    發(fā)表于 12-25 09:18 ?3次下載

    集成電源管理的超低功耗ARM Cortex-M3 MCU數(shù)據(jù)手冊(cè)

    電子發(fā)燒友網(wǎng)站提供《集成電源管理的超低功耗ARM Cortex-M3 MCU數(shù)據(jù)手冊(cè).pdf》資料免費(fèi)下載
    發(fā)表于 11-28 10:49 ?0次下載
    集成電源管理的超低功耗ARM <b class='flag-5'>Cortex-M3</b> MCU數(shù)據(jù)手冊(cè)

    基于Cortex-M3的全自動(dòng)焊接機(jī)設(shè)計(jì)

    電子發(fā)燒友網(wǎng)站提供《基于Cortex-M3的全自動(dòng)焊接機(jī)設(shè)計(jì).doc》資料免費(fèi)下載
    發(fā)表于 11-14 10:46 ?0次下載
    基于<b class='flag-5'>Cortex-M3</b>的全自動(dòng)焊接機(jī)設(shè)計(jì)

    基于CORTEX-M3的多機(jī)通信網(wǎng)絡(luò)的設(shè)計(jì)與實(shí)現(xiàn)

    電子發(fā)燒友網(wǎng)站提供《基于CORTEX-M3的多機(jī)通信網(wǎng)絡(luò)的設(shè)計(jì)與實(shí)現(xiàn).pdf》資料免費(fèi)下載
    發(fā)表于 11-08 09:47 ?0次下載
    基于<b class='flag-5'>CORTEX-M3</b>的多機(jī)通信網(wǎng)絡(luò)的設(shè)計(jì)與實(shí)現(xiàn)

    Cortex-M3咬尾中斷與晚到中斷基礎(chǔ)知識(shí)介紹

    Cortex-M3 內(nèi)核發(fā)生中斷時(shí),硬件會(huì)自動(dòng)將 XPSR、PC、LR、R12、R3、R2、R1 和 R0 這 8 個(gè)寄存器壓入棧,其余的 R4~R11、LR、XPSR 寄存器的備份則需要由 C 編譯器去做。
    的頭像 發(fā)表于 11-06 16:36 ?1276次閱讀
    <b class='flag-5'>Cortex-M3</b>咬尾中斷與晚到中斷基礎(chǔ)知識(shí)介紹

    深入 CortexM3 的 Faults異常

    深入 CortexM3 的 Faults異常
    的頭像 發(fā)表于 10-26 16:57 ?534次閱讀
    深入 <b class='flag-5'>Cortex</b>‐<b class='flag-5'>M3</b> 的 Faults異常