嵌入式面經(jīng)第五彈:Momenta、瑞晟、OPPO、VIVO
本篇涉及的所有問(wèn)題概要:大家可以試試在看參考答案前,提前嘗試解答,以便明確自身知識(shí)點(diǎn)的不足部分!
想進(jìn)大廠做嵌入式?想一次性拿下華為、博世、理想、韶音等20+公司的面試?這份超全嵌入式面經(jīng)就是你的制勝法寶!
提前模擬來(lái)練習(xí)這些問(wèn)題,面試不再慌!
剩下內(nèi)容都在????????????????????????????????????????????????????
嵌入式面經(jīng)第五彈:(嵌入式面經(jīng))第11章 20+公司面經(jīng)雜談(五):Momenta、瑞晟、OPPO、VIVO
1.中斷里面通??梢运邌幔瑸槭裁??
2.什么是棧溢出,有什么方法檢測(cè)?
3.MCU 與 MPU 的區(qū)別是什么?
4.講一下Linux中斷分為上半部和下半部的原因?
5.如果給線程訪問(wèn)加鎖,是在驅(qū)動(dòng)層實(shí)現(xiàn)還是應(yīng)用層實(shí)現(xiàn)?
6.現(xiàn)在需要一個(gè)常量5來(lái)做一些運(yùn)算,你會(huì)使用const還是define?為什么?
7.項(xiàng)目里的ADC多通道采集是具體采用什么方式?
8.說(shuō)一下互斥鎖,自旋鎖的區(qū)別,在中斷中可以用哪個(gè)鎖?
9.怎么保證原子性操作?
10.專欄訂閱獎(jiǎng)勵(lì)(支持模仿)——個(gè)人創(chuàng)新點(diǎn)問(wèn)答:在你設(shè)計(jì)的FreeRTOS PLUS中提及修改任務(wù)控制塊,增加優(yōu)先級(jí)階段繼承屬性,來(lái)進(jìn)一步降低“優(yōu)先級(jí)反轉(zhuǎn)”的影響,展開(kāi)說(shuō)說(shuō)?
---------------------------------------------------------------------------------------------------
1.中斷里面通??梢运邌?,為什么?
在 Linux 內(nèi)核或嵌入式 RTOS(如 FreeRTOS)中,中斷處理程序(ISR) 不能進(jìn)入 睡眠(sleep/wait) 狀態(tài)。
主要有 兩大原因:
- 中斷上下文的限制(缺乏調(diào)度支持)
- 中斷設(shè)計(jì)的初衷——高實(shí)時(shí)性、不可阻塞
1. 中斷上下文限制,缺乏調(diào)度支持
?? 什么是中斷上下文?
- 內(nèi)核中的中斷處理程序不屬于某個(gè)特定進(jìn)程,而是獨(dú)立的執(zhí)行實(shí)體,沒(méi)有進(jìn)程調(diào)度信息。
- 沒(méi)有進(jìn)程的內(nèi)核棧、調(diào)度信息、文件描述符 等數(shù)據(jù)結(jié)構(gòu),無(wú)法像普通進(jìn)程一樣被調(diào)度。
- 缺少進(jìn)程控制塊(PCB),無(wú)法進(jìn)行任務(wù)切換。
? 具體分析
- 進(jìn)程上下文(Process Context) → 進(jìn)程有自己的 調(diào)度信息、內(nèi)核棧、寄存器保存,可以被掛起并恢復(fù)。
- 中斷上下文(Interrupt Context) → 沒(méi)有這些信息,如果 ISR 進(jìn)入睡眠,就無(wú)法被調(diào)度器重新喚醒。
?? 問(wèn)題:
- 進(jìn)入睡眠后 找不到中斷的上下文信息,喚醒后無(wú)法恢復(fù),系統(tǒng)可能會(huì)崩潰。
2. 中斷設(shè)計(jì)的初衷:高實(shí)時(shí)性,不可阻塞
?? 中斷的核心任務(wù)
- 中斷的目的是 快速響應(yīng)硬件事件,執(zhí)行最小化的任務(wù),然后盡快恢復(fù)系統(tǒng)運(yùn)行。
- 如果中斷中調(diào)用
sleep()
,會(huì)導(dǎo)致 CPU 掛起整個(gè)系統(tǒng),影響其他任務(wù)的執(zhí)行。
? 為什么要避免阻塞?
- 中斷優(yōu)先級(jí)比普通進(jìn)程高,如果中斷中進(jìn)入睡眠,會(huì)導(dǎo)致 CPU 被占用,進(jìn)程調(diào)度器無(wú)法調(diào)度其他任務(wù)。
- 高優(yōu)先級(jí)中斷可能會(huì)阻塞低優(yōu)先級(jí)進(jìn)程,影響系統(tǒng)性能。
3. 實(shí)例:為什么 ISR 不能調(diào)用 sleep()
?? 錯(cuò)誤示例
?? 在中斷處理中調(diào)用 sleep()
msleep()
會(huì)導(dǎo)致任務(wù)掛起,但中斷上下文沒(méi)有進(jìn)程調(diào)度信息,無(wú)法恢復(fù)。?? 正確做法:使用 workqueue
或 tasklet
在 中斷處理程序中,只做必要的工作,然后將復(fù)雜任務(wù)交給其他線程(如 workqueue
)。
? 解決方案:使用 workqueue
結(jié)論
? 使用 workqueue
或 tasklet
處理復(fù)雜任務(wù)
? 避免在 ISR 中使用 sleep()
,改為調(diào)度后臺(tái)線程處理
2.什么是棧溢出,有什么方法檢測(cè)?
1. 什么是棧溢出?
棧溢出(Stack Overflow)是指程序在運(yùn)行過(guò)程中,函數(shù)調(diào)用??臻g超出系統(tǒng)分配的范圍,導(dǎo)致程序崩潰或行為異常。
由于??臻g是有限的,如果程序需要的棧空間超過(guò)了系統(tǒng)分配的最大限制,就會(huì)發(fā)生棧溢出。
2. 棧溢出的常見(jiàn)原因
??(1)函數(shù)調(diào)用層數(shù)過(guò)深
無(wú)限遞歸/深度遞歸 會(huì)不斷地向棧中壓入新的棧幀,最終超過(guò)棧的最大空間,導(dǎo)致棧溢出。
? 示例:遞歸導(dǎo)致的棧溢出
由于 stack_overflow_function()
沒(méi)有終止條件,遞歸會(huì)無(wú)限增長(zhǎng),最終導(dǎo)致??臻g被耗盡,程序崩潰。
??(2)占用??臻g過(guò)大的局部變量
如果一個(gè)函數(shù)中的局部變量過(guò)大,尤其是大數(shù)組或結(jié)構(gòu)體,也可能導(dǎo)致棧溢出。
? 示例:局部變量過(guò)大導(dǎo)致棧溢出
?? 問(wèn)題:
- 局部數(shù)組
buffer
占用了 10MB 的??臻g,大于默認(rèn)棧空間,導(dǎo)致棧溢出。
3. 棧溢出的后果
4. 棧溢出的檢測(cè)方法
??(1)哨兵檢測(cè)(Stack Sentinel)
- 在棧的起始地址或結(jié)束地址放置特定的標(biāo)志值(哨兵值),然后在任務(wù)切換或關(guān)鍵點(diǎn)檢查這些值是否被修改。
- 如果哨兵值被改寫(xiě),說(shuō)明發(fā)生了棧溢出!
? 示例:哨兵檢測(cè)
- 只適用于單任務(wù)環(huán)境,如果多個(gè)任務(wù)共用棧空間,可能檢測(cè)不到問(wèn)題。
??(2)棧指針?lè)秶鷻z測(cè)
- 在任務(wù)切換時(shí)檢查
SP
(棧指針) 是否越界 - 如果
SP
低于分配的??臻g,說(shuō)明棧溢出
? 示例:FreeRTOS 棧溢出檢測(cè)
?? FreeRTOS 需要在 FreeRTOSConfig.h
啟用檢測(cè)
??(3)使用 ulTaskCheckFreeStackSpace()
監(jiān)測(cè)任務(wù)棧
? FreeRTOS 提供的棧檢查 API
?? 如果 freeStack
過(guò)?。ㄈ?<20),可能需要增加??臻g!
??(4)GCC 編譯器保護(hù)(-fstack-protector
)
- 啟用
-fstack-protector
選項(xiàng),可以在函數(shù)返回時(shí)檢測(cè)棧溢出 - 原理:編譯器在棧上存放"Canary" 保護(hù)值函數(shù)返回時(shí)檢查 Canary 是否被修改如果被篡改,則觸發(fā) stack smashing detected
? 啟用 -fstack-protector
gcc -fstack-protector -o test test.c
5. 如何預(yù)防棧溢出
? (1)避免深度遞歸
- 用循環(huán)代替遞歸
- 尾遞歸優(yōu)化
? (2)減少局部變量的??臻g
- 大數(shù)組使用
malloc()
在堆上分配 - 減少函數(shù)嵌套調(diào)用
? (3)合理分配棧大小
- 在 FreeRTOS/Linux 任務(wù)創(chuàng)建時(shí),合理設(shè)置
STACK_SIZE
- 監(jiān)測(cè)
uxTaskGetStackHighWaterMark()
確保棧足夠
? (4)使用 -fstack-protector
進(jìn)行編譯器保護(hù)
gcc -fstack-protector -o my_program my_program.c
? (5)啟用 configCHECK_FOR_STACK_OVERFLOW
結(jié)論
?? 防止棧溢出,需要合理分配棧大小、優(yōu)化代碼結(jié)構(gòu)、并啟用硬件和軟件監(jiān)測(cè)機(jī)制! ??
3.MCU 與 MPU 的區(qū)別是什么?
- MPU(Microprocessor Unit) 適用于復(fù)雜運(yùn)算的大型程序,通常需要外掛 RAM 和 ROM。
- MCU(Microcontroller Unit) 適用于中小型控制程序,內(nèi)部集成 RAM 和 ROM,無(wú)需外掛存儲(chǔ)器。
1. MCU(微控制器)
特點(diǎn):
- 集成度高:MCU 典型地將 CPU、RAM、ROM、GPIO、定時(shí)器、ADC、PWM、串口(UART/I2C/SPI) 等外設(shè)集成在一顆芯片內(nèi)。
- 成本低:由于 MCU 的所有組件都集成在同一芯片中,硬件設(shè)計(jì)成本較低。
- 低功耗:適用于低功耗設(shè)備(如 IoT 設(shè)備、工業(yè)控制、汽車電子)。
- 高實(shí)時(shí)性:一上電即可運(yùn)行,無(wú)需操作系統(tǒng),也可以跑 RTOS(如 FreeRTOS)。
- 典型應(yīng)用:
? 例子:
- STM32F4(Cortex-M4)
- AVR ATmega328(Arduino 用的芯片)
- GD32F3(國(guó)產(chǎn) MCU)
2. MPU(微處理器)
特點(diǎn):
- 高性能:MPU 適用于復(fù)雜計(jì)算,如 AI、圖像處理、多任務(wù)操作。
- 需要外掛 RAM 和 ROM:
運(yùn)行完整的操作系統(tǒng):
適用于需要 UI、多任務(wù)、復(fù)雜運(yùn)算的設(shè)備:
典型應(yīng)用:
? 例子:
- 樹(shù)莓派(Raspberry Pi)
- NXP i.MX 6/8(Cortex-A 系列)
- Allwinner H3/H5(電視盒子芯片)
- Rockchip RK3399(安卓平板/開(kāi)發(fā)板)
3. STM32(MCU) vs 樹(shù)莓派(MPU)
4. 為什么導(dǎo)彈、工業(yè)控制用 MCU?
- 高實(shí)時(shí)性:MCU 上電即運(yùn)行,而 MPU 需要加載操作系統(tǒng),延遲高。
- 功耗低:MCU 可以低功耗運(yùn)行,而 MPU 需要較大功耗運(yùn)行。
- 穩(wěn)定可靠:MCU 運(yùn)行裸機(jī)或 RTOS,沒(méi)有 OS 崩潰的風(fēng)險(xiǎn)。
總結(jié):
- MPU 適合需要操作系統(tǒng)、復(fù)雜運(yùn)算(如 AI、Linux 設(shè)備)
- MCU 適合實(shí)時(shí)控制、低功耗應(yīng)用(如 STM32 控制電機(jī)、傳感器)