1. u-boot 存放位置
u-boot(或稱為Das U-Boot)是一種廣泛應(yīng)用于嵌入式系統(tǒng)的開源引導(dǎo)加載程序。它通常存放在嵌入式系統(tǒng)的非易失性存儲(chǔ)器中,具體位置可以根據(jù)具體的嵌入式系統(tǒng)架構(gòu)和設(shè)計(jì)來確定。
以下是幾種常見的u-boot存放位置:
1. Flash存儲(chǔ)器:
類似于單片機(jī)的情況,u-boot可以被燒寫到系統(tǒng)的Flash存儲(chǔ)器中。在嵌入式系統(tǒng)啟動(dòng)時(shí),處理器會(huì)從Flash存儲(chǔ)器讀取u-boot的代碼并執(zhí)行。
2. NOR Flash:
一些嵌入式系統(tǒng)使用NOR Flash作為主要的存儲(chǔ)器,并將u-boot存放在Flash芯片的特定地址范圍內(nèi)。這種存儲(chǔ)器通??梢灾苯釉谔幚砥髦袌?zhí)行,而無需將其復(fù)制到其他位置。
3. NAND Flash:
另一種常見的存儲(chǔ)器是NAND Flash,它也可以用于存放u-boot。與NOR Flash不同,NAND Flash的訪問方式復(fù)雜一些,因此在啟動(dòng)過程中,一般會(huì)將u-boot從NAND Flash中復(fù)制到RAM中,并在RAM中執(zhí)行。
4. SD卡/TF卡:
在某些嵌入式系統(tǒng)中,u-boot可以存放在可移動(dòng)存儲(chǔ)介質(zhì)上,例如SD卡或TF卡。當(dāng)系統(tǒng)啟動(dòng)時(shí),處理器會(huì)首先加載u-boot從存儲(chǔ)卡上,并執(zhí)行。
總結(jié)起來,u-boot一般存放在嵌入式系統(tǒng)的Flash存儲(chǔ)器中,包括NOR Flash和NAND Flash,在一些系統(tǒng)中也可以存放在可移動(dòng)存儲(chǔ)介質(zhì)上,例如SD卡或TF卡。
2. FreeRTOS 移植
在將FreeRTOS移植到STM32上之前,您需要進(jìn)行以下配置:
1. 配置硬件:確保您的STM32芯片與所選擇的FreeRTOS版本兼容,并且具備足夠的內(nèi)存資源。您可以參考芯片的數(shù)據(jù)手冊(cè)和FreeRTOS的系統(tǒng)要求來確認(rèn)這些信息。
2. 引入FreeRTOS源代碼:將FreeRTOS源代碼添加到您的項(xiàng)目中。您可以從FreeRTOS官方網(wǎng)站下載最新的穩(wěn)定版本或者適用于STM32的移植版。
3. 配置FreeRTOSConfig.h文件:這個(gè)文件包含了FreeRTOS的核心配置參數(shù)。您需要根據(jù)STM32的硬件特性和應(yīng)用需求進(jìn)行相應(yīng)配置。以下是一些可能需要配置的參數(shù):
?? - 定時(shí)器配置:根據(jù)STM32的定時(shí)器資源,配置用于FreeRTOS的系統(tǒng)節(jié)拍定時(shí)器。
?? - 內(nèi)存管理器配置:根據(jù)可用的RAM大小和需要的內(nèi)存管理策略,配置內(nèi)存管理器選項(xiàng)。
?? - 任務(wù)優(yōu)先級(jí)配置:定義任務(wù)優(yōu)先級(jí)的范圍和默認(rèn)優(yōu)先級(jí)。
?? - 棧配置:為每個(gè)任務(wù)定義適當(dāng)大小的??臻g。
?? - 優(yōu)化配置:根據(jù)應(yīng)用需求進(jìn)行合適的編譯優(yōu)化設(shè)置。
4. 創(chuàng)建任務(wù):在main.c(或其他文件)中創(chuàng)建需要運(yùn)行的任務(wù),通過調(diào)用FreeRTOS提供的API函數(shù)進(jìn)行任務(wù)的創(chuàng)建、啟動(dòng)和管理。
5. 配置中斷:根據(jù)您的應(yīng)用需求,配置適當(dāng)?shù)闹袛嗵幚沓绦?,并使用FreeRTOS提供的接口函數(shù)來在中斷中進(jìn)行任務(wù)切換。
6. 配置時(shí)鐘和系統(tǒng)節(jié)拍:根據(jù)STM32的時(shí)鐘設(shè)置和FreeRTOS的節(jié)拍定時(shí)器配置,確保系統(tǒng)節(jié)拍的準(zhǔn)確性和穩(wěn)定性。
7. 編譯和燒錄:將修改后的代碼編譯為可執(zhí)行文件,并將其燒錄到STM32芯片中進(jìn)行測(cè)試和調(diào)試。
請(qǐng)注意,以上步驟僅提供了一個(gè)大致的概述,實(shí)際移植過程可能會(huì)因STM32型號(hào)、FreeRTOS版本和應(yīng)用需求而有所差異。建議您參考針對(duì)您具體芯片和FreeRTOS版本的移植指南或示例代碼,以獲得更詳細(xì)和準(zhǔn)確的配置信息和步驟。
3. Linux 同步通信和異步通信方式
在Linux中,有多種通信方式可用于進(jìn)程間通信(IPC),其中一些是同步通信,而另一些是異步通信。下面是一些常見的IPC方式以及它們的通信方式:
1. 管道(Pipe):管道是一種半雙工通信方式,用于在父子進(jìn)程或具有共同祖先的進(jìn)程之間進(jìn)行通信。它是通過內(nèi)核緩沖區(qū)實(shí)現(xiàn)的,具有有限的容量。管道是同步通信方式,發(fā)送方寫入數(shù)據(jù)后,如果緩沖區(qū)已滿,發(fā)送方會(huì)被阻塞等待接收方讀取數(shù)據(jù)。
2. 命名管道(Named Pipe):命名管道也是一種半雙工通信方式,允許沒有親緣關(guān)系的進(jìn)程進(jìn)行通信。不同于管道,命名管道使用文件系統(tǒng)路徑作為標(biāo)識(shí)符,并以文件的形式存在于文件系統(tǒng)中。命名管道是同步通信方式,發(fā)送方在寫入數(shù)據(jù)時(shí),如果緩沖區(qū)已滿,則會(huì)被阻塞等待接收方讀取數(shù)據(jù)。
3. 消息隊(duì)列(Message Queue):消息隊(duì)列允許獨(dú)立的進(jìn)程通過消息傳遞進(jìn)行通信。它提供了一個(gè)存儲(chǔ)消息的隊(duì)列,并允許發(fā)送方發(fā)送消息到隊(duì)列中,接收方從隊(duì)列中讀取消息。消息隊(duì)列可以是同步或異步的,具體取決于發(fā)送方和接收方之間的操作。
4. 信號(hào)量(Semaphore):信號(hào)量用于在多進(jìn)程或多線程之間共享資源,并對(duì)資源的訪問進(jìn)行同步控制。信號(hào)量可以用于同步也可以用于異步通信,具體取決于進(jìn)程或線程如何使用它們。
5. 共享內(nèi)存(Shared Memory):共享內(nèi)存允許多個(gè)進(jìn)程共享同一塊物理內(nèi)存區(qū)域,以便進(jìn)行快速高效的數(shù)據(jù)交換。共享內(nèi)存本身是一個(gè)同步機(jī)制,但進(jìn)程間的同步與互斥需要額外的同步機(jī)制,如信號(hào)量來實(shí)現(xiàn)。
6. Socket套接字(Socket):Socket是一種常見的網(wǎng)絡(luò)編程接口,允許不同主機(jī)上的進(jìn)程進(jìn)行通信。Socket可以通過阻塞方式或非阻塞方式進(jìn)行通信,因此可以實(shí)現(xiàn)同步或異步的通信方式。
需要注意的是,上述通信方式并非專門屬于同步或異步通信的,而是根據(jù)具體實(shí)現(xiàn)和使用方式來確定其通信方式。通信方式的選擇應(yīng)根據(jù)實(shí)際需求和場(chǎng)景來確定。
4. Uboot啟動(dòng)流程
U-Boot(Universal Bootloader)是一款常用的開源引導(dǎo)加載程序,常用于嵌入式系統(tǒng)的啟動(dòng)。下面是Linux U-Boot的一般啟動(dòng)流程:
1. 引導(dǎo)加載器加載:當(dāng)嵌入式設(shè)備上電或復(fù)位后,處理器會(huì)跳轉(zhuǎn)到預(yù)定義的引導(dǎo)加載器(Bootloader)地址,通常在Flash存儲(chǔ)器的某個(gè)固定位置。這個(gè)引導(dǎo)加載器負(fù)責(zé)加載U-Boot鏡像文件到內(nèi)存中。
2. U-Boot初始化:一旦U-Boot鏡像被加載到內(nèi)存中,處理器會(huì)跳轉(zhuǎn)到U-Boot的入口地址,開始執(zhí)行U-Boot的代碼。U-Boot首先會(huì)進(jìn)行一系列的初始化工作,包括設(shè)置堆棧、初始化存儲(chǔ)器控制器、配置時(shí)鐘和外設(shè)等。(軟件初始化)
3. 硬件初始化:接下來,U-Boot會(huì)根據(jù)板級(jí)支持包(Board Support Package,BSP)中的配置信息,通過調(diào)用相關(guān)函數(shù)對(duì)設(shè)備的硬件進(jìn)行初始化,如GPIO口、UART、以太網(wǎng)控制器等。
4. 加載內(nèi)核鏡像:U-Boot會(huì)根據(jù)配置的啟動(dòng)方式(例如TFTP、NFS、MMC、SPI Flash等),從存儲(chǔ)介質(zhì)中加載Linux內(nèi)核鏡像(zImage或uImage)到內(nèi)存中的指定地址。
5. 加載設(shè)備樹(Device Tree):如果使用設(shè)備樹來描述硬件信息,則U-Boot會(huì)加載設(shè)備樹文件(dtb)到內(nèi)存中指定的地址。
6. 傳遞啟動(dòng)參數(shù):在加載完內(nèi)核和設(shè)備樹后,U-Boot會(huì)設(shè)置啟動(dòng)參數(shù)(如內(nèi)核命令行參數(shù)、Device Tree Blob地址等),并將這些參數(shù)傳遞給內(nèi)核。(直接修改PC寄存器的值為內(nèi)核的入口地址,就可以讓PC寄存器去執(zhí)行內(nèi)核的代碼)
7. 跳轉(zhuǎn)到內(nèi)核:最后,U-Boot會(huì)通過函數(shù)調(diào)用或匯編指令將控制權(quán)轉(zhuǎn)移到內(nèi)核的入口地址,讓內(nèi)核接管系統(tǒng)的進(jìn)一步啟動(dòng)過程。
需要注意的是,上述流程可能會(huì)因不同的硬件平臺(tái)、U-Boot版本和配置方式而有所差異。具體的啟動(dòng)流程和配置方式應(yīng)參考官方文檔或相關(guān)開發(fā)者手冊(cè),以確保正確配置和操作。
5. STM32(單片機(jī))啟動(dòng)流程
在STM32微控制器上電后,到達(dá)main函數(shù)執(zhí)行之前,通常會(huì)經(jīng)過以下幾個(gè)主要的步驟:
1. 復(fù)位向量表(Reset Vector Table):當(dāng)STM32微控制器上電或復(fù)位時(shí),硬件會(huì)將處理器重置為初始狀態(tài)。這時(shí),處理器會(huì)跳轉(zhuǎn)到預(yù)定義的復(fù)位向量表地址,即存儲(chǔ)器的起始位置(通常是0x0000 0000),從而執(zhí)行其中的復(fù)位處理程序。復(fù)位處理程序主要完成一些初始化工作,如設(shè)置堆棧指針、初始化全局變量等。
2. 設(shè)置堆棧和系統(tǒng)時(shí)鐘:復(fù)位處理程序一般會(huì)設(shè)置棧指針(Stack Pointer)的初始值,并初始化系統(tǒng)時(shí)鐘。通過設(shè)置合適的堆棧指針,可以確保在程序運(yùn)行期間正確地管理函數(shù)調(diào)用和中斷處理等操作。同時(shí),初始化系統(tǒng)時(shí)鐘可以為后續(xù)的外設(shè)和功能提供正確的時(shí)鐘源。(軟件初始化)
3. 初始化外設(shè)和系統(tǒng)組件:在復(fù)位處理程序或啟動(dòng)文件中,會(huì)進(jìn)行一系列的初始化工作,包括但不限于初始化中斷控制器、配置時(shí)鐘源和時(shí)鐘分頻器、初始化GPIO口、設(shè)置系統(tǒng)中斷優(yōu)先級(jí)等。這些步驟會(huì)確保各個(gè)外設(shè)和系統(tǒng)組件處于正確的狀態(tài),以便后續(xù)的應(yīng)用程序正常運(yùn)行。(硬件初始化)
4. 跳轉(zhuǎn)到main函數(shù):最后,經(jīng)過上述的初始化過程后,處理器會(huì)跳轉(zhuǎn)到main函數(shù)的入口地址開始執(zhí)行應(yīng)用程序。在main函數(shù)中,開發(fā)者可以編寫自己的應(yīng)用程序邏輯,實(shí)現(xiàn)所需的功能。
需要注意的是,上述步驟的具體實(shí)現(xiàn)可能因不同的微控制器型號(hào)和使用的開發(fā)工具鏈而有所差異。一般來說,STMicroelectronics提供了相應(yīng)的啟動(dòng)文件和庫函數(shù),能夠幫助開發(fā)者進(jìn)行初始化和配置工作。在編寫嵌入式代碼時(shí),建議參考對(duì)應(yīng)的微控制器參考手冊(cè)和相關(guān)文檔,并按照官方提供的示例進(jìn)行操作。
6. Linux 啟動(dòng)流程
- 上電:硬件上電
- Uboot:這里涉及到 uboot 的啟動(dòng)流程;
- Linux內(nèi)核啟動(dòng):uboot 啟動(dòng)后會(huì)指引 Linux 內(nèi)核啟動(dòng)
- 運(yùn)行文件系統(tǒng):讀入 boot 目錄下的內(nèi)核文件,或者說運(yùn)行文件系統(tǒng)(boot下有什么文件?arch 目錄等等)
- Init 進(jìn)程:內(nèi)核加載后運(yùn)行的第一個(gè)程序,sbin/init;用來初始化系統(tǒng)環(huán)境,PID=1;
- 加載開機(jī)啟動(dòng)腳本:比如 /etc/init.d ;、etc/local.rc 等等
- 用戶登錄,進(jìn)入shell
7. extern C
extern C 是一個(gè)用于 C++ 語言的關(guān)鍵字組合,用于聲明具有 C 語言編譯習(xí)慣和名稱修飾規(guī)則的函數(shù)或變量。
在 C++ 中,函數(shù)和變量的名稱修飾規(guī)則是不同于 C 語言的。C++ 會(huì)對(duì)函數(shù)或變量的名稱進(jìn)行修飾,以便支持函數(shù)重載、命名空間等特性。而 C 語言沒有名稱修飾這個(gè)概念。
使用 extern "C"
關(guān)鍵字將函數(shù)或變量聲明為 C 鏈接,可以使得 C++ 編譯器按照 C 語言的鏈接規(guī)則來處理這些聲明。這樣,就可以在 C++ 代碼中與 C 語言的函數(shù)或變量進(jìn)行兼容操作、調(diào)用或共享。
舉個(gè)栗子:
#ifdef __cplusplus
extern "C" {
#endif
// C 風(fēng)格的函數(shù)聲明
void foo();
#ifdef __cplusplus
}
#endif
8. 給你一個(gè)裸機(jī)你怎么輸出 printf
????????在裸機(jī)環(huán)境下,沒有操作系統(tǒng)提供的標(biāo)準(zhǔn)輸入輸出庫,無法直接使用 printf
函數(shù)進(jìn)行輸出。然而,你可以手動(dòng)編寫一個(gè)簡(jiǎn)單的輸出函數(shù)來模擬 printf
的功能。
????????首先,需要了解裸機(jī)環(huán)境的底層硬件和外設(shè)接口。通常,裸機(jī)開發(fā)中會(huì)涉及寄存器訪問、串口通信等底層操作。
下面是一個(gè)簡(jiǎn)單的示例,通過串口(UART)實(shí)現(xiàn)一個(gè)簡(jiǎn)化版的 printf
函數(shù)思路:
操作寄存器,初始化串口,往串口數(shù)據(jù)寄存器里面寫入數(shù)據(jù)。
// 定義串口地址
#define UART_BASE_ADDRESS 0x10000000
// 串口寄存器地址偏移量
#define UART_DATA_REG_OFFSET 0x00
#define UART_STATUS_REG_OFFSET 0x04
// 輸出單個(gè)字符到串口
void uart_putc(char c) {
// 等待串口就緒
while (*(volatile unsigned int *)(UART_BASE_ADDRESS + UART_STATUS_REG_OFFSET) & 0x01);
// 寫入字符到數(shù)據(jù)寄存器
*(volatile unsigned int *)(UART_BASE_ADDRESS + UART_DATA_REG_OFFSET) = c;
}
// 輸出格式化字符串到串口
void my_printf(const char *format, ...) {
// 根據(jù)參數(shù)解析格式化字符串并輸出到串口
// 這里只實(shí)現(xiàn)了 %c 和 %s 格式的輸出
}
9. define 有什么缺陷,可以用什么替換 define
`#define` 是 C 和 C++ 中用于定義宏的預(yù)處理指令。雖然 `#define` 在一些情況下很方便,但也存在一些缺陷,包括:
1. 無類型檢查:`#define` 定義的宏沒有類型檢查,編譯器無法對(duì)其進(jìn)行語法、語義和類型等錯(cuò)誤檢查。這可能導(dǎo)致宏的使用出現(xiàn)潛在的問題,并增加調(diào)試難度。
2. 可讀性差:使用過度復(fù)雜的宏定義會(huì)導(dǎo)致代碼可讀性差,使得代碼難以理解、維護(hù)和調(diào)試。宏定義通常是替換文本,不像函數(shù)一樣具備結(jié)構(gòu)和作用域。
3. 副作用:宏定義可以對(duì)參數(shù)進(jìn)行多次求值,這可能導(dǎo)致意外的副作用。例如,`#define SQUARE(x) (x * x)`,在將表達(dá)式作為參數(shù)時(shí),可能會(huì)產(chǎn)生預(yù)期之外的結(jié)果。
為了替代 `#define`,可以使用以下方法:
1. 使用常量或枚舉:對(duì)于需要定義常量或枚舉類型的場(chǎng)景,可以使用常量或枚舉來替代宏定義,這樣可以具有類型檢查和更好的可讀性。
2. 使用內(nèi)聯(lián)函數(shù):內(nèi)聯(lián)函數(shù)可以實(shí)現(xiàn)宏定義相同的效果,但會(huì)進(jìn)行更嚴(yán)格的類型檢查。內(nèi)聯(lián)函數(shù)能夠保留函數(shù)的結(jié)構(gòu)和作用域,同時(shí)具有類型安全性和可讀性。
3. 使用 constexpr(在 C++11 中引入):constexpr 是用于聲明可以在編譯期間計(jì)算的常量表達(dá)式的關(guān)鍵字。它可以用于替代宏定義的常量,并且會(huì)進(jìn)行編譯時(shí)類型檢查。
10. 為什么要有用戶態(tài)和內(nèi)核態(tài),兩者如何切換
????????用戶態(tài)和內(nèi)核態(tài)是計(jì)算機(jī)系統(tǒng)中的兩種不同的運(yùn)行模式,用于區(qū)分用戶程序和操作系統(tǒng)內(nèi)核的執(zhí)行權(quán)限和特權(quán)級(jí)別。
????????用戶態(tài)是指用戶程序在執(zhí)行時(shí)所處的權(quán)限較低的狀態(tài)。在用戶態(tài)下,用戶程序只能訪問受限的資源和執(zhí)行受限的操作。例如,用戶程序不能直接訪問底層硬件設(shè)備。
????????內(nèi)核態(tài)是指操作系統(tǒng)內(nèi)核在執(zhí)行時(shí)所處的權(quán)限較高的狀態(tài)。在內(nèi)核態(tài)下,操作系統(tǒng)具有對(duì)所有資源和操作的完全控制權(quán),包括訪問硬件設(shè)備、修改內(nèi)存映射、管理進(jìn)程等。
????????引入用戶態(tài)和內(nèi)核態(tài)的主要目的是實(shí)現(xiàn)系統(tǒng)的安全和可靠性。通過限制用戶程序的權(quán)限,可以防止用戶程序?qū)ο到y(tǒng)造成損害或?yàn)E用系統(tǒng)資源。同時(shí),操作系統(tǒng)在內(nèi)核態(tài)下具有更高的權(quán)限和更廣泛的功能,可以有效管理和保護(hù)系統(tǒng)資源。
????????當(dāng)用戶程序需要執(zhí)行特權(quán)操作時(shí)(例如訪問受保護(hù)的資源或執(zhí)行特權(quán)指令),必須通過系統(tǒng)調(diào)用的方式從用戶態(tài)切換到內(nèi)核態(tài)。系統(tǒng)調(diào)用是用戶程序發(fā)起系統(tǒng)服務(wù)請(qǐng)求的一種機(jī)制,它將控制權(quán)轉(zhuǎn)移到操作系統(tǒng)內(nèi)核,并在內(nèi)核態(tài)下執(zhí)行相應(yīng)的操作。完成后,操作系統(tǒng)再將控制權(quán)返回給用戶程序,并切換回用戶態(tài)。文章來源:http://www.zghlxwxcb.cn/news/detail-706277.html
??????? 但總的來說,用戶態(tài)和內(nèi)核態(tài)之間的切換是通過特殊的機(jī)制和處理器指令來實(shí)現(xiàn)的,確保用戶程序和操作系統(tǒng)能夠安全地進(jìn)行交互和協(xié)作。文章來源地址http://www.zghlxwxcb.cn/news/detail-706277.html
到了這里,關(guān)于嵌入式基礎(chǔ)知識(shí)大雜燴的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!