分析
- 一、 暫存器、架構、作業流程
- 1、 暫存器架構
- 二 、總線與各個部件之間的關系(主要是I-Code Bus、D-Code Bus、System Bus)
- 體系結構:哈佛結構與馮諾依曼結構的區別
- 復位有三種啟動方式,從哪里開始啟動、啟動代碼的所在的位置
- 三、從存盤器映射來看stm32架構(記憶體與外設)
- 四、從CM3內核架構來看CPU流水線--分析Cortex-M3內核架構
- 五、 stm32(ARM CPU)與x86 CPU架構組成的異同點
- 六、stm32中指令、匯編語言、機器碼
- 七、指令和資料在stm32中存放的結構、堆疊大小及位置
- 各種符號在編譯后不存在記憶體中
一、 暫存器、架構、作業流程
1.這里以stm32的架構:cortex-m3(也即ARMv7)的暫存器的作用、在指令取,指令的譯碼,指令的執行在其中的作用以及是如何配合實作代碼的執行的
哈佛結構和馮諾依曼結構是如何體現的?
編譯后的代碼為什么分為code、堆、堆疊、bss、data、符號等部分,分別存盤在哪些地方?
首先看暫存器
暫存器分為暫存器組,和外設暫存器
暫存器組對用戶是不可見的(用戶不能直接操作),它是CPU處理資料時需要呼叫的
外設暫存器對用戶是可見的(用戶可以通過地址的映射來對暫存器操作,從而控制相應的外設動作)

上面的是暫存器組,是在Cortex-M3中用來臨時存放運算的資料或者指示程式運行的位置
1、 暫存器架構
參考官方Cortex-M3權威指南



二 、總線與各個部件之間的關系(主要是I-Code Bus、D-Code Bus、System Bus)



上圖所示的指令總線與資料總線與CM3內部的資料總線和資料總線不一樣,具體可以看下面Cortex-M3內部結構圖,而且上圖的兩個總線共用一個總線矩陣,就導致取指令和訪問資料不能同時訪問flash(在CM3里,指令和資料都是存放在flash中,部分資料存放在SRAM中,具體可以看指令和資料在stm32中存放的結構那一節),
而CM3外部總線部分是有芯片產商來決定,所以stm32的指令和資料總線是由意法半導體來設計制造的,具體架構如下圖所示,可以看到該架構,指令和資料總線并沒有共用一個總線矩陣,資料總線和系統總線是共用總線矩陣,從Cortex-M3的地址映射關系(從存盤器映射來看stm32架構(記憶體與外設)那一節和指令和資料在stm32中存放的結構那一節),可以知道資料總線是是訪問flash中的程式編譯好后生成的靜態資料(初始化的全域變數、 ),系統總線是訪問SRAM中程式運行程序中產生的動態資料(區域變數、)
因為靜態資料和動態資料不會同時訪問,所以不用設計成可以同時訪問的,也就可以共用一個總線矩陣
而讀取指令和訪問資料是可以同時進行的,所以就沒有共用一個總線矩陣,這里就體現了哈佛結構的特性,指令與資料可以同時訪問
下面這個是32官方參考手冊,才是我們真正使用stm32的MCU具備的系統結構

體系結構:哈佛結構與馮諾依曼結構的區別
上述I-code與D-code與flash的連接就體現了哈佛結構的特性:

CPU采用的是哈佛結構還是馮諾依曼結構?
復位有三種啟動方式,從哪里開始啟動、啟動代碼的所在的位置
復位后啟動的位置都是從記憶體地址為0x00000000的位置開始,如下圖:

但是根據boot引腳的硬體配置,有三種不同的硬體映射方式,將處于記憶體(Flash、system memery、SRAM)中不同地址(參考上面存盤器映射)的啟動代碼,映射到0x00000000這個位置;

一般都是將位于Flash的啟動代碼映射到0地址的位置,這個時候,取指令是通過ICode總線,取資料靠的是DCode和System 總線,通過不同的總線和總線矩陣,以及流水線的實作,可以實作指令和資料的同時訪問,這樣就體現了哈佛結構;
三、從存盤器映射來看stm32架構(記憶體與外設)
STM32架構相關
記憶體的映射就是資料和代碼實際存放的地址
外設映射的地址其實是控制該外設的暫存器的地址
整個架構說的就是處理核心、記憶體與外設暫存器它們的關系,是怎么通過各種總線連接起來的
如果取指令和訪問資料能同時進行,那么這種總線連接的關系,就可以稱之為哈佛結構;
存盤器地址映射如下:



