嵌入式軟體工程師筆試面試指南-ARM體系與架構
哈嘍,大家好。我終於回來了!19號剛提交完大論文,就被抓去出差了,折騰了整整一週,26號晚上,才回到學校。鴿了好久都沒更新幹貨了。今天更新一篇關於Arm的筆試面試題目,文章內容已同步更新在github。
硬體基礎
NAND FLASH 和NOR FLASH異同?
CPU,MPU,MCU,SOC,SOPC聯絡與差別?
什麼是交叉編譯?
為什麼需要交叉編譯?
描述一下嵌入式基於ROM的執行方式和基於RAM的執行方式有什麼區別?
ARM處理器
什麼是哈佛結構和馮諾依曼結構?
什麼是ARM流水線技術?
ARM有幾種工作模式?
Arm有多少32位暫存器?
Arm2440和6410有什麼區別?
ARM指令集分為幾類?
通用暫存器包括R0~R15,可以分為具體哪三類?
Arm處理器有幾種工作狀態?
ARM系統中,在函式呼叫的時候,引數是透過哪種方式傳遞的?
為什麼2440的記憶體起始地址是0x30000000?
ARM協處理器指令包括哪3類,請描述它們的功能。
什麼是PLL(鎖相環)?
中斷與異常
中斷與異常有何區別?
中斷與DMA有何區別?
中斷能不能睡眠,為什麼?下半部能不能睡眠?
中斷的響應執行流程是什麼?
當一個異常出現以後,ARM微處理器會執行哪幾步操作?
寫一箇中斷服務需要注意哪些?如果中斷產生之後要做比較多的事情你是怎麼做的?
為什麼FIQ比IRQ要快?
中斷和輪詢哪個效率高?怎樣決定是採用中斷方式還是採用輪詢方式去實現驅動?
通訊協議
什麼是非同步傳輸和同步傳輸?
RS232和RS485通訊介面有什麼區別?
SPI協議
IIC協議
程式設計
嵌人式程式設計中,什麼是大端?什麼是小端?
如何判斷計算機處理器是大端,還是小端?
如何進行大小端的轉換?
如何對絕對地址0x100000賦值?
github倉庫
微信
公眾號
ARM體系與架構
硬體基礎
NAND FLASH 和NOR FLASH異同?
不同點
類別
NOR
NAND
注意:nandflash和norflash的0地址是不衝突的,norflash佔用BANK地址,而nandflash不佔用BANK地址,它的0地址是內部的。
相同點
1
寫之前都要先擦除,因為寫操作只能使1->0,而擦除動作是為了把所有位都變1
CPU,MPU,MCU,SOC,SOPC聯絡與差別?
1。CPU(Central Processing Unit),是一臺計算機的
運算核心和控制核心
。CPU由運算器、控制器和暫存器及實現它們之間聯絡的資料、控制及狀態的匯流排構成。差不多所有的CPU的運作原理可分為四個階段:提取(Fetch)、解碼(Decode)、執行(Execute)和寫回(Writeback)。 CPU從儲存器或高速緩衝儲存器中取出指令,放入指令暫存器,並對指令譯碼,並執行指令。所謂的計算機的可程式設計性主要是指對CPU的程式設計。
2。MPU (Micro Processor Unit),叫
微處理器
(不是微控制器),通常代表一個
功能強大的CPU
(暫且理解為
增強版的CPU
吧),但不是為任何已有的特定計算目的而設計的晶片。這種晶片往往是個人計算機和高階工作站的核心CPU。最常見的微處理器是Motorola的68K系列和Intel的X86系列。
3。MCU(Micro Control Unit),叫微控制器,是指隨著大規模積體電路的出現及其發展,
將計算機的CPU、RAM、ROM、定時計數器和多種I/O介面整合在一片晶片上
,形成晶片級的晶片,
比如51,avr這些晶片,內部除了CPU外還有RAM,ROM,可以直接加簡單的外圍器件(電阻,電容)就可以執行程式碼了
,而MPU如x86,arm這些就不能直接放程式碼了,它只不過是增強版的CPU,所以得
新增RAM,ROM
。
MCU MPU 最主要的區別就睡能否直接執行程式碼。MCU有內部的RAM ROM,而MPU是增強版的CPU,需要新增外部RAM ROM才可以執行程式碼。
4。SOC(System on Chip),指的是片上系統,MCU只是
晶片級
的晶片,而
SOC是系統級的晶片
,它既MCU(51,avr)那樣有內建RAM,ROM同時又像MPU(arm)那樣強大的,不單單是放簡單的程式碼,可以放系統級的程式碼,也就是說
可以執行作業系統
(將就認為是MCU整合化與MPU強處理力各優點二合一)。
5。SOPC(System On a Programmable Chip)可程式設計片上系統(FPGA就是其中一種),上面4點的硬體配置是固化的,就是說51微控制器就是51微控制器,不能變為avr,而avr就是avr不是51微控制器,他們的硬體是一次性掩膜成型的,能改的就是軟體配置,說白點就是改程式碼,本來是跑流水燈的,改下程式碼,變成數碼管,而SOPC則是
硬體配置,軟體配置都可以修改
,軟體配置跟上面一樣,沒什麼好說的,至於硬體,是可以自己構建的也就是說這個晶片是自己構造出來的,
這顆晶片我們叫“白片”
,什麼晶片都不是,把
硬體配置資訊下載進去了,他就是相應的晶片了
,可以讓他變成51,也可以是avr,甚至arm,同時SOPC是在SOC基礎上來的,所以他也是系統級的晶片,所以記得當把他變成arm時還得加外圍ROM,RAM之類的,不然就是MPU了。
什麼是交叉編譯?
在一種計算機環境中執行的編譯程式,能編譯出在
另外一種環境
下執行的程式碼,我們就稱這種編譯器
支援交叉編譯
。這個
編譯過程
就叫交叉編譯。簡單地說,就是
在一個平臺上生成另一個平臺上的可執行程式碼
。
這裡需要注意的是所謂平臺,實際上包含兩個概念:體系結構(Architecture)、作業系統(OperatingSystem)。同一個體系結構可以執行不同的作業系統;同樣,同一個作業系統也可以在不同的體系結構上執行。舉例來說,我們常說的x86 Linux平臺實際上是Intel x86體系結構和Linux for x86作業系統的統稱;而x86 WinNT平臺實際上是Intel x86體系結構和Windows NT for x86作業系統的簡稱。
為什麼需要交叉編譯?
有時是因為目的平臺上不允許或不能夠安裝我們所需要的編譯器,而我們又需要這個編譯器的某些特徵;有時是因為目的平臺上的資源貧乏,無法執行我們所需要編譯器;有時又是因為目的平臺還沒有建立,連作業系統都沒有,根本談不上執行什麼編譯器。
描述一下嵌入式基於ROM的執行方式和基於RAM的執行方式有什麼區別?
基於RAM
需要把硬碟和其他介質的程式碼先載入到ram中,載入過程中一般有重定位的操作。
速度比基於ROM的快,可用RAM比基於ROM的少,因為所有的程式碼,資料都必須存放在RAM中。
基於ROM
速度較基於RAM的慢,因為會有一個把變數,部分程式碼等從儲存器(硬碟,flash)搬移到RAM的過程。
可用RAM資源比基於RAM的多;
ARM處理器
什麼是哈佛結構和馮諾依曼結構?
定義
馮諾依曼結構釆用指令和資料
統一編址
,使用
同條匯流排
傳輸,CPU讀取指令和資料的操作
無法重疊
。
哈佛結構釆用指令和資料
獨立編址
,使用
兩條獨立的匯流排
傳輸,CPU讀取指令和資料的操作
可以重疊
。
利弊
馮諾依曼結構主要用於通用計算機領域,需要對儲存器中的程式碼和資料頻繁的進行修改,統一編址有利於
節約資源
。
哈佛結構主要用於嵌入式計算機,程式固化在硬體中,有較高的可靠性、運算速度和較大的吞吐。
什麼是ARM流水線技術?
流水線技術通 過
多個功能部件並行工作
來縮短程式執行時間,提高處理器核的效率和吞吐率,從而成為微處理器設計中最為重要的技術之一。
ARM7
處理器核使用了典型
三級流水線的馮·諾伊曼結構
,
ARM9
系列則採用了基於
五級流水線的哈佛結構
。透過增加流水線級數簡化了流水線各級的邏輯,進一步提高了處理器的效能。
PC代表程式計數器,流水線使用三個階段,因此指令分為三個階段執行:1。取指(從儲存器裝載一條指令);2。譯碼(識別將要被執行的指令);3。執行(處理指令並將結果寫回暫存器)。而R15(PC)總是指向“正在取指”的指令,而不是指向“正在執行”的指令或正在“譯碼”的指令。一般來說,人們習慣性約定將“
正在執行的指令作為參考點
”,稱之為當前第一條指令,因此PC總是指向第三條指令。當ARM狀態時,每條指令為4位元組長,所以PC始終指向該指令地址加8位元組的地址,即:
PC值=當前程式執行位置+8
;
ARM指令是三級流水線,取指,譯指,執行,同時執行的,現在
PC指向的是正在取指的地址(下一條指令)
,那麼cpu正在譯指的指令地址是PC-4(假設在ARM狀態下,一個指令佔4個位元組),
cpu正在執行的指令地址是PC-8
,也就是說PC所指向的地址和現在所執行的指令地址相差8。
當突然發生中斷的時候,儲存的是PC的地址(PC-8+4 = PC-4 下一條指令的地址)
這樣你就知道了,如果返回的時候返回PC,那麼中間就有一個指令沒有執行,所以用
SUB pc lr-irq #4
。
ARM有幾種工作模式?
使用者模式(USR)
使用者模式是使用者程式的工作模式,它執行在作業系統的使用者態,它沒有許可權去操作其它硬體資源,只能執行處理自己的資料,也
不能切換到其它模式下
,要想
訪問硬體資源或切換到其它模式只能透過軟中斷或產生異常。
系統模式(SYS)
系統模式是特權模式,不受使用者模式的限制。使用者模式和系統模式共用一套暫存器,作業系統在該模式下可以方便的訪問使用者模式的暫存器,而且作業系統的
一些特權任務可以使用這個模式訪問一些受控的資源。
說明:使用者模式與系統模式兩者使用相同的暫存器,都沒有SPSR(Saved Program Statement Register,已儲存程式狀態暫存器),但系統模式比使用者模式有更高的許可權,可以訪問所有系統資源。
一般中斷模式(IRQ)
一般中斷模式也叫普通中斷模式,用於處理一般的中斷請求,通常在硬體產生中斷訊號之後自動進入該模式,該模式為特權模式,可以自由訪問系統硬體資源。
快速中斷模式(FIQ)
快速中斷模式是相對一般中斷模式而言的,它是用來處理對時間要求比較緊急的中斷請求,主要用於高速資料傳輸及通道處理中。(快中斷有許多(R8~R14)自己的專用暫存器,發生中斷時,使用自己的暫存器就避免了儲存和恢復某些暫存器。如果異常中斷處理程式中使用它自己的物理暫存器之外的其他暫存器,異常中斷處理程式必須儲存和恢復這些暫存器)
管理模式(SVC)
管理模式是
CPU上電後預設模式
,因此,在該模式下主要用來做
系統的初始化
,軟中斷處理也在該模式下。當用戶模式下的使用者程式請求使用硬體資源時,透過軟體中斷進入該模式。
說明:系統復位或開機、軟中斷時進入到SVC模式下。
終止模式(ABT)
: 中止模式用於支援虛擬記憶體或儲存器保護,當用戶程式訪問
非法地址
,
沒有許可權讀取的記憶體地址時
,會進入該模式,linux下程式設計時經常出現的segment fault通常都是在該模式下丟擲返回的。
未定義模式(UND)
: 未定義模式用於支援硬體協處理器的軟體模擬,CPU在指令的譯碼階段不能識別該指令操作時,會進入未定義模式。
除了使用者模式外,其它6種模式稱為特權模式。所謂特權模式,即具有如下權利:
a。 MRS(把狀態暫存器的內容放到通用暫存器);
b。 MSR(把通用暫存器的內容放到狀態暫存器中)。
由於狀態暫存器中的內容不能夠改變,因此,要先把內容複製到通用暫存器中,然後修改通用暫存器中的內容,再把通用暫存器中的內容複製給狀態暫存器中,即可完成“修改狀態暫存器”的任務。
剩下的六種模式中除去系統模式外,統稱為異常模式。
Arm有多少32位暫存器?
ARM處理器共有
37
個暫存器。它包含
31
個通用暫存器和
6
個狀態暫存器。
Arm2440和6410有什麼區別?
主頻不同。2440是400M的。6410是533/667M的;
處理器版本不一樣:2440是arm920T核心,6410是arm1176ZJF核心;
6410在影片處理方面比2440要強很多。內部影片解碼器,包括MPEG4等影片格式;
6410支援WMV9、xvid、mpeg4、h264等格式的硬解碼和編碼;
6410多和很多擴充套件介面比如:tv-out、CF卡和S-Video輸出等;
spi、串列埠、sd介面也比那兩個要豐富;
6410採用的是DDR記憶體控制器;2440採用的是SDRam記憶體控制器;
6410為雙匯流排架構,一路用於記憶體匯流排、一路用於Flash匯流排;
6410的啟動方式更加靈活:主要包括SD、Nand Flash、Nor Flash和OneFlash等裝置啟動;
6410的Nand Flash支援SLC和MLC兩種架構,從而大大擴大儲存空間;
6410為雙匯流排架構,一路用於記憶體匯流排、一路用於Flash匯流排;
6410具備8路DMA通道,包括LCD、UART、Camera等專用DMA通道;
6410還支援2D和3D的圖形加速;
ARM指令集分為幾類?
2類,分別為Thumb指令集,ARM指令集。ARM指令長度為32位,Thumb指令長度為16位。這種特點使得ARM既能執行16位指令,又能執行32位指令,從而增強了ARM核心的功能。
通用暫存器包括R0~R15,可以分為具體哪三類?
通用暫存器包括R0-R15,可以分為3類:
未分組暫存器R0-R7
在所有執行模式下,未分組暫存器都指向
同一個物理暫存器
,他們未被系統用作特殊的用途。因此在中斷或異常處理進行
異常模式轉換
時,由於不同的處理器執行模式均使用相同的物理暫存器,所以可能造成
暫存器中資料的破壞
。
分組暫存器R8-R14
對於分組暫存器,他們每次所訪問的物理暫存器都
與當前的處理器執行模式相關
。
R13常用作存放堆疊指標,使用者也可以使用其他暫存器存放堆疊指標,但在Thumb指令集下,某些指令強制要求使用R13存放堆疊指標。
R14稱為連結暫存器(LR,Link Register),當執行子程式時,R14可得到R15(PC)的備份,執行完子程式後,又將R14的值複製回PC,即使用R14儲存返回地址。
程式計數器PC(R15)
暫存器R15用作程式計數器(PC),在ARM狀態下,位[1:0]為0,位[31:2]用於儲存PC;在Thumb狀態下,位[0]為0,位[31:1]用於儲存PC。
Arm處理器有幾種工作狀態?
從程式設計的角度來看,ARM微處理器的工作狀態一般ARM和Thumb有兩種,並可在兩種狀態之間切換。
ARM狀態:此時處理器執行32位的字對齊ARM指令,絕大部分工作在此狀態。
Thumb狀態:此時處理器執行16位的半字對齊的Thumb指令。
ARM系統中,在函式呼叫的時候,引數是透過哪種方式傳遞的?
當引數小於等於4的時候是透過
r0-r3暫存器
來進行傳遞的,當引數大於4的時候是透過
壓棧
的方式進行傳遞。
為什麼2440的記憶體起始地址是0x30000000?
S3C2440處理器有八個固定的記憶體塊,只有兩個是可以作為ROM,SRAM和SDRAM等儲存器bank。具體如下圖所示。
ARM協處理器指令包括哪3類,請描述它們的功能。
ARM協處理器指令包括以下3類:
用於ARM處理器初始化ARM協處理器的資料處理操作。
用於ARM處理器的暫存器和ARM協處理器的暫存器間的資料傳送操作。
用於在ARM協處理器的暫存器和記憶體單元之間傳送資料。
什麼是PLL(鎖相環)?
簡單來說,輸入時鐘的存在是作為“參考源”。鎖相環不是為了單純產生同頻同相訊號,而是一般整合進某種“頻率綜合電路”,產生一個不同頻,但鎖相的訊號。
有點繞,打個比方:某參考晶振10Mhz,頻率綜合器A使用該參考源產生了900Mhz時鐘,而頻率綜合器B產生了1Ghz時鐘。雖然兩路頻率不同,但
由於使用的通一個參考源,他們倆仍然是同源訊號
。相反,如果不同源,那麼即便同頻他們也不可能一致,因為世界上沒有兩個鍾能做到完全一樣,總有微弱的頻差,導致相位飄移。在很多現實應用中有要求同源時鐘的場合,所以,鎖相環被廣泛應用。鎖相環的另外一項衍生應用是相干解調,可以自己查查相關資料。
中斷與異常
中斷與異常有何區別?
中斷是指
外部硬體
產生的一個電訊號從CPU的中斷引腳進入,打斷CPU的執行。
異常是指軟體執行過程中發生了一些
必須作出處理
的事件,CPU自動產生一個陷入來打斷CPU的執行。異常在處理的時候必須考慮與處理器的
時鐘同步
,實際上異常也稱為
同步中斷
,在處理器執行到因編譯錯誤而導致的錯誤指令時,或者在執行期間出現特殊錯誤,必須靠核心處理的時候,處理器就會產生一個異常。
中斷與DMA有何區別?
DMA
:是一種
無須CPU
的參與,就可以讓
外設與系統記憶體
之間進行
雙向資料傳輸
的硬體機制,使用DMA可以使系統CPU從實際的I/O資料傳輸過程中擺脫出來,從而大大提高系統的吞吐率。
中斷
:是指CPU在執行程式的過程中,出現了某些
突發事件
時,CPU必須
暫停執行
當前的程式,轉去
處理突發事件
,處理完畢後CPU又
返回
源程式被中斷的位置並繼續執行。
所以中斷和DMA的區別就是:
DMA不需CPU參與,而中斷是需要CPU參與的。
中斷能不能睡眠,為什麼?下半部能不能睡眠?
中斷處理的時候,不應該發生程序切換。因為在中斷上下文中,
唯一能打斷當前中斷handler的只有更高優先順序的中斷
,它
不會被程序打斷
。如果在中斷上下文中休眠,則
沒有辦法喚醒它
,因為所有的
wake_up_xxx都是針對某個程序而言的
,而在中斷上下文中,沒有程序的概念,沒有一個task_struct(這點對於softirq和tasklet一樣)。因此真的休眠了,比如呼叫了會導致阻塞的例程,核心幾乎肯定會死。
schedule()在切換程序時,
儲存當前的程序上下文
(CPU暫存器的值、程序的狀態以及堆疊中的內容),以便以後恢復此程序執行。中斷髮生後,核心會
先儲存當前被中斷的程序上下文
(在呼叫中斷處理程式後恢復)。
但在中斷處理程式裡,CPU暫存器的值肯定已經變化了(最重要的程式計數器PC、堆疊SP等)。如果此時因為睡眠或阻塞操作呼叫了schedule(),則儲存的程序上下文就不是當前的程序上下文了。所以,不可以在中斷處理程式中呼叫schedule()。
2。4核心中schedule()函式本身在進來的時候
判斷是否處於中斷上下文
:
if(unlikely(in_interrupt()))
BUG();
因此,強行呼叫schedule()的結果就是核心BUG,但看2。6。18的核心schedule()的實現卻沒有這句,改掉了。
中斷handler會使用被中斷的程序核心堆疊,但不會對它有任何影響,因為handler使用完後會完全清除它使用的那部分堆疊,恢復被中斷前的原貌。
處於
中斷上下文
時候,
核心是不可搶佔的
。因此,如果休眠,則核心一定掛起。
中斷的響應執行流程是什麼?
中斷的響應流程:cpu接受中斷->儲存中斷上下文跳轉到中斷處理歷程->執行中斷上半部->執行中斷下半部->恢復中斷上下文。
當一個異常出現以後,ARM微處理器會執行哪幾步操作?
將下一條指令的地址存入相應連線暫存器LR,以便程式在處理異常返回時能從正確的位置重新開始執行。若異常是從
ARM狀態
進入,則LR暫存器中儲存的是
下一條指令的地址
(當前PC+4或PC+8,與異常的型別有關);若異常是從
Thumb狀態
進入,則在LR暫存器中儲存
當前PC的偏移量
,這樣,異常處理程式就不需要確定異常是從何種狀態進入的。例如:在軟體中斷異常SWI,指令 MOV PC,R14_svc總是返回到下一條指令,不管SWI是在ARM狀態執行,還是在Thumb狀態執行。
將CPSR複製到相應的SPSR中。
根據異常型別,強制設定CPSR的執行模式位。
強制PC從相關的異常向量地址取下一條指令執行,從而跳轉到相應的異常處理程式處。
寫一箇中斷服務需要注意哪些?如果中斷產生之後要做比較多的事情你是怎麼做的?
寫一箇中斷服務程式要注意
快進快出
,在中斷服務程式裡面儘量
快速採集資訊
,包括硬體資訊,然後退出中斷,要做其它事情可以使用
工作佇列
或者
tasklet
方式。也就是中斷上半部和下半部。
中斷服務程式中
不能有阻塞操作
。應為中斷期間是完全佔用CPU的(即不存在核心排程),中斷被阻塞住,其他程序將無法操作。
中斷服務程式
注意返回值
,要用作業系統定義的宏做為返回值,而不是自己定義的。
如果要做的事情較多,應將這些任務放在後半段(tasklet,等待佇列等)處理。
為什麼FIQ比IRQ要快?
ARM的FIQ模式提供了
更多的banked暫存器
,
r8到r14還有SPSR
,而IRQ模式就沒有那麼多,R8,R9,R10,R11,R12對應的banked的暫存器就沒有,這就意味著在ARM的IRQ模式下,中斷處理程式
自己要儲存R8到R12這幾個暫存器
,然後
退出中斷處理時程式要恢復這幾個暫存器
,而FIQ模式由於這幾個暫存器都有banked暫存器,模式
切換時CPU自動儲存這些值到banked暫存器
,退出FIQ模式時自動恢復,所以這個過程FIQ比IRQ快。不要小看這幾個暫存器,ARM在編譯的時候,如果你FIQ中斷處理程式足夠用這幾個獨立的暫存器來運作,它就
不會進行通用暫存器的壓棧
,這樣也省了一些時間。
FIQ比IRQ有
更高優先順序
,如果FIQ和IRQ同時產生,那麼FIQ先處理。
在symbian系統裡,當CPU處於FIQ模式處理FIQ中斷的過程中,預取指令異常,未定義指令異常,軟體中斷全被禁止,所有的中斷被遮蔽。所以FIQ就會很快執行,不會被其他異常或者中斷打斷,所以它又比IRQ快了。而IRQ不一樣,當ARM處理IRQ模式處理IRQ中斷時,如果來了一個FIQ中斷請求,那正在執行的IRQ中斷處理程式會被搶斷,ARM切換到FIQ模式去執行這個FIQ,所以FIQ比IRQ快多了。
另外FIQ的入口地址是0x1c,IRQ的入口地址是0x18。寫過完整彙編系統的都比較明白這點的差別,18只能放一條指令,為了不與1C處的FIQ衝突,
這個地方只能跳轉
,而FIQ不一樣,1C以後沒有任何中斷向量表了,這樣
可以直接在1C處放FIQ的中斷處理程式
,由於跳轉的範圍限制,至少少了一條跳轉指令。
中斷和輪詢哪個效率高?怎樣決定是採用中斷方式還是採用輪詢方式去實現驅動?
中斷是CPU處於
被動狀態
下來接受裝置的訊號,而輪詢是
CPU主動去查詢
該裝置是否有請求。
凡事都是兩面性,所以,看效率不能簡單的說那個效率高。如果是請求裝置是一個
頻繁請求
cpu的裝置,或者有
大量資料
請求的網路裝置,那麼
輪詢
的效率是比中斷高。如果是一般裝置,並且該裝置請求cpu的
頻率比較低
,則用
中斷
效率要高一些。主要是看請求頻率。
通訊協議
什麼是非同步傳輸和同步傳輸?
非同步傳輸:是一種典型的基於位元組的輸入輸出,資料按每次一個位元組進行傳輸,其傳輸速度低。
同步傳輸:需要外界的時鐘訊號進行通訊,是把資料位元組組合起來一起傳送,這種組合稱之為幀,其傳輸速度比非同步傳輸快。
RS232和RS485通訊介面有什麼區別?
傳輸方式不同
。 RS232採取不平衡傳輸方式,即所謂
單端通訊
。 而RS485則採用平衡傳輸,即
差分傳輸方式
。
傳輸距離不同
。RS232適合本地裝置之間的通訊,傳輸距離一般
不超過20m
。而RS485的傳輸距離為
幾十米到上千米
。
裝置數量
。RS232 只允許
一對一通訊
,而RS485 介面在總線上是允許連線
多達128個收發器
。
連線方式
。RS232,規定
用電平表示資料
,因此線路就是
單線路的,用兩根線
才能達到
全雙工
的目的;而RS485, 使用
差分電平表示資料
,因此,必須用
兩根線
才能達到傳輸資料的基本要求,要實現
全雙工
,必需用
4根線
。
總結:從某種意義上,可以說,線路上存在的僅僅是電流,
RS232/RS485規定了這些電流在什麼樣的線路上流動和流動的樣式
。
SPI協議
SPI的應用
SPI(Serial Peripheral Interface)協議是由摩托羅拉公司提出的通訊協議,即
序列外圍裝置介面
,是一種
高速全雙工
的通訊匯流排。SPI匯流排系統是一種同步序列外設介面,它可以使MCU與各種外圍裝置以序列方式進行通訊以交換資訊。SPI匯流排可直接與各個廠家生產的多種標準外圍器件相連,包括FLASH、RAM、網路控制器、LCD顯示驅動器、A/D轉換器和MCU等。
介面
MOSI (Master Output, Slave Input)
主裝置輸出/從裝置輸入引腳。主機的資料從這條訊號線輸出,從機由這條訊號線讀入主機發送的資料,即這條線上資料的方向為主機到從機。
MISO(Master Input,, Slave Output)
主裝置輸入/從裝置輸出引腳。主機從這條訊號線讀入資料,從機的資料由這條訊號線輸出到主機,即在這條線上資料的方向為從機到主機。
SCLK (Serial Clock)
時鐘訊號線,用於通訊資料同步。它由通訊主機產生,決定了通訊的速率,不同的裝置支援的最高時鐘頻率不一樣,如 STM32 的 SPI 時鐘頻率最大為fpclk/2,兩個裝置之間通訊時,通訊速率受限於低速裝置。
SS( Slave Select)
從裝置選擇訊號線,常稱為片選訊號線,也稱為 NSS、 CS,以下用 NSS 表示。 當有多個 SPI 從裝置與 SPI 主機相連時,裝置的其它訊號線 SCK、MOSI 及 MISO 同時並聯到相同的 SPI 總線上,即無論有多少個從裝置,都共同只使用這 3 條匯流排;而每個從裝置都有獨立的這一條 NSS 訊號線,本訊號線獨佔主機的一個引腳,即有多少個從裝置,就有多少條片選訊號線。
I2C 協議中透過裝置地址來定址、選中總線上的某個裝置並與其進行通訊;而 SPI 協議中沒有裝置地址,它使用 NSS 訊號線來定址,當主機要選擇從裝置時,把該從裝置的 NSS 訊號線設定為低電平,該從裝置即被選中,即片選有效,接著主機開始與被選中的從裝置進行 SPI 通訊。所以SPI 通訊以 NSS 線置低電平為開始訊號,以 NSS 線被拉高作為結束訊號。
協議層
SPI 通訊裝置之間的常用連線方式見下圖:
SPI 通訊的通訊時序,見下圖:
通訊的起始和停止訊號
在圖中的標號1處,NSS 訊號線由高變低,是 SPI 通訊的起始訊號。 NSS 是每個從機各自獨佔的訊號線,當從機檢在自己的 NSS 線檢測到起始訊號後,就知道自己被主機選中了,開始準備與主機通訊。在圖中的標號處, NSS 訊號由低變高,是 SPI 通訊的停止訊號,表示本次通訊結束,從機的選中狀態被取消。
資料有效性
SPI 使用 MOSI 及 MISO 訊號線來傳輸資料,使用 SCK 訊號線進行資料同步。 MOSI及 MISO 資料線在 SCK 的每個時鐘週期傳輸一位資料,且資料輸入輸出是同時進行的。資料傳輸時, MSB 先行(高位先行)或 LSB(低位先行)先行並沒有作硬性規定,但要保證兩個 SPI 通訊裝置之間使用同樣的協定,一般都會採用上圖中的 MSB 先行(高位先行)模式。
觀察圖中的2345標號處, MOSI 及 MISO 的資料在 SCK 的上升沿期間變化輸出,在 SCK 的下降沿時被取樣。即在 SCK 的下降沿時刻, MOSI 及 MISO 的資料有效,高電平時表示資料“1”,為低電平時表示資料“0”。在其它時刻,資料無效, MOSI 及 MISO為下一次表示資料做準備。
SPI 每次資料傳輸可以 8 位或 16 位為單位,每次傳輸的單位數不受限制。
CPOL(時鐘極性)/CPHA(時鐘相位)及通訊模式
上面講述的圖中的時序只是 SPI 中的其中一種通訊模式, SPI 一共有四種通訊模式,它們的主要區別是:匯流排空閒時 SCK 的時鐘狀態以及資料取樣時刻。為方便說明,在此引入“時鐘極性CPOL”和“時鐘相位 CPHA”的概念。
時鐘極性 CPOL 是指 SPI 通訊裝置處於空閒狀態時, SCK 訊號線的電平訊號(即 SPI 通訊開始前、 NSS 線為高電平時 SCK 的狀態)。 CPOL=0 時, SCK 在空閒狀態時為低電平,CPOL=1 時,則相反。
時鐘相位 CPHA 是指資料的取樣的時刻,當 CPHA=0 時, MOSI 或 MISO 資料線上的訊號將會在 SCK 時鐘線的“奇數邊沿” 被取樣。當 CPHA=1 時,資料線在 SCK 的“偶數邊沿” 取樣。
IIC協議
簡介
IIC協議是由資料線SDA和時鐘SCL構成的序列匯流排,可傳送和接收資料,是一個多主機的
半雙工通訊方式
每個掛接在總線上的器件都有個
唯一的地址
。位速在標準模式下可達 100kbit/s,在快速模式下可達400kbit/s,在高速模式下可待3。4Mbit/s。
I2C匯流排系統結構,如下所示:
I2C時序介紹
1. 空閒狀態
當總線上的
SDA和SCL兩條訊號線同時處於高電平
,便是
空閒狀態
,如上面的硬體圖所示,當我們不傳輸資料時, SDA和SCL被上拉電阻拉高,即進入空閒狀態
2. 起始訊號
當
SCL為高
期間,
SDA由高到低的跳變
;便是匯流排的
啟動訊號
,
只能由主機發起
,且在空閒狀態下才能啟動該訊號,如下圖所示:
3. 停止訊號
當
SCL為高期間
,
SDA由低到高的跳變
;便是匯流排的**停止訊號,**表示資料已傳輸完成,如下圖所示:
4. 傳輸資料格式
當發了起始訊號後,就開始傳輸資料,傳輸的資料格式如下圖所示:
當
SCL為高電平時
,便會獲取SDA資料值,其中
SDA資料必須是穩定的
(若SDA不穩定就會變成起始/停止訊號)。
當
SCL為低電平時
,便是
SDA的電平變化狀態
。
若主從機在傳輸資料期間,需要完成其它功能(例如一箇中斷),可以主動
拉低SCL
,使I2C進入
等待狀態
,直到
處理結束再釋放SCL,資料傳輸會繼續
5. 應答訊號ACK
I2C總線上的資料都是以
8位資料(位元組)進行的,當傳送了8個數據後,傳送方會在第9個
時鐘脈衝期間
釋放SDA資料
,當接收方接收該位元組成功,便會輸出一個ACK應答訊號,當SDA為高電平,表示為非應答訊號NACK,當SDA為低電平,表示為
有效應答訊號ACK
PS:當主機為接收方時,收到最後一個位元組後,主機可以不傳送ACK,直接傳送停止訊號來結束傳輸
。
當從機為接收方時,沒有傳送ACK,則表示從機可能在忙其它事、或者不匹配地址訊號和不支援多主機發送,主機可以傳送停止訊號,再次傳送起始訊號啟動新的傳輸。
6. 完整的資料傳輸
如下圖所示,
傳送起始訊號
後,便傳送一個
8位的裝置地址
,其中
第8位是對裝置的讀寫標誌
,後面緊跟著的就是
資料
了,直到傳送停止訊號
終止
。
PS:當我們第一次是讀操作,然後想換成寫操作時,可以再次傳送一個起始訊號,然後傳送讀的裝置地址,不需要停止訊號便能實現不同的地址轉換。
IIC傳輸資料的格式
1.寫操作
剛開始主晶片要發出一個
start訊號
,然後發出一個(用來確定是往哪一個晶片寫資料),
方向
(讀/寫,0表示寫,1表示讀)。
迴應
(用來確定這個裝置是否存在),然後就可以
傳輸資料
,傳輸資料之後,要有一個
迴應訊號
(確定資料是否接受完成),然後再傳輸
下一個資料
。每傳輸一個數據,接受方都會有一個迴應訊號,資料
傳送完
之後,主晶片就會發送一個
停止訊號
。
白色背景:主→從。灰色背景:從→主。
2.讀操作
剛開始主晶片要發出一個
start訊號
,然後發出一個
裝置地址
(用來確定是從哪一個晶片讀取資料),
方向
(讀/寫,0表示寫,1表示讀)。
迴應
(用來確定這個裝置是否存在),然後就可以
傳輸資料
,傳輸資料之後,要有一個迴應訊號(確定資料是否接受完成),然後在傳輸
下一個資料
。每傳輸一個數據,接受方都會有一個
迴應訊號
,資料傳送完之後,主晶片就會發送一個
停止訊號
。
白色背景:主→從。灰色背景:從→主
程式設計
嵌人式程式設計中,什麼是大端?什麼是小端?
大端模式:低位位元組存在高地址上,高位位元組存在低地址上。
小端模式:高位位元組存在高地址上,低位位元組存在低地址上。
STM32屬於小端模式,簡單的說,比如u32 temp=0X12345678;假設temp地址在0X2000 0010。那麼在記憶體裡面,存放就變成了:
地址 | HEX |
0X2000 0010 | 78 56 43 12 |
因為是16進位制的,一個數為0。5位元組,所以 12 代表一個位元組 34 代表一個位元組。
釆用小端模式的CPU對運算元的存放方式是從低位元組到高位元組,而大端模式對運算元的存放方式是從高位元組到低位元組。例如,16位寬的數0x1234在小端模式CPU記憶體中的存放方式(假設從地址0x4000開始存放)見表1,而在大端模式CPU記憶體中的存放方式見表2。
表1 0x1234在小端CPU記憶體中的存放方式
記憶體地址
存放內容
表2 0x1234在大端CPU記憶體中的存放方式
記憶體地址
存放內容
32位寬的數0x12345678在小端模式CPU記憶體中的存放方式(假設從地址0x4000開始存放)見表3,而在大端模式CPU記憶體中的存放方式見表4。
表3 0x12345678在小端CPU記憶體中的存放方式
記憶體地址
存放內容
表4 0x12345678在大端CPU記憶體中的存放方式
記憶體地址
存放內容
以下程式為例:
#include
struct mybitfields
{
unsigned short a:4;
unsigned short b:5;
unsigned short c:7;
}test;
int main()
{
int i;
test。a = 2;
test。b = 3;
test。c = 0;
i =*((short*)&test);
printf(“%d\n”,i);
return 0;
}
程式的輸出結果為 50。
上例中, sizeof( test)=2,上例的宣告方式是把一個 short(也就是一塊16位記憶體)分成3部分,各部分的大小分別是4位、5位、7位,賦值語句
i*( short*)&test)
就是把上面的16位記憶體轉換成 short型別進行解釋。
變數a的二進位制表示為0000000000000010,取其低四位是0010。變數b的二進位制表示為0000000000000011,取其低五位是00011。變數c的二進位制表示為0000000000000000,取其低七位是0000000。
80x86機是小端(修改分割槽表時要注意)模式,微控制器一般為大端模式
。小端一般是低位位元組在高位位元組的前面,也就是低位在記憶體地址低的一端,可以這樣記(小端→低位→在前→與正常邏輯順序相反),所以合成後得到0000000000110010,即十進位制的50。
下面給出另外一個例子
#include
#include
#include
int main()
{
unsigned int uiVal_1 = 0x12345678;
unsigned int uiVal_2 = 0;
unsigned char aucVal[4] = {0x12,0x34,0x56,0x78};
unsigned short usVal_1 = 0;
unsigned short usVal_2 = 0;
memcpy(&uiVal_2,aucVal,sizeof(uiVal_2));
usVal_1 = (unsigned short)uiVal_1;//在這裡截斷,都取得的是低位
usVal_2 = (unsigned short)uiVal_2;//在這裡截斷
printf(“usVal_1:%x\n”,usVal_1);//在這裡又轉化回來
printf(“usVal_2:%x\n”,usVal_2);//在這裡又轉化回來
return 0;
}
小端模式是低地址存放低位元組,高地址存放高位元組,結構如下所示
78//低地址
56
34
12//高地址
在記憶體裡面測試機是小端,地址由小到大。
val1:78563412
riVal2:12345678
結果如下:
5678
3412
如何判斷計算機處理器是大端,還是小端?
#include
int checkCPU()
{
{
union w
{
int a;
char b;
}c;
c。a =1;
return(c。b == 1);
}
}
int main()
{
if(checkCPU())
printf(“小端\n”);
else
printf(“大端\n”);
return 0;
}
編者的處理器為ntel處理器,因為 Intel處理器一般都是小端模式,所以此時程式的輸出結果為:小端
上述程式碼中,如果處理器是大端,則返回0;如果處理器是小端,則返回1。聯合體 union的存放順序是所有成員都從低地址開始存放,如果能夠透過改程式碼知道CPU對記憶體是採用小端模式讀寫,還是採用大端模式讀寫,一定會令面試官刮目相看。
還可以透過指標地址來判斷,由於在32位計算機系統中, short佔兩個位元組,char佔1個位元組,所以可以採用如下做法實現該判斷。
#include
int checkCPU()
{
unsigned short usData = 0x1122;
unsigned char*pucData = (unsigned char*)&usData;
return (*pucData == 0x22);
}
int main()
{
if(checkCPU())
printf(“小端\n”);
else
printf(“大端\n”);
return 0;
}
程式輸出的結果為:小端
如何進行大小端的轉換?
int swapInt32(int intValue){
int temp = 0;
temp = ((intValue & 0x000000FF) <<24)|
((intValue & 0x0000FF00) <<8) |
((intValue & 0x00FF0000) >>8) |
((intValue & 0xFF000000) >>24);
return temp;
}
/*short型:*/
unsigned short swapShort16(unsigned short shortValue){
return ((shortValue & 0x00FF ) <<8) | ((shortValue & 0xFF00)>>8);
}
/*float型:*/
float swapFloat32(float floatValue){
typedef union SWAP_UNION{
float unionFloat;
int unionInt;
}SWAP_UNION;
SWAP_UNION swapUnion;
swapUnion。unionFloat = floatValue;
swapUnion。unionInt = swapInt32( swapUnion。unionInt);
return swapUnion。unionFloat;
}
/*double型換一種寫法,用一下指標,不然移位移死了……*/
void swapDouble64(unsigned char *pIn, unsigned char *pOut){
for( int i=0;i<8;i++)
pOut[7-i] = pIn[i];
}
int main()
{
int x = 0x12345678;
int y = swapInt32(x);
printf(“%x\r\n”,y);
return 0;
}
如何對絕對地址0x100000賦值?
(unsigned int*)0x100000 = 1234;
那麼要是想讓程式跳轉到絕對地址是0x100000去執行,應該怎麼做?
*((void (*)( ))0x100000 ) ( );
首先要將0x100000強制轉換成函式指標,即:
(void (*)())0x100000
然後再呼叫它:
*((void (*)())0x100000)();·
用typedef可以看得更直觀些:
typedef void(*)() voidFuncPtr;
*((voidFuncPtr)0x100000)();
聯絡作者
作者在準備秋招的過程中,憑藉這份資料,最後順利拿到了
oppo,小米,兆易創新,全志科技,海康威視
等十餘家家公司的offer。現將這部分資料分享出來,希望能對大家有幫助!
如果大家在網上看到了不錯的資料,或者在筆試面試中遇到了資料中沒有的知識點,大家可以關注
我的公眾號
聯絡我,我替大家整理。
資料如有錯誤或者不合適的地方,可以在github向我提交issues。由於精力有限,所以只會用心維護好
github和公眾號
兩個平臺。
資料中的勘誤也會同步更新在github中。
github倉庫
這份資料總共有七個部分,分別為:
C/C++
,
資料結構與演算法分析
,
Arm體系與架構
,
Linux驅動開發
,
作業系統
,
網路程式設計
,
名企筆試真題
。所有內容均會同步更新到github倉庫中。
點選跳轉
微信
掃描下方二維碼加我微信。微訊號:LinuxDriverDev。
公眾號
掃描下方二維碼,關注我的公眾號。
公眾號有近
2000G
的嵌入式學習影片和
10G
的電子書,均可以免費獲取!
哈嘍,大家好。我終於回來了!19號剛提交完大論文,就被抓去出差了,折騰了整整一週,26號晚上,才回到學校。鴿了好久都沒更新幹貨了。今天更新一篇關於Arm的筆試面試題目,文章內容已同步更新在github。
ARM體系與架構
硬體基礎
NAND FLASH 和NOR FLASH異同?
不同點
類別
NOR
NAND
注意:nandflash和norflash的0地址是不衝突的,norflash佔用BANK地址,而nandflash不佔用BANK地址,它的0地址是內部的。
相同點
1
寫之前都要先擦除,因為寫操作只能使1->0,而擦除動作是為了把所有位都變1
CPU,MPU,MCU,SOC,SOPC聯絡與差別?
1。CPU(Central Processing Unit),是一臺計算機的
運算核心和控制核心
。CPU由運算器、控制器和暫存器及實現它們之間聯絡的資料、控制及狀態的匯流排構成。差不多所有的CPU的運作原理可分為四個階段:提取(Fetch)、解碼(Decode)、執行(Execute)和寫回(Writeback)。 CPU從儲存器或高速緩衝儲存器中取出指令,放入指令暫存器,並對指令譯碼,並執行指令。所謂的計算機的可程式設計性主要是指對CPU的程式設計。
2。MPU (Micro Processor Unit),叫
微處理器
(不是微控制器),通常代表一個
功能強大的CPU
(暫且理解為
增強版的CPU
吧),但不是為任何已有的特定計算目的而設計的晶片。這種晶片往往是個人計算機和高階工作站的核心CPU。最常見的微處理器是Motorola的68K系列和Intel的X86系列。
3。MCU(Micro Control Unit),叫微控制器,是指隨著大規模積體電路的出現及其發展,
將計算機的CPU、RAM、ROM、定時計數器和多種I/O介面整合在一片晶片上
,形成晶片級的晶片,
比如51,avr這些晶片,內部除了CPU外還有RAM,ROM,可以直接加簡單的外圍器件(電阻,電容)就可以執行程式碼了
,而MPU如x86,arm這些就不能直接放程式碼了,它只不過是增強版的CPU,所以得
新增RAM,ROM
。
MCU MPU 最主要的區別就睡能否直接執行程式碼。MCU有內部的RAM ROM,而MPU是增強版的CPU,需要新增外部RAM ROM才可以執行程式碼。
4。SOC(System on Chip),指的是片上系統,MCU只是
晶片級
的晶片,而
SOC是系統級的晶片
,它既MCU(51,avr)那樣有內建RAM,ROM同時又像MPU(arm)那樣強大的,不單單是放簡單的程式碼,可以放系統級的程式碼,也就是說
可以執行作業系統
(將就認為是MCU整合化與MPU強處理力各優點二合一)。
5。SOPC(System On a Programmable Chip)可程式設計片上系統(FPGA就是其中一種),上面4點的硬體配置是固化的,就是說51微控制器就是51微控制器,不能變為avr,而avr就是avr不是51微控制器,他們的硬體是一次性掩膜成型的,能改的就是軟體配置,說白點就是改程式碼,本來是跑流水燈的,改下程式碼,變成數碼管,而SOPC則是
硬體配置,軟體配置都可以修改
,軟體配置跟上面一樣,沒什麼好說的,至於硬體,是可以自己構建的也就是說這個晶片是自己構造出來的,
這顆晶片我們叫“白片”
,什麼晶片都不是,把
硬體配置資訊下載進去了,他就是相應的晶片了
,可以讓他變成51,也可以是avr,甚至arm,同時SOPC是在SOC基礎上來的,所以他也是系統級的晶片,所以記得當把他變成arm時還得加外圍ROM,RAM之類的,不然就是MPU了。
什麼是交叉編譯?
在一種計算機環境中執行的編譯程式,能編譯出在
另外一種環境
下執行的程式碼,我們就稱這種編譯器
支援交叉編譯
。這個
編譯過程
就叫交叉編譯。簡單地說,就是
在一個平臺上生成另一個平臺上的可執行程式碼
。
這裡需要注意的是所謂平臺,實際上包含兩個概念:體系結構(Architecture)、作業系統(OperatingSystem)。同一個體系結構可以執行不同的作業系統;同樣,同一個作業系統也可以在不同的體系結構上執行。舉例來說,我們常說的x86 Linux平臺實際上是Intel x86體系結構和Linux for x86作業系統的統稱;而x86 WinNT平臺實際上是Intel x86體系結構和Windows NT for x86作業系統的簡稱。
為什麼需要交叉編譯?
有時是因為目的平臺上不允許或不能夠安裝我們所需要的編譯器,而我們又需要這個編譯器的某些特徵;有時是因為目的平臺上的資源貧乏,無法執行我們所需要編譯器;有時又是因為目的平臺還沒有建立,連作業系統都沒有,根本談不上執行什麼編譯器。
描述一下嵌入式基於ROM的執行方式和基於RAM的執行方式有什麼區別?
基於RAM
需要把硬碟和其他介質的程式碼先載入到ram中,載入過程中一般有重定位的操作。
速度比基於ROM的快,可用RAM比基於ROM的少,因為所有的程式碼,資料都必須存放在RAM中。
基於ROM
速度較基於RAM的慢,因為會有一個把變數,部分程式碼等從儲存器(硬碟,flash)搬移到RAM的過程。
可用RAM資源比基於RAM的多;
ARM處理器
什麼是哈佛結構和馮諾依曼結構?
定義
馮諾依曼結構釆用指令和資料
統一編址
,使用
同條匯流排
傳輸,CPU讀取指令和資料的操作
無法重疊
。
哈佛結構釆用指令和資料
獨立編址
,使用
兩條獨立的匯流排
傳輸,CPU讀取指令和資料的操作
可以重疊
。
利弊
馮諾依曼結構主要用於通用計算機領域,需要對儲存器中的程式碼和資料頻繁的進行修改,統一編址有利於
節約資源
。
哈佛結構主要用於嵌入式計算機,程式固化在硬體中,有較高的可靠性、運算速度和較大的吞吐。
什麼是ARM流水線技術?
流水線技術通 過
多個功能部件並行工作
來縮短程式執行時間,提高處理器核的效率和吞吐率,從而成為微處理器設計中最為重要的技術之一。
ARM7
處理器核使用了典型
三級流水線的馮·諾伊曼結構
,
ARM9
系列則採用了基於
五級流水線的哈佛結構
。透過增加流水線級數簡化了流水線各級的邏輯,進一步提高了處理器的效能。
PC代表程式計數器,流水線使用三個階段,因此指令分為三個階段執行:1。取指(從儲存器裝載一條指令);2。譯碼(識別將要被執行的指令);3。執行(處理指令並將結果寫回暫存器)。而R15(PC)總是指向“正在取指”的指令,而不是指向“正在執行”的指令或正在“譯碼”的指令。一般來說,人們習慣性約定將“
正在執行的指令作為參考點
”,稱之為當前第一條指令,因此PC總是指向第三條指令。當ARM狀態時,每條指令為4位元組長,所以PC始終指向該指令地址加8位元組的地址,即:
PC值=當前程式執行位置+8
;
ARM指令是三級流水線,取指,譯指,執行,同時執行的,現在
PC指向的是正在取指的地址(下一條指令)
,那麼cpu正在譯指的指令地址是PC-4(假設在ARM狀態下,一個指令佔4個位元組),
cpu正在執行的指令地址是PC-8
,也就是說PC所指向的地址和現在所執行的指令地址相差8。
當突然發生中斷的時候,儲存的是PC的地址(PC-8+4 = PC-4 下一條指令的地址)
這樣你就知道了,如果返回的時候返回PC,那麼中間就有一個指令沒有執行,所以用
SUB pc lr-irq #4
。
ARM有幾種工作模式?
使用者模式(USR)
使用者模式是使用者程式的工作模式,它執行在作業系統的使用者態,它沒有許可權去操作其它硬體資源,只能執行處理自己的資料,也
不能切換到其它模式下
,要想
訪問硬體資源或切換到其它模式只能透過軟中斷或產生異常。
系統模式(SYS)
系統模式是特權模式,不受使用者模式的限制。使用者模式和系統模式共用一套暫存器,作業系統在該模式下可以方便的訪問使用者模式的暫存器,而且作業系統的
一些特權任務可以使用這個模式訪問一些受控的資源。
說明:使用者模式與系統模式兩者使用相同的暫存器,都沒有SPSR(Saved Program Statement Register,已儲存程式狀態暫存器),但系統模式比使用者模式有更高的許可權,可以訪問所有系統資源。
一般中斷模式(IRQ)
一般中斷模式也叫普通中斷模式,用於處理一般的中斷請求,通常在硬體產生中斷訊號之後自動進入該模式,該模式為特權模式,可以自由訪問系統硬體資源。
快速中斷模式(FIQ)
快速中斷模式是相對一般中斷模式而言的,它是用來處理對時間要求比較緊急的中斷請求,主要用於高速資料傳輸及通道處理中。(快中斷有許多(R8~R14)自己的專用暫存器,發生中斷時,使用自己的暫存器就避免了儲存和恢復某些暫存器。如果異常中斷處理程式中使用它自己的物理暫存器之外的其他暫存器,異常中斷處理程式必須儲存和恢復這些暫存器)
管理模式(SVC)
管理模式是
CPU上電後預設模式
,因此,在該模式下主要用來做
系統的初始化
,軟中斷處理也在該模式下。當用戶模式下的使用者程式請求使用硬體資源時,透過軟體中斷進入該模式。
說明:系統復位或開機、軟中斷時進入到SVC模式下。
終止模式(ABT)
: 中止模式用於支援虛擬記憶體或儲存器保護,當用戶程式訪問
非法地址
,
沒有許可權讀取的記憶體地址時
,會進入該模式,linux下程式設計時經常出現的segment fault通常都是在該模式下丟擲返回的。
未定義模式(UND)
: 未定義模式用於支援硬體協處理器的軟體模擬,CPU在指令的譯碼階段不能識別該指令操作時,會進入未定義模式。
除了使用者模式外,其它6種模式稱為特權模式。所謂特權模式,即具有如下權利:
a。 MRS(把狀態暫存器的內容放到通用暫存器);
b。 MSR(把通用暫存器的內容放到狀態暫存器中)。
由於狀態暫存器中的內容不能夠改變,因此,要先把內容複製到通用暫存器中,然後修改通用暫存器中的內容,再把通用暫存器中的內容複製給狀態暫存器中,即可完成“修改狀態暫存器”的任務。
剩下的六種模式中除去系統模式外,統稱為異常模式。
Arm有多少32位暫存器?
ARM處理器共有
37
個暫存器。它包含
31
個通用暫存器和
6
個狀態暫存器。
Arm2440和6410有什麼區別?
主頻不同。2440是400M的。6410是533/667M的;
處理器版本不一樣:2440是arm920T核心,6410是arm1176ZJF核心;
6410在影片處理方面比2440要強很多。內部影片解碼器,包括MPEG4等影片格式;
6410支援WMV9、xvid、mpeg4、h264等格式的硬解碼和編碼;
6410多和很多擴充套件介面比如:tv-out、CF卡和S-Video輸出等;
spi、串列埠、sd介面也比那兩個要豐富;
6410採用的是DDR記憶體控制器;2440採用的是SDRam記憶體控制器;
6410為雙匯流排架構,一路用於記憶體匯流排、一路用於Flash匯流排;
6410的啟動方式更加靈活:主要包括SD、Nand Flash、Nor Flash和OneFlash等裝置啟動;
6410的Nand Flash支援SLC和MLC兩種架構,從而大大擴大儲存空間;
6410為雙匯流排架構,一路用於記憶體匯流排、一路用於Flash匯流排;
6410具備8路DMA通道,包括LCD、UART、Camera等專用DMA通道;
6410還支援2D和3D的圖形加速;
ARM指令集分為幾類?
2類,分別為Thumb指令集,ARM指令集。ARM指令長度為32位,Thumb指令長度為16位。這種特點使得ARM既能執行16位指令,又能執行32位指令,從而增強了ARM核心的功能。
通用暫存器包括R0~R15,可以分為具體哪三類?
通用暫存器包括R0-R15,可以分為3類:
未分組暫存器R0-R7
在所有執行模式下,未分組暫存器都指向
同一個物理暫存器
,他們未被系統用作特殊的用途。因此在中斷或異常處理進行
異常模式轉換
時,由於不同的處理器執行模式均使用相同的物理暫存器,所以可能造成
暫存器中資料的破壞
。
分組暫存器R8-R14
對於分組暫存器,他們每次所訪問的物理暫存器都
與當前的處理器執行模式相關
。
R13常用作存放堆疊指標,使用者也可以使用其他暫存器存放堆疊指標,但在Thumb指令集下,某些指令強制要求使用R13存放堆疊指標。
R14稱為連結暫存器(LR,Link Register),當執行子程式時,R14可得到R15(PC)的備份,執行完子程式後,又將R14的值複製回PC,即使用R14儲存返回地址。
程式計數器PC(R15)
暫存器R15用作程式計數器(PC),在ARM狀態下,位[1:0]為0,位[31:2]用於儲存PC;在Thumb狀態下,位[0]為0,位[31:1]用於儲存PC。
Arm處理器有幾種工作狀態?
從程式設計的角度來看,ARM微處理器的工作狀態一般ARM和Thumb有兩種,並可在兩種狀態之間切換。
ARM狀態:此時處理器執行32位的字對齊ARM指令,絕大部分工作在此狀態。
Thumb狀態:此時處理器執行16位的半字對齊的Thumb指令。
ARM系統中,在函式呼叫的時候,引數是透過哪種方式傳遞的?
當引數小於等於4的時候是透過
r0-r3暫存器
來進行傳遞的,當引數大於4的時候是透過
壓棧
的方式進行傳遞。
為什麼2440的記憶體起始地址是0x30000000?
S3C2440處理器有八個固定的記憶體塊,只有兩個是可以作為ROM,SRAM和SDRAM等儲存器bank。具體如下圖所示。
ARM協處理器指令包括哪3類,請描述它們的功能。
ARM協處理器指令包括以下3類:
用於ARM處理器初始化ARM協處理器的資料處理操作。
用於ARM處理器的暫存器和ARM協處理器的暫存器間的資料傳送操作。
用於在ARM協處理器的暫存器和記憶體單元之間傳送資料。
什麼是PLL(鎖相環)?
簡單來說,輸入時鐘的存在是作為“參考源”。鎖相環不是為了單純產生同頻同相訊號,而是一般整合進某種“頻率綜合電路”,產生一個不同頻,但鎖相的訊號。
有點繞,打個比方:某參考晶振10Mhz,頻率綜合器A使用該參考源產生了900Mhz時鐘,而頻率綜合器B產生了1Ghz時鐘。雖然兩路頻率不同,但
由於使用的通一個參考源,他們倆仍然是同源訊號
。相反,如果不同源,那麼即便同頻他們也不可能一致,因為世界上沒有兩個鍾能做到完全一樣,總有微弱的頻差,導致相位飄移。在很多現實應用中有要求同源時鐘的場合,所以,鎖相環被廣泛應用。鎖相環的另外一項衍生應用是相干解調,可以自己查查相關資料。
中斷與異常
中斷與異常有何區別?
中斷是指
外部硬體
產生的一個電訊號從CPU的中斷引腳進入,打斷CPU的執行。
異常是指軟體執行過程中發生了一些
必須作出處理
的事件,CPU自動產生一個陷入來打斷CPU的執行。異常在處理的時候必須考慮與處理器的
時鐘同步
,實際上異常也稱為
同步中斷
,在處理器執行到因編譯錯誤而導致的錯誤指令時,或者在執行期間出現特殊錯誤,必須靠核心處理的時候,處理器就會產生一個異常。
中斷與DMA有何區別?
DMA
:是一種
無須CPU
的參與,就可以讓
外設與系統記憶體
之間進行
雙向資料傳輸
的硬體機制,使用DMA可以使系統CPU從實際的I/O資料傳輸過程中擺脫出來,從而大大提高系統的吞吐率。
中斷
:是指CPU在執行程式的過程中,出現了某些
突發事件
時,CPU必須
暫停執行
當前的程式,轉去
處理突發事件
,處理完畢後CPU又
返回
源程式被中斷的位置並繼續執行。
所以中斷和DMA的區別就是:
DMA不需CPU參與,而中斷是需要CPU參與的。
中斷能不能睡眠,為什麼?下半部能不能睡眠?
中斷處理的時候,不應該發生程序切換。因為在中斷上下文中,
唯一能打斷當前中斷handler的只有更高優先順序的中斷
,它
不會被程序打斷
。如果在中斷上下文中休眠,則
沒有辦法喚醒它
,因為所有的
wake_up_xxx都是針對某個程序而言的
,而在中斷上下文中,沒有程序的概念,沒有一個task_struct(這點對於softirq和tasklet一樣)。因此真的休眠了,比如呼叫了會導致阻塞的例程,核心幾乎肯定會死。
schedule()在切換程序時,
儲存當前的程序上下文
(CPU暫存器的值、程序的狀態以及堆疊中的內容),以便以後恢復此程序執行。中斷髮生後,核心會
先儲存當前被中斷的程序上下文
(在呼叫中斷處理程式後恢復)。
但在中斷處理程式裡,CPU暫存器的值肯定已經變化了(最重要的程式計數器PC、堆疊SP等)。如果此時因為睡眠或阻塞操作呼叫了schedule(),則儲存的程序上下文就不是當前的程序上下文了。所以,不可以在中斷處理程式中呼叫schedule()。
2。4核心中schedule()函式本身在進來的時候
判斷是否處於中斷上下文
:
if(unlikely(in_interrupt()))
BUG();
因此,強行呼叫schedule()的結果就是核心BUG,但看2。6。18的核心schedule()的實現卻沒有這句,改掉了。
中斷handler會使用被中斷的程序核心堆疊,但不會對它有任何影響,因為handler使用完後會完全清除它使用的那部分堆疊,恢復被中斷前的原貌。
處於
中斷上下文
時候,
核心是不可搶佔的
。因此,如果休眠,則核心一定掛起。
中斷的響應執行流程是什麼?
中斷的響應流程:cpu接受中斷->儲存中斷上下文跳轉到中斷處理歷程->執行中斷上半部->執行中斷下半部->恢復中斷上下文。
當一個異常出現以後,ARM微處理器會執行哪幾步操作?
將下一條指令的地址存入相應連線暫存器LR,以便程式在處理異常返回時能從正確的位置重新開始執行。若異常是從
ARM狀態
進入,則LR暫存器中儲存的是
下一條指令的地址
(當前PC+4或PC+8,與異常的型別有關);若異常是從
Thumb狀態
進入,則在LR暫存器中儲存
當前PC的偏移量
,這樣,異常處理程式就不需要確定異常是從何種狀態進入的。例如:在軟體中斷異常SWI,指令 MOV PC,R14_svc總是返回到下一條指令,不管SWI是在ARM狀態執行,還是在Thumb狀態執行。
將CPSR複製到相應的SPSR中。
根據異常型別,強制設定CPSR的執行模式位。
強制PC從相關的異常向量地址取下一條指令執行,從而跳轉到相應的異常處理程式處。
寫一箇中斷服務需要注意哪些?如果中斷產生之後要做比較多的事情你是怎麼做的?
寫一箇中斷服務程式要注意
快進快出
,在中斷服務程式裡面儘量
快速採集資訊
,包括硬體資訊,然後退出中斷,要做其它事情可以使用
工作佇列
或者
tasklet
方式。也就是中斷上半部和下半部。
中斷服務程式中
不能有阻塞操作
。應為中斷期間是完全佔用CPU的(即不存在核心排程),中斷被阻塞住,其他程序將無法操作。
中斷服務程式
注意返回值
,要用作業系統定義的宏做為返回值,而不是自己定義的。
如果要做的事情較多,應將這些任務放在後半段(tasklet,等待佇列等)處理。
為什麼FIQ比IRQ要快?
ARM的FIQ模式提供了
更多的banked暫存器
,
r8到r14還有SPSR
,而IRQ模式就沒有那麼多,R8,R9,R10,R11,R12對應的banked的暫存器就沒有,這就意味著在ARM的IRQ模式下,中斷處理程式
自己要儲存R8到R12這幾個暫存器
,然後
退出中斷處理時程式要恢復這幾個暫存器
,而FIQ模式由於這幾個暫存器都有banked暫存器,模式
切換時CPU自動儲存這些值到banked暫存器
,退出FIQ模式時自動恢復,所以這個過程FIQ比IRQ快。不要小看這幾個暫存器,ARM在編譯的時候,如果你FIQ中斷處理程式足夠用這幾個獨立的暫存器來運作,它就
不會進行通用暫存器的壓棧
,這樣也省了一些時間。
FIQ比IRQ有
更高優先順序
,如果FIQ和IRQ同時產生,那麼FIQ先處理。
在symbian系統裡,當CPU處於FIQ模式處理FIQ中斷的過程中,預取指令異常,未定義指令異常,軟體中斷全被禁止,所有的中斷被遮蔽。所以FIQ就會很快執行,不會被其他異常或者中斷打斷,所以它又比IRQ快了。而IRQ不一樣,當ARM處理IRQ模式處理IRQ中斷時,如果來了一個FIQ中斷請求,那正在執行的IRQ中斷處理程式會被搶斷,ARM切換到FIQ模式去執行這個FIQ,所以FIQ比IRQ快多了。
另外FIQ的入口地址是0x1c,IRQ的入口地址是0x18。寫過完整彙編系統的都比較明白這點的差別,18只能放一條指令,為了不與1C處的FIQ衝突,
這個地方只能跳轉
,而FIQ不一樣,1C以後沒有任何中斷向量表了,這樣
可以直接在1C處放FIQ的中斷處理程式
,由於跳轉的範圍限制,至少少了一條跳轉指令。
中斷和輪詢哪個效率高?怎樣決定是採用中斷方式還是採用輪詢方式去實現驅動?
中斷是CPU處於
被動狀態
下來接受裝置的訊號,而輪詢是
CPU主動去查詢
該裝置是否有請求。
凡事都是兩面性,所以,看效率不能簡單的說那個效率高。如果是請求裝置是一個
頻繁請求
cpu的裝置,或者有
大量資料
請求的網路裝置,那麼
輪詢
的效率是比中斷高。如果是一般裝置,並且該裝置請求cpu的
頻率比較低
,則用
中斷
效率要高一些。主要是看請求頻率。
通訊協議
什麼是非同步傳輸和同步傳輸?
非同步傳輸:是一種典型的基於位元組的輸入輸出,資料按每次一個位元組進行傳輸,其傳輸速度低。
同步傳輸:需要外界的時鐘訊號進行通訊,是把資料位元組組合起來一起傳送,這種組合稱之為幀,其傳輸速度比非同步傳輸快。
RS232和RS485通訊介面有什麼區別?
傳輸方式不同
。 RS232採取不平衡傳輸方式,即所謂
單端通訊
。 而RS485則採用平衡傳輸,即
差分傳輸方式
。
傳輸距離不同
。RS232適合本地裝置之間的通訊,傳輸距離一般
不超過20m
。而RS485的傳輸距離為
幾十米到上千米
。
裝置數量
。RS232 只允許
一對一通訊
,而RS485 介面在總線上是允許連線
多達128個收發器
。
連線方式
。RS232,規定
用電平表示資料
,因此線路就是
單線路的,用兩根線
才能達到
全雙工
的目的;而RS485, 使用
差分電平表示資料
,因此,必須用
兩根線
才能達到傳輸資料的基本要求,要實現
全雙工
,必需用
4根線
。
總結:從某種意義上,可以說,線路上存在的僅僅是電流,
RS232/RS485規定了這些電流在什麼樣的線路上流動和流動的樣式
。
SPI協議
SPI的應用
SPI(Serial Peripheral Interface)協議是由摩托羅拉公司提出的通訊協議,即
序列外圍裝置介面
,是一種
高速全雙工
的通訊匯流排。SPI匯流排系統是一種同步序列外設介面,它可以使MCU與各種外圍裝置以序列方式進行通訊以交換資訊。SPI匯流排可直接與各個廠家生產的多種標準外圍器件相連,包括FLASH、RAM、網路控制器、LCD顯示驅動器、A/D轉換器和MCU等。
介面
MOSI (Master Output, Slave Input)
主裝置輸出/從裝置輸入引腳。主機的資料從這條訊號線輸出,從機由這條訊號線讀入主機發送的資料,即這條線上資料的方向為主機到從機。
MISO(Master Input,, Slave Output)
主裝置輸入/從裝置輸出引腳。主機從這條訊號線讀入資料,從機的資料由這條訊號線輸出到主機,即在這條線上資料的方向為從機到主機。
SCLK (Serial Clock)
時鐘訊號線,用於通訊資料同步。它由通訊主機產生,決定了通訊的速率,不同的裝置支援的最高時鐘頻率不一樣,如 STM32 的 SPI 時鐘頻率最大為fpclk/2,兩個裝置之間通訊時,通訊速率受限於低速裝置。
SS( Slave Select)
從裝置選擇訊號線,常稱為片選訊號線,也稱為 NSS、 CS,以下用 NSS 表示。 當有多個 SPI 從裝置與 SPI 主機相連時,裝置的其它訊號線 SCK、MOSI 及 MISO 同時並聯到相同的 SPI 總線上,即無論有多少個從裝置,都共同只使用這 3 條匯流排;而每個從裝置都有獨立的這一條 NSS 訊號線,本訊號線獨佔主機的一個引腳,即有多少個從裝置,就有多少條片選訊號線。
I2C 協議中透過裝置地址來定址、選中總線上的某個裝置並與其進行通訊;而 SPI 協議中沒有裝置地址,它使用 NSS 訊號線來定址,當主機要選擇從裝置時,把該從裝置的 NSS 訊號線設定為低電平,該從裝置即被選中,即片選有效,接著主機開始與被選中的從裝置進行 SPI 通訊。所以SPI 通訊以 NSS 線置低電平為開始訊號,以 NSS 線被拉高作為結束訊號。
協議層
SPI 通訊裝置之間的常用連線方式見下圖:
SPI 通訊的通訊時序,見下圖:
通訊的起始和停止訊號
在圖中的標號1處,NSS 訊號線由高變低,是 SPI 通訊的起始訊號。 NSS 是每個從機各自獨佔的訊號線,當從機檢在自己的 NSS 線檢測到起始訊號後,就知道自己被主機選中了,開始準備與主機通訊。在圖中的標號處, NSS 訊號由低變高,是 SPI 通訊的停止訊號,表示本次通訊結束,從機的選中狀態被取消。
資料有效性
SPI 使用 MOSI 及 MISO 訊號線來傳輸資料,使用 SCK 訊號線進行資料同步。 MOSI及 MISO 資料線在 SCK 的每個時鐘週期傳輸一位資料,且資料輸入輸出是同時進行的。資料傳輸時, MSB 先行(高位先行)或 LSB(低位先行)先行並沒有作硬性規定,但要保證兩個 SPI 通訊裝置之間使用同樣的協定,一般都會採用上圖中的 MSB 先行(高位先行)模式。
觀察圖中的2345標號處, MOSI 及 MISO 的資料在 SCK 的上升沿期間變化輸出,在 SCK 的下降沿時被取樣。即在 SCK 的下降沿時刻, MOSI 及 MISO 的資料有效,高電平時表示資料“1”,為低電平時表示資料“0”。在其它時刻,資料無效, MOSI 及 MISO為下一次表示資料做準備。
SPI 每次資料傳輸可以 8 位或 16 位為單位,每次傳輸的單位數不受限制。
CPOL(時鐘極性)/CPHA(時鐘相位)及通訊模式
上面講述的圖中的時序只是 SPI 中的其中一種通訊模式, SPI 一共有四種通訊模式,它們的主要區別是:匯流排空閒時 SCK 的時鐘狀態以及資料取樣時刻。為方便說明,在此引入“時鐘極性CPOL”和“時鐘相位 CPHA”的概念。
時鐘極性 CPOL 是指 SPI 通訊裝置處於空閒狀態時, SCK 訊號線的電平訊號(即 SPI 通訊開始前、 NSS 線為高電平時 SCK 的狀態)。 CPOL=0 時, SCK 在空閒狀態時為低電平,CPOL=1 時,則相反。
時鐘相位 CPHA 是指資料的取樣的時刻,當 CPHA=0 時, MOSI 或 MISO 資料線上的訊號將會在 SCK 時鐘線的“奇數邊沿” 被取樣。當 CPHA=1 時,資料線在 SCK 的“偶數邊沿” 取樣。
IIC協議
簡介
IIC協議是由資料線SDA和時鐘SCL構成的序列匯流排,可傳送和接收資料,是一個多主機的
半雙工通訊方式
每個掛接在總線上的器件都有個
唯一的地址
。位速在標準模式下可達 100kbit/s,在快速模式下可達400kbit/s,在高速模式下可待3。4Mbit/s。
I2C匯流排系統結構,如下所示:
I2C時序介紹
1. 空閒狀態
當總線上的
SDA和SCL兩條訊號線同時處於高電平
,便是
空閒狀態
,如上面的硬體圖所示,當我們不傳輸資料時, SDA和SCL被上拉電阻拉高,即進入空閒狀態
2. 起始訊號
當
SCL為高
期間,
SDA由高到低的跳變
;便是匯流排的
啟動訊號
,
只能由主機發起
,且在空閒狀態下才能啟動該訊號,如下圖所示:
3. 停止訊號
當
SCL為高期間
,
SDA由低到高的跳變
;便是匯流排的**停止訊號,**表示資料已傳輸完成,如下圖所示:
4. 傳輸資料格式
當發了起始訊號後,就開始傳輸資料,傳輸的資料格式如下圖所示:
當
SCL為高電平時
,便會獲取SDA資料值,其中
SDA資料必須是穩定的
(若SDA不穩定就會變成起始/停止訊號)。
當
SCL為低電平時
,便是
SDA的電平變化狀態
。
若主從機在傳輸資料期間,需要完成其它功能(例如一箇中斷),可以主動
拉低SCL
,使I2C進入
等待狀態
,直到
處理結束再釋放SCL,資料傳輸會繼續
5. 應答訊號ACK
I2C總線上的資料都是以
8位資料(位元組)進行的,當傳送了8個數據後,傳送方會在第9個
時鐘脈衝期間
釋放SDA資料
,當接收方接收該位元組成功,便會輸出一個ACK應答訊號,當SDA為高電平,表示為非應答訊號NACK,當SDA為低電平,表示為
有效應答訊號ACK
PS:當主機為接收方時,收到最後一個位元組後,主機可以不傳送ACK,直接傳送停止訊號來結束傳輸
。
當從機為接收方時,沒有傳送ACK,則表示從機可能在忙其它事、或者不匹配地址訊號和不支援多主機發送,主機可以傳送停止訊號,再次傳送起始訊號啟動新的傳輸。
6. 完整的資料傳輸
如下圖所示,
傳送起始訊號
後,便傳送一個
8位的裝置地址
,其中
第8位是對裝置的讀寫標誌
,後面緊跟著的就是
資料
了,直到傳送停止訊號
終止
。
PS:當我們第一次是讀操作,然後想換成寫操作時,可以再次傳送一個起始訊號,然後傳送讀的裝置地址,不需要停止訊號便能實現不同的地址轉換。
IIC傳輸資料的格式
1.寫操作
剛開始主晶片要發出一個
start訊號
,然後發出一個(用來確定是往哪一個晶片寫資料),
方向
(讀/寫,0表示寫,1表示讀)。
迴應
(用來確定這個裝置是否存在),然後就可以
傳輸資料
,傳輸資料之後,要有一個
迴應訊號
(確定資料是否接受完成),然後再傳輸
下一個資料
。每傳輸一個數據,接受方都會有一個迴應訊號,資料
傳送完
之後,主晶片就會發送一個
停止訊號
。
白色背景:主→從。灰色背景:從→主。
2.讀操作
剛開始主晶片要發出一個
start訊號
,然後發出一個
裝置地址
(用來確定是從哪一個晶片讀取資料),
方向
(讀/寫,0表示寫,1表示讀)。
迴應
(用來確定這個裝置是否存在),然後就可以
傳輸資料
,傳輸資料之後,要有一個迴應訊號(確定資料是否接受完成),然後在傳輸
下一個資料
。每傳輸一個數據,接受方都會有一個
迴應訊號
,資料傳送完之後,主晶片就會發送一個
停止訊號
。
白色背景:主→從。灰色背景:從→主
程式設計
嵌人式程式設計中,什麼是大端?什麼是小端?
大端模式:低位位元組存在高地址上,高位位元組存在低地址上。
小端模式:高位位元組存在高地址上,低位位元組存在低地址上。
STM32屬於小端模式,簡單的說,比如u32 temp=0X12345678;假設temp地址在0X2000 0010。那麼在記憶體裡面,存放就變成了:
地址 | HEX |
0X2000 0010 | 78 56 43 12 |
因為是16進位制的,一個數為0。5位元組,所以 12 代表一個位元組 34 代表一個位元組。
釆用小端模式的CPU對運算元的存放方式是從低位元組到高位元組,而大端模式對運算元的存放方式是從高位元組到低位元組。例如,16位寬的數0x1234在小端模式CPU記憶體中的存放方式(假設從地址0x4000開始存放)見表1,而在大端模式CPU記憶體中的存放方式見表2。
表1 0x1234在小端CPU記憶體中的存放方式
記憶體地址
存放內容
表2 0x1234在大端CPU記憶體中的存放方式
記憶體地址
存放內容
32位寬的數0x12345678在小端模式CPU記憶體中的存放方式(假設從地址0x4000開始存放)見表3,而在大端模式CPU記憶體中的存放方式見表4。
表3 0x12345678在小端CPU記憶體中的存放方式
記憶體地址
存放內容
表4 0x12345678在大端CPU記憶體中的存放方式
記憶體地址
存放內容
以下程式為例:
#include
struct mybitfields
{
unsigned short a:4;
unsigned short b:5;
unsigned short c:7;
}test;
int main()
{
int i;
test。a = 2;
test。b = 3;
test。c = 0;
i =*((short*)&test);
printf(“%d\n”,i);
return 0;
}
程式的輸出結果為 50。
上例中, sizeof( test)=2,上例的宣告方式是把一個 short(也就是一塊16位記憶體)分成3部分,各部分的大小分別是4位、5位、7位,賦值語句
i*( short*)&test)
就是把上面的16位記憶體轉換成 short型別進行解釋。
變數a的二進位制表示為0000000000000010,取其低四位是0010。變數b的二進位制表示為0000000000000011,取其低五位是00011。變數c的二進位制表示為0000000000000000,取其低七位是0000000。
80x86機是小端(修改分割槽表時要注意)模式,微控制器一般為大端模式
。小端一般是低位位元組在高位位元組的前面,也就是低位在記憶體地址低的一端,可以這樣記(小端→低位→在前→與正常邏輯順序相反),所以合成後得到0000000000110010,即十進位制的50。
下面給出另外一個例子
#include
#include
#include
int main()
{
unsigned int uiVal_1 = 0x12345678;
unsigned int uiVal_2 = 0;
unsigned char aucVal[4] = {0x12,0x34,0x56,0x78};
unsigned short usVal_1 = 0;
unsigned short usVal_2 = 0;
memcpy(&uiVal_2,aucVal,sizeof(uiVal_2));
usVal_1 = (unsigned short)uiVal_1;//在這裡截斷,都取得的是低位
usVal_2 = (unsigned short)uiVal_2;//在這裡截斷
printf(“usVal_1:%x\n”,usVal_1);//在這裡又轉化回來
printf(“usVal_2:%x\n”,usVal_2);//在這裡又轉化回來
return 0;
}
小端模式是低地址存放低位元組,高地址存放高位元組,結構如下所示
78//低地址
56
34
12//高地址
在記憶體裡面測試機是小端,地址由小到大。
val1:78563412
riVal2:12345678
結果如下:
5678
3412
如何判斷計算機處理器是大端,還是小端?
#include
int checkCPU()
{
{
union w
{
int a;
char b;
}c;
c。a =1;
return(c。b == 1);
}
}
int main()
{
if(checkCPU())
printf(“小端\n”);
else
printf(“大端\n”);
return 0;
}
編者的處理器為ntel處理器,因為 Intel處理器一般都是小端模式,所以此時程式的輸出結果為:小端
上述程式碼中,如果處理器是大端,則返回0;如果處理器是小端,則返回1。聯合體 union的存放順序是所有成員都從低地址開始存放,如果能夠透過改程式碼知道CPU對記憶體是採用小端模式讀寫,還是採用大端模式讀寫,一定會令面試官刮目相看。
還可以透過指標地址來判斷,由於在32位計算機系統中, short佔兩個位元組,char佔1個位元組,所以可以採用如下做法實現該判斷。
#include
int checkCPU()
{
unsigned short usData = 0x1122;
unsigned char*pucData = (unsigned char*)&usData;
return (*pucData == 0x22);
}
int main()
{
if(checkCPU())
printf(“小端\n”);
else
printf(“大端\n”);
return 0;
}
程式輸出的結果為:小端
如何進行大小端的轉換?
int swapInt32(int intValue){
int temp = 0;
temp = ((intValue & 0x000000FF) <<24)|
((intValue & 0x0000FF00) <<8) |
((intValue & 0x00FF0000) >>8) |
((intValue & 0xFF000000) >>24);
return temp;
}
/*short型:*/
unsigned short swapShort16(unsigned short shortValue){
return ((shortValue & 0x00FF ) <<8) | ((shortValue & 0xFF00)>>8);
}
/*float型:*/
float swapFloat32(float floatValue){
typedef union SWAP_UNION{
float unionFloat;
int unionInt;
}SWAP_UNION;
SWAP_UNION swapUnion;
swapUnion。unionFloat = floatValue;
swapUnion。unionInt = swapInt32( swapUnion。unionInt);
return swapUnion。unionFloat;
}
/*double型換一種寫法,用一下指標,不然移位移死了……*/
void swapDouble64(unsigned char *pIn, unsigned char *pOut){
for( int i=0;i<8;i++)
pOut[7-i] = pIn[i];
}
int main()
{
int x = 0x12345678;
int y = swapInt32(x);
printf(“%x\r\n”,y);
return 0;
}
如何對絕對地址0x100000賦值?
(unsigned int*)0x100000 = 1234;
那麼要是想讓程式跳轉到絕對地址是0x100000去執行,應該怎麼做?
*((void (*)( ))0x100000 ) ( );
首先要將0x100000強制轉換成函式指標,即:
(void (*)())0x100000
然後再呼叫它:
*((void (*)())0x100000)();·
用typedef可以看得更直觀些:
typedef void(*)() voidFuncPtr;
*((voidFuncPtr)0x100000)();
聯絡作者
作者在準備秋招的過程中,憑藉這份資料,最後順利拿到了
oppo,小米,兆易創新,全志科技,海康威視
等十餘家家公司的offer。現將這部分資料分享出來,希望能對大家有幫助!
如果大家在網上看到了不錯的資料,或者在筆試面試中遇到了資料中沒有的知識點,大家可以關注
我的公眾號
聯絡我,我替大家整理。
資料如有錯誤或者不合適的地方,可以在github向我提交issues。由於精力有限,所以只會用心維護好
github和公眾號
兩個平臺。資料中的勘誤也會同步更新在github中。
github倉庫
這份資料總共有七個部分,分別為:
C/C++
,
資料結構與演算法分析
,
Arm體系與架構
,
Linux驅動開發
,
作業系統
,
網路程式設計
,
名企筆試真題
。所有內容均會同步更新到github倉庫中。
PDF版本獲取方式也放在了github中。
關於作者
本碩雙非,參加了2020年秋招和2021年的春招,投遞崗位是嵌入式軟體(驅動)相關。總共收穫
Oppo,小米,海康威視,兆易創新,全志科技
等十餘家公司的offer。 我把自己的秋招,春招歷程詳細記錄了下來,同時,把自己秋招過程總結的
筆試面試資料
分享了出來,即
嵌入式軟體工程師筆試面試指南
。關注我的
知乎專欄
即可獲取PDF版本。
原文作者:仲一
文章來源(內含PDF)
:
原出處:公眾號-嵌入式與Linux那些事
侵刪