国产毛片a精品毛-国产毛片黄片-国产毛片久久国产-国产毛片久久精品-青娱乐极品在线-青娱乐精品

查看: 3048|回復: 0
打印 上一主題 下一主題

簡析STM32的啟動過程

[復制鏈接]
跳轉到指定樓層
樓主
發表于 2017-4-18 14:53:55 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
   當前的嵌入式應用程序開發過程里,C語言已成為了絕大部分場合的最佳選擇。如此一來main函數似乎成為了理所當然的起點——因為C程序往往從main函數開始執行。但一個經常會被忽略的問題是:微控制器(單片機)上電后,是如何尋找到并執行main函數的呢?很顯然微控制器無法從硬件上定位main函數的入口地址,因為使用C語言作為開發語言后,變量/函數的地址便由編譯器在編譯時自行分配,這樣一來main函數的入口地址在微控制器的內部存儲空間中不再是絕對不變的。相信讀者都可以回答這個問題,答案也許大同小異,但肯定都有個關鍵詞,叫“啟動文件”,用英文單詞來描述是“Bootloader”。

    無論性能高下,結構簡繁,價格貴賤,每一種微控制器(處理器)都必須有啟動文件,啟動文件的作用便是負責執行微控制器從“復位”到“開始執行main函數”中間這段時間(稱為啟動過程)所必須進行的工作。最為常見的51,AVRMSP430等微控制器當然也有對應啟動文件,但開發環境往往自動完整地提供了這個啟動文件,不需要開發人員再行干預啟動過程,只需要從main函數開始進行應用程序的設計即可。

關于“啟動模式”

    話題轉到STM32微控制器,無論是keil uvision4還是IAR EWARM開發環境,ST公司都提供了現成的直接可用的啟動文件,程序開發人員可以直接引用啟動文件后直接進行C應用程序的開發。這樣能大大減小開發人員從其它微控制器平臺跳轉至STM32平臺,也降低了適應STM32微控制器的難度(對于上一代ARM的當家花旦ARM9,啟動文件往往是第一道難啃卻又無法逾越的坎)。 相對于ARM上一代的主流ARM7/ARM9內核架構,新一代Cortex內核架構的啟動方式有了比較大的變化。ARM7/ARM9內核的控制器在復位后,CPU會從存儲空間的絕對地址0x000000取出第一條指令執行復位中斷服務程序的方式啟動,即固定了復位后的起始地址為0x000000(PC =0x000000)同時中斷向量表的位置并不是固定的。而Cortex-M3內核則正好相反,有3種情況:

    1、 通過boot引腳設置可以將中斷向量表定位于SRAM區,即起始地址為0x2000000,同時復位后PC指針位于0x2000000處;

    2、 通過boot引腳設置可以將中斷向量表定位于FLASH區,即起始地址為0x8000000,同時復位后PC指針位于0x8000000處;

    3、 通過boot引腳設置可以將中斷向量表定位于內置Bootloader區,本文不對這種情況做論述;

Cortex-M3內核規定,起始地址必須存放堆頂指針,而第二個地址則必須存放復位中斷入口向量地址,這樣在Cortex-M3內核復位后,會自動從起始地址的下一個32位空間取出復位中斷入口向量,跳轉執行復位中斷服務程序。對比ARM7/ARM9內核,Cortex-M3內核則是固定了中斷向量表的位置而起始地址是可變化的。

細說STM32的啟動過程

    下面就從ST的啟動文件說起,由于庫中的startup_stm32f10x_md.s與編譯環境有關,所以針對的是庫中的

STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\TrueSTUDIO路徑下的文件進行分析。

system_stm32f10x.c

    SystemInit():在"startup_stm32f10x_xx.s"文件中被調用,功能是設置系統時鐘(包括時鐘源,PLL系數,AHB/APBx的預分頻系數還有 flash的設定),這個函數會在系統復位之后首先被執行。文件中默認的一些設置:允許HSE(外部時鐘),FLASH(允許預取緩沖區,設置2個等待周 期),PLL系數為9,開啟PLL并選擇PLL輸出作為時鐘源(SYSCLK),后續設置SYSCLK = HCLK = APB2 = 72MHz,APB1 = HCLK/2 = 36MHz,HCLK即AHB的時鐘。

    SystemCoreClockUpdate():在系統時鐘HCLK變化的時候調用,以更新一個全局變量SystemCoreClock,這個變量可以為應用程序使用,必須保證正確。默認不調用這個函數,因為SystemCoreClock默認被設置為設定的頻率了(72MHz)

    另外,下面這種設置寄存器的方法值得借鑒,先用位名清除相應的位,再進行設置,例如:

#define  RCC_CFGR_PLLSRC                     ((uint32_t)0x00010000)        /*!< PLL entry clock source */

#define  RCC_CFGR_PLLXTPRE                   ((uint32_t)0x00020000)        /*!< HSE divider for PLL entry */

#define  RCC_CFGR_PLLMULL                    ((uint32_t)0x003C0000)        /*!< PLLMUL[3:0] bits (PLL multiplication factor) */

#define  RCC_CFGR_PLLSRC_HSE                ((uint32_t)0x00010000)        /*!< HSE clock selected as PLL entry clock source */

#define  RCC_CFGR_PLLMULL9                  ((uint32_t)0x001C0000)        /*!< PLL input clock*9 */

/*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */   

RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));

RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);

    startup_stm32f10x_md.s:(針對F103RBT6為中容量的產品)

    這個文件里面首先定義了復位中斷(復位入口矢量被硬件固定在地址0x0000_0004)的處理函數:Reset_Handler,它的作用就是將保存于flash中的初始化數據復制到sram中,調用上面說到的SystemInit來初始化時鐘,接著跳轉到main執行。

    接著定義了Default_Handler, 這個是作為其他所有中斷的默認處理函數,作用就是死循環,所以你假如開啟了某個中斷,請按照這里面的中斷函數名給它寫中斷處理函數,例如串口中斷處理函數名是 USART1_IRQHandler,你開了串口中斷,如果不重寫USART1_IRQHandler,就默認執行Default_Handler,死循環了。而如果你有重寫,那么中斷向量表中的處理函數的地址就會更新為你自己寫的那個函數的地址了。為什么會這樣呢?因為此文件的末尾用了類似這樣的語句:

   .weak    USART1_IRQHandler

   .thumb_set USART1_IRQHandler,Default_Handler

它給中斷處理函數提供了弱(weak)別名(Default_Handler),如果不重寫,中斷了默認執行Default_Handler,如果重寫了,因為是弱別名,所以會被你寫的同名函數覆蓋。

最后定義了一個中斷向量表的段(.section    .isr_vector,"a",%progbits),這個表將會放置在0x0000 0000那里,第二個字(0x0000 0004)是復位向量,復位之后從這地址所指的函數執行。

那么,如何保證.isr_vector這個段將放在flash的最開始(0x08000000)呢?這就需要鏈接腳本了,即我們用的那個stm32_flash.ld文件了,查看一下就知道了,里面先定義了堆棧的地址:

_estack

/* Highest address of the user mode stack */

_estack = 0x20005000;    /* end of 20K RAM */

接著定義了堆和棧的大小:

/* Generate a link error if heap and stack don't fit into RAM */

_Min_Heap_Size = 0;      /* required amount of heap  */

_Min_Stack_Size = 0x100; /* required amount of stack */

接著聲明了各個內存的區域(定義了幾個代表某個線性空間的名字,如下面的FLASH):

/* Specify the memory areas */

MEMORY

{

FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 128K  

RAM (xrw)       : ORIGIN = 0x20000000, LENGTH = 20K  

MEMORY_B1 (rx)  : ORIGIN = 0x60000000, LENGTH = 0K }

接著下面再介紹上面這三個名字里面都放了什么東西,首先是FLASH的:

/* Define output sections */

SECTIONS

{

/* The startup code goes first into FLASH */

.isr_vector :

{

   . = ALIGN(4);    KEEP(*(.isr_vector)) /* Startup code */

   . = ALIGN(4);  } >FLASH

/* The program code and other data goes into FLASH */

.text :

{

   . = ALIGN(4);    *(.text)           /* .text sections (code) */

   *(.text*)          /* .text* sections (code) */

   *(.rodata)         /* .rodata sections (constants, strings, etc.) */

   *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */

   *(.glue_7)         /* glue arm to thumb code */

   *(.glue_7t)        /* glue thumb to arm code */

   KEEP (*(.init))

   KEEP (*(.fini))

   . = ALIGN(4);    _etext = .;        /* define a global symbols at end of code */  

} >FLASH

    可以看到startup_stm32f10x_md.s中定義的這個段.isr_vector確實放在了最開頭的位置。

但是我們前面說復位向量在0x0000 0004,現在其地址是在flash中,所以地址是0x0800 0004,這個怎么回事呢?原來,stm32可以通過boot0、boot1引腳的配置將flash映射到0x0000 0000處。具體可參考stm32的用戶手冊2.4節。

    從主閃存存儲器啟動(BOOT0 = 0,BOOT1 = X):主閃存存儲器被映射到啟動空間(0x0000 0000),但仍然能夠在它原有的地址(0x0800 0000)訪問它,即閃存存儲器的內容可以在兩個地址區域訪問,0x0000 0000或0x0800 0000。

至此,整個STM32的啟動過程以及程序結構都可以比較清晰了。

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

關于我們  -  服務條款  -  使用指南  -  站點地圖  -  友情鏈接  -  聯系我們
電子工程網 © 版權所有   京ICP備16069177號 | 京公網安備11010502021702
快速回復 返回頂部 返回列表
主站蜘蛛池模板: 免费看男女做好爽好硬视频 | 国自产拍在线天天更新91 | 日韩成本大片35分钟免费播放 | 四虎一区二区三区 | 国内精品第一页 | 9191在线精品播放 | 国产第一页福利 | 久久久久九九 | 黄页在线观看 | 日韩欧美中文字幕在线播放 | 九九九九热精品视频 | 羞羞视频在线观看 | 成年人黄色免费网站 | 四虎在线最新永久免费 | 在线观看日韩 | 日本二区免费一片黄2019 | 欧美色婷婷天堂网站 | 天堂在线最新版资源www | 欧美成人免费全部观看在线看 | 五月天爱爱网 | 91精品国产91久久久久 | www.亚洲天堂 | 在线看片91 | 卡一卡二卡四卡免费观看 | 欧美日韩视频一区二区在线观看 | 激情久久久久久久久久久 | 日韩精品中文字幕在线观看 | 国产精品国产高清国产专区 | 国产色在线 | 2019天天做天天拍天天夜 | 青青青青草 | 亚洲视频在线观看网站 | 中文字幕在线观看亚洲日韩 | 国产99视频精品免视看9 | 欧美成在线视频 | 日韩精品特黄毛片免费看 | 男女羞羞视频在线观看 | 欧美一区二区三区激情视频 | 亚洲黄色在线观看网站 | 这里只有精品在线播放 | 国产一区日韩二区欧美三 |