以上三圖都是在 Cortex-M3權威指南 中定義的,說明該架構的這些存盤器映射是有arm定義好的,不是由芯片生產廠商來定義
下圖為 stm32中文參考手冊中定義的,這具體的就是有芯片生產廠家來定義的,主要介紹了code區、SRAM、片上外設(編程時主要就是用這里的地址來控制相應的模塊)

由上四圖可知,外設分為片上外設(USART、GPIO等模塊)、片外外設(這個需要自己擴展)、片內外設(中斷NVIC、路徑跟蹤TPIU等、除錯介面SWJ,它并不是除錯組件),這里的片內是相對于Cortex-M3,在它內部的外設叫片內外設;
下圖的附加除錯組件與再下一個圖的外部私有外設總線相連

Cortex-M3內部還有一個核心CM3Core,它周圍的外設叫片內外設(除錯系統(除錯組件)為片上外設); CM3Core和片內外設組成Cortex-M3;
Cortex-M3周圍的外設叫片上外設;
Cortex-M3和片上外設組成stm32芯片;
在stm32外部自己在通過PCB添加外設組件叫片外外設; 如下圖所示:
Cortex-M3模塊結構圖:
該圖里并不包含除錯組件,與外部私有外設總線相連的是除錯組件


上述兩張圖第一張是CM3Core和片內外設(不包括除錯組件),加上除錯組件,主要由ARM設計;
第二張圖除了CM3Core和片內外設組成的Cortex-M3,以及Trace controller(除錯組件),其它的是芯片制造公司設計制造的
抽象圖如下兩張圖所示:


四、從CM3內核架構來看CPU流水線–分析Cortex-M3內核架構
從上一節我們了解到Cortex-M3的內核CM3,它就相當于日常電腦的CPU,架構圖如下:Processor Core System那部分

上圖的Register Bank又可以分為以下:

ARM CPU的組成
ARM——Cortex系列體系結構

三級流水線


ARM Cortex-A8體系結構


流水線中出現的三個相關:
1、資料相關:是指令在流水bai線中du重疊執行時,當后繼指令需要用到zhi前面的指令產生的結果dao時發生的,
2、控制相關:是當流水線遇到轉移指令引起的,統計表明,轉移指令約占總指令的四分之一左右,比起資料相關,它會使流水線喪失更多的功能,
3.結構相關:多條指令進入流水線后在同一機器周期內爭用同一功能部件所發生的沖突,
使用五級指令流水的優點:
1.并行性更好
2.周期:機器周期可以設定地更短、時鐘周期也更短、主頻更高

具體為以下5級

從上面指令譯碼那個可以看到與下一節x86CPU組成不一樣的在于,x86CPU還有一個操作控制器OC,而arm相當于是在譯碼器包含了這個
五、 stm32(ARM CPU)與x86 CPU架構組成的異同點
x86CPU組成:
CPU的內部架構和作業原理

cpu架構一

這里的AC累加器、緩沖暫存器和ARM里的通用暫存器R0、R1是一個作用

ARM

六、stm32中指令、匯編語言、機器碼

CPU的內部架構和作業原理
根據運算元的地址是在暫存器還是在記憶體還是立即數,將這些資料傳輸型別分為以下幾種:
1、Cortex-CM3中的資料傳輸型別
1)、兩個暫存器間的傳輸資料,MOV
2)、暫存器與存盤器間傳輸資料,LDR、STR
3)、暫存器與特殊功能暫存器間傳輸資料,
4)、把一個立即數加載到暫存器,MOV
STM32學習之路入門篇之指令集及cortex——m3的存盤系統
ARM 反匯編基礎(六)(Thumb 匯編指令集)
可以通過命令列來匯編與反匯編

ARM-CPU原理,基于ARM的SOC講解

看下面這個例子:

LED0=0這條C指令編譯器把它轉換成了3潭訓編指令MOVS、LDR、STR,這三句匯編分別對應的機器碼就是2000、490B、6008,
圖中,0x08,,,是CODE地址,然后該地址開始的機器碼,最后就是這個機器對應的匯編陳述句,
F04F0001是對應匯編的機器碼,你不用關心它的長度,有興趣的可以去查匯編指令表,其中有對應機器碼的格式
上面的機器碼對三種運算元的尋址:暫存器(R0這些)、記憶體(flash等)、立即數
對立即數尋址就是確定該立即數的大小,

