嵌入式實(shí)戰(zhàn)場景題第二彈
滿滿干貨,每一道題都是經(jīng)典!??!
此部分不只包含面經(jīng)內(nèi)容,均是實(shí)戰(zhàn)類型不必全文背誦,有思路即可
后續(xù)收錄于專欄:http://fangfengwang8.cn/creation/manager/columnDetail/MJNwoM
1.4K空間其實(shí)可以存放很多int類型的數(shù)據(jù)的,第一個(gè)頁表項(xiàng)占了一個(gè)int類型的一個(gè)空間,他怎么找到第二級頁表的首地址?4K中存放了1024個(gè)地址,怎么找到某一個(gè)就是我想要找的那個(gè)二級頁?
整個(gè)問題圍繞的就是內(nèi)存管理的頁表,理解頁表結(jié)構(gòu)就可以回答這個(gè)問題.
知識點(diǎn):
1?.頁表存儲結(jié)構(gòu)
- 頁大小為4KB,每個(gè)頁表項(xiàng)占用4字節(jié),因此單個(gè)頁表最多可存儲 (4KB ÷ 4B = 1024)?12。
2.虛擬地址轉(zhuǎn)物理地址過程
虛擬地址被劃分為多個(gè)字段。例如:一級頁表索引(占10位,可尋址1024項(xiàng))二級頁表索引(同樣占10位)頁內(nèi)偏移(占12位,對應(yīng)4KB頁大?。?/p>
程序邏輯地址 → 分段轉(zhuǎn)換 → 虛擬地址(線性地址) → 分頁轉(zhuǎn)換 → 物理地址
三級頁表轉(zhuǎn)換方法:(兩步)
(1)邏輯地址轉(zhuǎn)線性地址:段起始地址+段內(nèi)偏移地址=線性地址
(2)線性地址轉(zhuǎn)物理地址:
每一個(gè)32位的線性地址被劃分為三部分:頁目錄索引(10位)、頁表索引(10位)、頁內(nèi)偏移(12位)
- 從cr3中取出進(jìn)程的頁目錄地址(操作系統(tǒng)調(diào)用進(jìn)程時(shí),這個(gè)地址被裝入寄存器中)
- 頁目錄地址 + 頁目錄索引 = 頁表地址
- 頁表地址 + 頁表索引 = 頁地址
- 頁地址 + 頁內(nèi)偏移 = 物理地址
舉例
頁目錄物理基地址存儲在CR3寄存器中(如0x1000
)
虛擬地址為0x12345678
(32位)
頁目錄索引=
0x48
,頁表索引=0x167
,頁內(nèi)偏移=0x678
?
1.定位一級頁表項(xiàng)
- 頁目錄索引=高10位:0x12345678 >> 22 = 0x48
- 計(jì)算條目地址:CR3基址 + 索引×4 = 0x1000 + 0x48×4 = 0x1120
- 讀取該地址內(nèi)容(如0x3000),此為二級頁表物理基地址?
2.?定位二級頁表項(xiàng)
- 頁表索引=中間10位:(0x12345678 >> 12) & 0x3FF = 0x167
- 計(jì)算條目地址:二級頁表基址 + 索引×4 = 0x3000 + 0x167×4 = 0x35BC
- 讀取該地址內(nèi)容(如0x8000),此為物理頁框基地址?
這里的頁面大小 是4kb(2^12),所以頁地址 = PFN × 頁面大小
頁地址 = PFN × 頁面大小 =
0x8000 <<12 = 0x8000000
3.計(jì)算最終物理地址
- 物理地址=頁地址 +偏移(
0x678
) =0x8000678?
2.中斷為什么不能用互斥鎖?一定要用鎖用什么鎖
知識點(diǎn):
互斥鎖的特點(diǎn)
一、基本使用過程
- 互斥鎖的加鎖、解鎖操作是原子性的,保證執(zhí)行過程中不會被其他線程中斷?。同一時(shí)刻僅有一個(gè)線程能持有鎖,其他線程必須等待鎖釋放后才能獲取?。
- 若鎖已被占用,請求線程會被掛起并進(jìn)入阻塞狀態(tài),不占用CPU資源,直到鎖被釋放后喚醒?。
- 通過對臨界區(qū)的互斥訪問,防止多個(gè)線程同時(shí)修改共享資源導(dǎo)致數(shù)據(jù)不一致?。
二、功能特性
- 鎖必須由持有線程主動釋放,其他線程不可強(qiáng)制剝奪或越權(quán)操作?。
- 某些互斥鎖允許同一線程多次獲取同一把鎖(需解鎖次數(shù)與加鎖次數(shù)匹配)?。
- 在實(shí)時(shí)操作系統(tǒng)中,當(dāng)?shù)蛢?yōu)先級線程持有鎖時(shí),可臨時(shí)繼承高優(yōu)先級線程的優(yōu)先級,減少優(yōu)先級反轉(zhuǎn)問題的影響?。
中斷的特性
- 中斷事件的發(fā)生不受程序控制,可隨時(shí)由硬件或軟件觸發(fā)(如外部設(shè)備請求或程序異常).
- 中斷機(jī)制使系統(tǒng)能夠快速響應(yīng)緊急事件(如硬件故障、數(shù)據(jù)到達(dá)),立即暫停當(dāng)前任務(wù)并處理中斷請求?
- 中斷的觸發(fā)與主程序執(zhí)行無關(guān),可在任意時(shí)間點(diǎn)打斷當(dāng)前流程,無需等待其他任務(wù)完成?。
答案:
由上邊的中斷和互斥鎖的特性可以看到,互斥鎖在獲取失敗時(shí)會使線程進(jìn)入休眠狀態(tài)(阻塞等待)而中斷處理程序必須保持非阻塞、快速響應(yīng)的特性,休眠會導(dǎo)致中斷無法正常返回并引發(fā)死鎖或系統(tǒng)崩潰?。
總結(jié)一下如下:
- 互斥鎖在獲取失敗時(shí)會觸發(fā)線程休眠(進(jìn)入阻塞狀態(tài)),但中斷處理程序運(yùn)行在中,沒有關(guān)聯(lián)的進(jìn)程或線程,無法保存休眠所需的執(zhí)行現(xiàn)場(如棧、調(diào)度狀態(tài)),強(qiáng)行休眠會導(dǎo)致內(nèi)核狀態(tài)不一致或系統(tǒng)崩潰?。
- 中斷處理程序必須快速完成并退出,休眠會破壞實(shí)時(shí)性要求,可能導(dǎo)致后續(xù)中斷無法響應(yīng)或引發(fā)死鎖?
- 互斥鎖要求“哪個(gè)線程申請,就由哪個(gè)線程釋放”,而中斷上下文不綁定任何線程,釋放鎖的操作可能無法完成,導(dǎo)致資源永久占用?
替代方案:自旋鎖
自旋鎖原理:通過忙等待(循環(huán)檢查鎖狀態(tài))避免線程休眠,確保中斷處理程序快速完成?。
只要中斷中不讓線程休眠就可以正常使用鎖。
3.如何通過代碼降低嵌入式系統(tǒng)功耗
1.低功耗模式(現(xiàn)有)
大部分的設(shè)備或者現(xiàn)有是有一些低功耗模式。
1.空閑時(shí)進(jìn)入WFI/WFE模式
在空閑任務(wù)中循環(huán)執(zhí)行__wfi()
或__wfe()
指令,關(guān)閉CPU時(shí)鐘以消除動態(tài)功耗?
void OS_Idle(void) { for (;;) { __wfi(); } }
2.?啟用Tickless模式
在操作系統(tǒng)中配置Tickless模式,通過動態(tài)調(diào)整系統(tǒng)時(shí)鐘中斷間隔,減少不必要的喚醒次數(shù)?25。例如FreeRTOS中可通過configUSE_TICKLESS_IDLE
宏實(shí)現(xiàn)。
2.關(guān)閉沒用的硬件資源損耗
?1.外設(shè)時(shí)鐘管理
在初始化階段僅開啟必要外設(shè)的時(shí)鐘,閑置外設(shè)通過寄存器操作關(guān)閉時(shí)鐘源?。例如STM32中調(diào)用__HAL_RCC_GPIOA_CLK_DISABLE()
。
?2.中斷驅(qū)動替代輪詢
避免使用while(NAND_FLASH_BUSY);
類阻塞代碼,改用硬件就緒信號觸發(fā)中斷,或在循環(huán)中添加延遲(如OS_TASK_Delay_us(30)
)?。
4.STM32的啟動過程,如果從FLASH啟動,為什么是0x08000000?
我以STM32F103ZE的空間地址映射去看一下,可以看到0x08000000 是位于代碼區(qū)
首先我們要分清楚一個(gè)概念,那就是STM32 單片機(jī)跟arm的聯(lián)系,例如STM32系列大多數(shù)使用ARM的Cortex-M3的內(nèi)核,所以STM32也是基于ARM定下的規(guī)矩去運(yùn)行。
那么這里我們指導(dǎo)Cortex-M3定下的規(guī)矩是從0地址啟動,SMT32當(dāng)然不能破壞ARM定下的“規(guī)矩”,那為什么STM32還可以從0x08000000去啟動,講道理STM32不應(yīng)該按照Cortex M3的規(guī)矩從0開始啟動嗎,現(xiàn)在FLash 可是從0x08000000啟動。
那我們先了解一個(gè)概念什么是重映射。
什么是STM32的重映射
那么我們先看一下 STM32的自舉模式看一下這三種的區(qū)別。
可以從表上看出來,當(dāng)你用Flash啟動的時(shí)候,你的代碼段地址會映射到Flash區(qū)然后從Flash啟動。因?yàn)槲覀兤綍r(shí)用的最多的就是從Flash去啟動stm32 所以我這里以Flash舉例去看一下什么是重映射。
可以從下圖看到 如果 BOOT1 =X BOOT0=0 那么
實(shí)際上就是 從0x00000000-0x001FFFFF 運(yùn)行的時(shí)候 從 0x08000000-0x081FFFFF(1MB) 讀取代碼,這就是重映射,然后這樣就遵循了Cortex-M內(nèi)核的啟動規(guī)則。
提出問題:既然設(shè)置到0x0800 0000這么麻煩,為什么不直接使用0x0000 0000?
- 這是因?yàn)镾TM32不僅可以從內(nèi)部Flash啟動,還可以從系統(tǒng)存儲器(可以實(shí)現(xiàn)串口ISP,USB DFU等程序下載方式,這個(gè)程序是ST固化好的程序代碼)和從內(nèi)部SRAM啟動,
- 我們將內(nèi)部Flash安排到0x0000 0000顯然是不行的。這樣會導(dǎo)致系統(tǒng)存儲器或者內(nèi)部SRAM無法重映射到0x0000 0000了。
5.程序大小超出flash存儲,有什么優(yōu)化方法?
一、代碼層面優(yōu)化
優(yōu)化變量和一些數(shù)據(jù)結(jié)構(gòu)
- 盡可能選用最小數(shù)據(jù)類型(如uint
剩余60%內(nèi)容,訂閱專欄后可繼續(xù)查看/也可單篇購買
BG雙9,目前在某外企。打算把之前校招時(shí)做的筆記通過專欄發(fā)出來,本專欄適合于C/C++、嵌入式方向就業(yè)的同學(xué),本篇面經(jīng)總結(jié)數(shù)千篇面經(jīng)的知識集合,實(shí)時(shí)更新全網(wǎng)最新的嵌入式/C++最新內(nèi)容,囊括了C語言、C++、操作系統(tǒng)、計(jì)算機(jī)網(wǎng)絡(luò)、嵌入式、算法與數(shù)據(jù)結(jié)構(gòu)、數(shù)據(jù)庫等一系列知識點(diǎn),在我看來這些是求職者在面試中必須掌握的知識點(diǎn)。最后呢祝各位能找到自己合適的工作。