詳細參考如下文章:
ARM體系架構總結
首先我們分析下上面的例子:
490B LDR R1,[PC,#44]
490A LDR R1,[PC,#40]
這兩的機器碼為啥只差了1,而立即數差了4
這是因為立即數尋址是有8位圖決定的,不是直接映射數值的


我們可以看到它是將機器碼的0-4位乘以4得到最終的立即數
0xb=11,114=44
0xa=10,104=40

參考
ARM指令計算機器碼,自己歸納整理的ARM THUMB指令機器碼表
32位指令的尋址方式如下:
ARM立即尋址中有效立即數的計算

為什么要通過這種方式來尋址:
暫存器尋址可以直接控制暫存器,在機器碼中所需的位數不多,夠用
記憶體中尋址,如果是32位的那地址就有0-2的32次方,32位指令的話不夠用,但這里就可以采用【】的方式間接尋址
而立即數就沒有辦法通過直接和間接來,32位指令中間除去操作碼,剩下的位數根本覆寫不了0-2的32次方,所有采用了位圖加回圈右移的方式
詳細如下:
ARM指令中如何判斷一個立即數是有效立即數

七、指令和資料在stm32中存放的結構、堆疊大小及位置
這一節應該和**從存盤器映射來看stm32架構(記憶體與外設)**這一節結合來看

上面的代碼區(Block0)又細分為以下:

Flash=Code + RO-Data + RW-Data(.data);
SRAM= RW-data+ZI-data(.bss+heap+stack);
.bss:未初始化的全域變數
heap:申請的動態記憶體
stack:區域變數都是放在堆疊中
STM32記憶體管理以及堆和堆疊的理解
說說STM32的堆疊與記憶體
下面是附件代碼生成的map圖
==============================================================================
Memory Map of the image
Image Entry point : 0x08000131
Load Region LR_IROM1 (Base: 0x08000000, Size: 0x0000293c, Max: 0x00010000, ABSOLUTE)
Execution Region ER_IROM1 (Exec base: 0x08000000, Load base: 0x08000000, Size: 0x00002904, Max: 0x00010000, ABSOLUTE)
Exec Addr Load Addr Size Type Attr Idx E Section Name Object
0x08000000 0x08000000 0x00000130 Data RO 231 RESET startup_stm32f10x_hd.o
0x08000130 0x08000130 0x00000000 Code RO 3423 * .ARM.Collect$$$$00000000 mc_w.l(entry.o)
0x08000130 0x08000130 0x00000004 Code RO 3738 .ARM.Collect$$$$00000001 mc_w.l(entry2.o)
0x08000134 0x08000134 0x00000004 Code RO 3741 .ARM.Collect$$$$00000004 mc_w.l(entry5.o)
0x08000138 0x08000138 0x00000000 Code RO 3743 .ARM.Collect$$$$00000008 mc_w.l(entry7b.o)
0x08000138 0x08000138 0x00000000 Code RO 3745 .ARM.Collect$$$$0000000A mc_w.l(entry8b.o)
0x08000138 0x08000138 0x00000008 Code RO 3746 .ARM.Collect$$$$0000000B mc_w.l(entry9a.o)
0x08000140 0x08000140 0x00000000 Code RO 3748 .ARM.Collect$$$$0000000D mc_w.l(entry10a.o)
0x08000140 0x08000140 0x00000000 Code RO 3750 .ARM.Collect$$$$0000000F mc_w.l(entry11a.o)
0x08000140 0x08000140 0x00000004 Code RO 3739 .ARM.Collect$$$$00002712 mc_w.l(entry2.o)
0x08000144 0x08000144 0x00000024 Code RO 232 .text startup_stm32f10x_hd.o
0x08000168 0x08000168 0x00000062 Code RO 3426 .text mc_w.l(ldiv.o)
0x080001ca 0x080001ca 0x00000064 Code RO 3689 .text mf_w.l(fmul.o)
0x0800022e 0x0800022e 0x0000007c Code RO 3691 .text mf_w.l(fdiv.o)
0x080002aa 0x080002aa 0x0000014e Code RO 3693 .text mf_w.l(dadd.o)
0x080003f8 0x080003f8 0x000000e4 Code RO 3695 .text mf_w.l(dmul.o)
0x080004dc 0x080004dc 0x000000de Code RO 3697 .text mf_w.l(ddiv.o)
0x080005ba 0x080005ba 0x00000022 Code RO 3699 .text mf_w.l(dflti.o)
0x080005dc 0x080005dc 0x0000001a Code RO 3701 .text mf_w.l(dfltui.o)
0x080005f6 0x080005f6 0x00000028 Code RO 3703 .text mf_w.l(ffixui.o)
0x0800061e 0x0800061e 0x00000026 Code RO 3705 .text mf_w.l(f2d.o)
0x08000644 0x08000644 0x00000038 Code RO 3707 .text mf_w.l(d2f.o)
0x0800067c 0x0800067c 0x00000014 Code RO 3709 .text mf_w.l(cfrcmple.o)
0x08000690 0x08000690 0x00000062 Code RO 3755 .text mc_w.l(uldiv.o)
0x080006f2 0x080006f2 0x0000001e Code RO 3757 .text mc_w.l(llshl.o)
0x08000710 0x08000710 0x00000024 Code RO 3759 .text mc_w.l(llsshr.o)
0x08000734 0x08000734 0x00000000 Code RO 3768 .text mc_w.l(iusefp.o)
0x08000734 0x08000734 0x0000006e Code RO 3769 .text mf_w.l(fepilogue.o)
0x080007a2 0x080007a2 0x000000ba Code RO 3771 .text mf_w.l(depilogue.o)
0x0800085c 0x0800085c 0x0000002e Code RO 3773 .text mf_w.l(dscalb.o)
0x0800088a 0x0800088a 0x00000002 PAD
0x0800088c 0x0800088c 0x00000030 Code RO 3777 .text mf_w.l(cdrcmple.o)
0x080008bc 0x080008bc 0x00000024 Code RO 3779 .text mc_w.l(init.o)
0x080008e0 0x080008e0 0x00000020 Code RO 3781 .text mc_w.l(llushr.o)
0x08000900 0x08000900 0x000000a2 Code RO 3783 .text mf_w.l(dsqrt.o)
0x080009a2 0x080009a2 0x00000004 Code RO 144 i.BusFault_Handler stm32f10x_it.o
0x080009a6 0x080009a6 0x00000002 Code RO 145 i.DebugMon_Handler stm32f10x_it.o
0x080009a8 0x080009a8 0x00000116 Code RO 243 i.GPIO_Init stm32f10x_gpio.o
0x08000abe 0x08000abe 0x00000004 Code RO 251 i.GPIO_SetBits stm32f10x_gpio.o
0x08000ac2 0x08000ac2 0x00000004 Code RO 146 i.HardFault_Handler stm32f10x_it.o
0x08000ac6 0x08000ac6 0x00000002 PAD
0x08000ac8 0x08000ac8 0x00000038 Code RO 3164 i.IIC_Ack myiic.o
0x08000b00 0x08000b00 0x00000038 Code RO 3165 i.IIC_Init myiic.o
0x08000b38 0x08000b38 0x00000038 Code RO 3166 i.IIC_NAck myiic.o
0x08000b70 0x08000b70 0x00000058 Code RO 3167 i.IIC_Read_Byte myiic.o
0x08000bc8 0x08000bc8 0x00000060 Code RO 3168 i.IIC_Send_Byte myiic.o
0x08000c28 0x08000c28 0x00000038 Code RO 3169 i.IIC_Start myiic.o
0x08000c60 0x08000c60 0x00000034 Code RO 3170 i.IIC_Stop myiic.o
0x08000c94 0x08000c94 0x0000004c Code RO 3171 i.IIC_Wait_Ack myiic.o
0x08000ce0 0x08000ce0 0x00000050 Code RO 2906 i.LED_Init led.o
0x08000d30 0x08000d30 0x00000004 Code RO 147 i.MemManage_Handler stm32f10x_it.o
0x08000d34 0x08000d34 0x00000002 Code RO 148 i.NMI_Handler stm32f10x_it.o
0x08000d36 0x08000d36 0x00000002 PAD
0x08000d38 0x08000d38 0x00000070 Code RO 551 i.NVIC_Init misc.o
0x08000da8 0x08000da8 0x00000014 Code RO 552 i.NVIC_PriorityGroupConfig misc.o
0x08000dbc 0x08000dbc 0x00000002 Code RO 149 i.PendSV_Handler stm32f10x_it.o
0x08000dbe 0x08000dbe 0x00000002 PAD
0x08000dc0 0x08000dc0 0x00000020 Code RO 355 i.RCC_APB2PeriphClockCmd stm32f10x_rcc.o
0x08000de0 0x08000de0 0x000000d4 Code RO 363 i.RCC_GetClocksFreq stm32f10x_rcc.o
0x08000eb4 0x08000eb4 0x00000020 Code RO 3172 i.SDA_IN myiic.o
0x08000ed4 0x08000ed4 0x00000024 Code RO 3173 i.SDA_OUT myiic.o
0x08000ef8 0x08000ef8 0x00000002 Code RO 150 i.SVC_Handler stm32f10x_it.o
0x08000efa 0x08000efa 0x00000008 Code RO 2862 i.SetSysClock system_stm32f10x.o
0x08000f02 0x08000f02 0x00000002 PAD
0x08000f04 0x08000f04 0x000000e0 Code RO 2863 i.SetSysClockTo72 system_stm32f10x.o
0x08000fe4 0x08000fe4 0x00000028 Code RO 555 i.SysTick_CLKSourceConfig misc.o
0x0800100c 0x0800100c 0x00000002 Code RO 151 i.SysTick_Handler stm32f10x_it.o
0x0800100e 0x0800100e 0x00000002 PAD
0x08001010 0x08001010 0x0000003c Code RO 3320 i.SysTick_Init systick.o
0x0800104c 0x0800104c 0x00000060 Code RO 2865 i.SystemInit system_stm32f10x.o
0x080010ac 0x080010ac 0x0000003c Code RO 3349 i.USART1_IRQHandler usart.o
0x080010e8 0x080010e8 0x000000b0 Code RO 3350 i.USART1_Init usart.o
0x08001198 0x08001198 0x00000040 Code RO 3379 i.USART2_IRQHandler rs485.o
0x080011d8 0x080011d8 0x00000012 Code RO 1189 i.USART_ClearFlag stm32f10x_usart.o
0x080011ea 0x080011ea 0x00000018 Code RO 1193 i.USART_Cmd stm32f10x_usart.o
0x08001202 0x08001202 0x0000001a Code RO 1196 i.USART_GetFlagStatus stm32f10x_usart.o
0x0800121c 0x0800121c 0x00000054 Code RO 1197 i.USART_GetITStatus stm32f10x_usart.o
0x08001270 0x08001270 0x0000004a Code RO 1199 i.USART_ITConfig stm32f10x_usart.o
0x080012ba 0x080012ba 0x00000002 PAD
0x080012bc 0x080012bc 0x000000d8 Code RO 1200 i.USART_Init stm32f10x_usart.o
0x08001394 0x08001394 0x0000000a Code RO 1207 i.USART_ReceiveData stm32f10x_usart.o
0x0800139e 0x0800139e 0x00000008 Code RO 1210 i.USART_SendData stm32f10x_usart.o
0x080013a6 0x080013a6 0x00000004 Code RO 152 i.UsageFault_Handler stm32f10x_it.o
0x080013aa 0x080013aa 0x00000002 PAD
0x080013ac 0x080013ac 0x00000020 Code RO 3561 i.__0printf$5 mc_w.l(printf5.o)
0x080013cc 0x080013cc 0x00000028 Code RO 3725 i.__ARM_fpclassify m_ws.l(fpclassify.o)
0x080013f4 0x080013f4 0x000000aa Code RO 3727 i.__kernel_poly m_ws.l(poly.o)
0x0800149e 0x0800149e 0x00000002 PAD
0x080014a0 0x080014a0 0x00000010 Code RO 3711 i.__mathlib_dbl_divzero m_ws.l(dunder.o)
0x080014b0 0x080014b0 0x00000004 Code RO 3713 i.__mathlib_dbl_infnan2 m_ws.l(dunder.o)
0x080014b4 0x080014b4 0x0000000c Code RO 3714 i.__mathlib_dbl_invalid m_ws.l(dunder.o)
0x080014c0 0x080014c0 0x0000000e Code RO 3715 i.__mathlib_dbl_overflow m_ws.l(dunder.o)
0x080014ce 0x080014ce 0x00000002 PAD
0x080014d0 0x080014d0 0x00000010 Code RO 3717 i.__mathlib_dbl_underflow m_ws.l(dunder.o)
0x080014e0 0x080014e0 0x0000000e Code RO 3789 i.__scatterload_copy mc_w.l(handlers.o)
0x080014ee 0x080014ee 0x00000002 Code RO 3790 i.__scatterload_null mc_w.l(handlers.o)
0x080014f0 0x080014f0 0x0000000e Code RO 3791 i.__scatterload_zeroinit mc_w.l(handlers.o)
0x080014fe 0x080014fe 0x00000002 PAD
0x08001500 0x08001500 0x0000000c Code RO 3763 i.__set_errno mc_w.l(errno.o)
0x0800150c 0x0800150c 0x000002c0 Code RO 3568 i._printf_core mc_w.l(printf5.o)
0x080017cc 0x080017cc 0x000001b0 Code RO 3257 i.bmp280CompensateP bmp280.o
0x0800197c 0x0800197c 0x00000048 Code RO 3258 i.bmp280CompensateT bmp280.o
0x080019c4 0x080019c4 0x00000088 Code RO 3259 i.bmp280GetData bmp280.o
0x08001a4c 0x08001a4c 0x0000004c Code RO 3260 i.bmp280GetPressure bmp280.o
0x08001a98 0x08001a98 0x00000084 Code RO 3261 i.bmp280Init bmp280.o
0x08001b1c 0x08001b1c 0x0000007c Code RO 3262 i.bmp280PressureToAltitude bmp280.o
0x08001b98 0x08001b98 0x0000004c Code RO 3321 i.delay_ms systick.o
0x08001be4 0x08001be4 0x0000004c Code RO 3322 i.delay_us systick.o
0x08001c30 0x08001c30 0x00000024 Code RO 3351 i.fputc usart.o
0x08001c54 0x08001c54 0x00000060 Code RO 3174 i.iicDevRead myiic.o
0x08001cb4 0x08001cb4 0x00000040 Code RO 3175 i.iicDevReadByte myiic.o
0x08001cf4 0x08001cf4 0x00000030 Code RO 3177 i.iicDevWriteByte myiic.o
0x08001d24 0x08001d24 0x000000a0 Code RO 1 i.main main.o
0x08001dc4 0x08001dc4 0x000009d8 Code RO 3414 i.pow m_ws.l(pow.o)
0x0800279c 0x0800279c 0x00000006 Code RO 3263 i.presssureFilter bmp280.o
0x080027a2 0x080027a2 0x0000004c Code RO 3731 i.sqrt m_ws.l(sqrt.o)
0x080027ee 0x080027ee 0x00000002 PAD
0x080027f0 0x080027f0 0x00000088 Data RO 3415 .constdata m_ws.l(pow.o)
0x08002878 0x08002878 0x00000008 Data RO 3729 .constdata m_ws.l(qnan.o)
0x08002880 0x08002880 0x00000064 Data RO 2 .conststring main.o
0x080028e4 0x080028e4 0x00000020 Data RO 3787 Region$$Table anon$$obj.o
Execution Region RW_IRAM1 (Exec base: 0x20000000, Load base: 0x08002904, Size: 0x00000498, Max: 0x00005000, ABSOLUTE)
Exec Addr Load Addr Size Type Attr Idx E Section Name Object
0x20000000 0x08002904 0x00000014 Data RW 383 .data stm32f10x_rcc.o
0x20000014 0x08002918 0x00000014 Data RW 3265 .data bmp280.o
0x20000028 0x0800292c 0x00000004 Data RW 3323 .data systick.o
0x2000002c 0x08002930 0x00000001 Data RW 3381 .data rs485.o
0x2000002d 0x08002931 0x00000003 PAD
0x20000030 0x08002934 0x00000004 Data RW 3752 .data mc_w.l(stdout.o)
0x20000034 0x08002938 0x00000004 Data RW 3764 .data mc_w.l(errno.o)
0x20000038 - 0x0000001c Zero RW 3264 .bss bmp280.o
0x20000054 - 0x00000040 Zero RW 3380 .bss rs485.o
0x20000094 0x0800293c 0x00000004 PAD
0x20000098 - 0x00000400 Zero RW 229 STACK startup_stm32f10x_hd.o
==============================================================================
上面分為兩個部分:
1.Load Region
可以稱之為加載域,加載的指令在這里,初始化時將RW-data從flash中加載到SRAM中
2.Execution Region
可以稱之為執行域,在代碼運行程序中,生成的中間變數和全域變數的修改都是在這個區域進行的(SRAM)
在這一部分我們可以看到在最左邊執行地址的后面又Load Addr,這個地址就是當前地址上的資料是從哪里加載過來的,可以看到RW-data是從第一部分RO-data后面加載過來的
第二部分最后有STACK這個section,它是從0x20000098地址開始,然后在startup_stm32f10x_hd啟動檔案里定義了0x00000400大小的堆疊,所以在編譯完后堆疊指標sp就等于0x00000498
同樣可以在map檔案 全域符號那塊看到,如下圖

下面為區域符號STACK,為堆疊底指標

Code (inc. data) RO Data RW Data ZI Data Debug
9920 616 580 56 1120 272362 Grand Totals
9920 616 580 56 1120 272362 ELF Image Totals
9920 616 580 56 0 0 ROM Totals
==============================================================================
Total RO Size (Code + RO Data) 10500 ( 10.25kB)
Total RW Size (RW Data + ZI Data) 1176 ( 1.15kB)
Total ROM Size (Code + RO Data + RW Data) 10556 ( 10.31kB)
==============================================================================
可以看到上述RW Data + ZI Data其實就是編譯后加載到SRAM內的資料,轉換為16進制就是0x00000498
STM32 | map檔案詳解

下面看一下編程中實際字串在flash中的位置,字串屬于RO-Data型別,.conststring段
下面的printf列印的字串就屬于

在map檔案區域符號中找到該段的地址,如下:
因為該段屬于物件main.o物件,即在主函式中定義,所以選它,而不是最上面那個段

在keil中輸入該地址,找到該地址,

上圖框中前100個位元組就是printf函式里的字串,通過ascall表可以知道每個位元組翻譯過來加起來就代表了該字串
上面是找了RO-data的地址位置
下面找一下RW-data和ZI-data的位置,根據之前的描述,他們分別是全域初始化變數和靜態變數、未初始化的全域變數;
如下代碼:
#include <math.h>
#include "stdbool.h"
#include "SysTick.h"
#include "myiic.h"
#include "bmp280.h"
#include "usart.h"
/*bmp280 氣壓和溫度過采樣 作業模式*/
#define BMP280_PRESSURE_OSR (BMP280_OVERSAMP_8X)
#define BMP280_TEMPERATURE_OSR (BMP280_OVERSAMP_16X)
#define BMP280_MODE (BMP280_PRESSURE_OSR<<2|BMP280_TEMPERATURE_OSR<<5|BMP280_NORMAL_MODE)
typedef struct
{
u16 dig_T1; /* calibration T1 data */
s16 dig_T2; /* calibration T2 data */
s16 dig_T3; /* calibration T3 data */
u16 dig_P1; /* calibration P1 data */
s16 dig_P2; /* calibration P2 data */
s16 dig_P3; /* calibration P3 data */
s16 dig_P4; /* calibration P4 data */
s16 dig_P5; /* calibration P5 data */
s16 dig_P6; /* calibration P6 data */
s16 dig_P7; /* calibration P7 data */
s16 dig_P8; /* calibration P8 data */
s16 dig_P9; /* calibration P9 data */
s32 t_fine; /* calibration t_fine data */
} bmp280Calib;
bmp280Calib bmp280Cal;
static u8 bmp280ID=0;
static bool isInit=false;
static s32 bmp280RawPressure=0;
static s32 bmp280RawTemperature=0;
static void bmp280GetPressure(void);
static void presssureFilter(float* in,float* out);
static float bmp280PressureToAltitude(float* pressure/*, float* groundPressure, float* groundTemp*/);
bool bmp280Init(void)
{
if (isInit)
return true;
IIC_Init(); /*初始化I2C*/
delay_ms(20);
bmp280ID=iicDevReadByte(BMP280_ADDR,BMP280_CHIP_ID); /* 讀取bmp280 ID*/
if(bmp280ID==BMP280_DEFAULT_CHIP_ID)
printf("BMP280 ID IS: 0x%X\n",bmp280ID);
else
return false;
/* 讀取校準資料 */
iicDevRead(BMP280_ADDR,BMP280_TEMPERATURE_CALIB_DIG_T1_LSB_REG,24,(u8 *)&bmp280Cal);
iicDevWriteByte(BMP280_ADDR,BMP280_CTRL_MEAS_REG,BMP280_MODE);
iicDevWriteByte(BMP280_ADDR,BMP280_CONFIG_REG,5<<2); /*配置IIR濾波*/
isInit=true;
return true;
}
static void bmp280GetPressure(void)
{
u8 data[BMP280_DATA_FRAME_SIZE];
// read data from sensor
iicDevRead(BMP280_ADDR,BMP280_PRESSURE_MSB_REG,BMP280_DATA_FRAME_SIZE,data);
bmp280RawPressure=(s32)((((uint32_t)(data[0]))<<12)|(((uint32_t)(data[1]))<<4)|((uint32_t)data[2]>>4));
bmp280RawTemperature=(s32)((((uint32_t)(data[3]))<<12)|(((uint32_t)(data[4]))<<4)|((uint32_t)data[5]>>4));
}
// Returns temperature in DegC, resolution is 0.01 DegC. Output value of "5123" equals 51.23 DegC
// t_fine carries fine temperature as global value
static s32 bmp280CompensateT(s32 adcT)
{
s32 var1,var2,T;
var1=((((adcT>>3)-((s32)bmp280Cal.dig_T1<<1)))*((s32)bmp280Cal.dig_T2))>>11;
var2=(((((adcT>>4)-((s32)bmp280Cal.dig_T1))*((adcT>>4)-((s32)bmp280Cal.dig_T1)))>>12)*((s32)bmp280Cal.dig_T3))>>14;
bmp280Cal.t_fine=var1+var2;
T=(bmp280Cal.t_fine*5+128)>>8;
return T;
}
// Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24 integer bits and 8 fractional bits).
// Output value of "24674867" represents 24674867/256 = 96386.2 Pa = 963.862 hPa
static uint32_t bmp280CompensateP(s32 adcP)
{
int64_t var1,var2,p;
var1=((int64_t)bmp280Cal.t_fine)-128000;
var2=var1*var1*(int64_t)bmp280Cal.dig_P6;
var2=var2+((var1*(int64_t)bmp280Cal.dig_P5)<<17);
var2=var2+(((int64_t)bmp280Cal.dig_P4)<<35);
var1=((var1*var1*(int64_t)bmp280Cal.dig_P3)>>8)+((var1*(int64_t)bmp280Cal.dig_P2)<<12);
var1=(((((int64_t)1)<<47)+var1))*((int64_t)bmp280Cal.dig_P1)>>33;
if (var1==0)
return 0;
p=1048576-adcP;
p=(((p<<31)-var2)*3125)/var1;
var1=(((int64_t)bmp280Cal.dig_P9)*(p>>13)*(p>>13))>>25;
var2=(((int64_t)bmp280Cal.dig_P8)*p)>>19;
p=((p+var1+var2)>>8)+(((int64_t)bmp280Cal.dig_P7)<<4);
return(uint32_t)p;
}
#define FILTER_NUM 5
#define FILTER_A 0.1f
/*限幅平均濾波法*/
static void presssureFilter(float* in,float* out)
{
*out=*in;
}
void bmp280GetData(float* pressure,float* temperature,float* asl)
{
static float t;
static float p;
bmp280GetPressure();
t=bmp280CompensateT(bmp280RawTemperature)/100.0;
p=bmp280CompensateP(bmp280RawPressure)/25600.0;
*temperature=(float)t; /*單位度*/
presssureFilter(&p,pressure); /*濾波后平均出壓力單位hPa*/
*asl=bmp280PressureToAltitude(pressure); /*轉換成海拔*/
}
#define CONST_PF 0.1902630958 //(1/5.25588f) Pressure factor
#define FIX_TEMP 25 // Fixed Temperature. ASL is a function of pressure and temperature, but as the temperature changes so much (blow a little towards the flie and watch it drop 5 degrees) it corrupts the ASL estimates.
// TLDR: Adjusting for temp changes does more harm than good.
/*
* Converts pressure to altitude above sea level (ASL) in meters
*/
static float bmp280PressureToAltitude(float* pressure/*, float* groundPressure, float* groundTemp*/)
{
if (*pressure>0)
{
return((pow((1015.7f/ *pressure),CONST_PF)-1.0f)*(FIX_TEMP+273.15f))/0.0065f;
}
else
{
return 0;
}
}
其中的全域初始化變數有bmp280ID、islnit、bmp280RawPressure、bmp280RawTemperature、t、p
未初始化全域變數有bmp280Cal
在在map檔案區域符號中找到該段的地址,如下:

首先在.data出就表明了該段的開始地址,該段總共有多大,其中我們看到資料只占了18位元組,而一共占了20位元組,還有兩位元組是pad,
然后在map檔案的全域符號區,找到全域未初始化變數如下:
一共有28位元組

通過上述分析我們知道該段代碼中一共占了20+28位元組:
在map檔案的映像組大小部分可以看到統計,如下:

各種符號在編譯后不存在記憶體中

C語言記憶體中是否存在一個區域,存盤著變數的符號,變數的型別和變數的首地址?
變數名和記憶體地址及符號表
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/301255.html
標籤:其他

