從引導加載程序到sysfs:Linux設備樹的完整解析與驅動綁定機制

摘要

本報告旨在為嵌入式Linux開發者詳細梳理設備樹(Device Tree, DT)在系統啟動中的完整解析流程。報告將從引導加載程序(Bootloader)如何準備和傳遞設備樹二進制文件(DTB)開始,逐步深入到內核如何將其轉化為可操作的內存數據結構,如何與設備驅動程序進行匹配與綁定,最終闡述驅動程序如何利用這些信息在sysfs文件系統中創建可供用戶空間訪問的設備節點。這份報告旨在解答從靜態的硬件描述到用戶可見的動態設備文件這一過程中的所有核心技術問題。

引言:設備樹的核心作用與演變

1.1 設備樹的起源與必要性

設備樹最初源于SPARC和PowerPC平臺的Open Firmware項目,其設計初衷是為了在不修改操作系統內核的情況下,支持多種不同的硬件配置 。在ARM架構中,設備樹的引入尤其關鍵,因為它徹底改變了傳統的“一個板子一個內核”的困境 。

在設備樹出現之前,Linux內核的硬件描述是硬編碼在所謂的board-file(如arch/arm/mach-xxx/board-yyy.c)中的 。這意味著,每當硬件發生微小改動,例如更改了一個I2C外設的地址,就需要重新編譯整個內核鏡像 。這種緊耦合的設計使得內核開發難以擴展,也極大地增加了新板卡移植的復雜性。

設備樹的出現標志著一種從硬編碼到數據驅動的嵌入式軟件開發范式轉變。在舊的ARM啟動機制中,引導加載程序使用一種名為ATAGS(一個鏈表結構)的機制,只能傳遞內存大小、內核命令行等少量基本信息 。而其他所有非自發現(non-discoverable)的硬件信息,如I2C控制器地址、GPIO引腳配置等,都必須預先硬編碼在內核源碼的

board-file里 。

與此形成鮮明對比的是,設備樹二進制文件(DTB)包含了完整的硬件拓撲結構。引導加載程序只需將DTB的物理地址傳遞給內核(在ARM上,這一地址通常被加載到R2寄存器中),內核就能在運行時自主解析整個硬件配置 。這種轉變將硬件描述從內核源碼中移除,放入獨立的文件(

.dts)中,使得同一個內核鏡像能夠通過加載不同的DTB文件來支持多個不同的板卡 。這種解耦機制是現代Linux內核在嵌入式領域取得成功,特別是實現通用主線內核支持的關鍵。

1.2 設備樹的基本構成

設備樹本質上是一種描述硬件的數據結構,采用樹形或非循環圖的格式 。其基本結構由節點(nodes)和屬性(properties)組成 。每個節點都代表一個設備或總線,并可以包含任意數量的命名屬性和子節點 。

  • 根節點(/:設備樹的頂層節點,沒有名稱和地址 。

  • 節點命名:每個節點都遵循node-name@unit-address的命名慣例 。

    node-name描述設備的類型,unit-address則指定設備在其父總線地址空間中的基地址 。

  • 核心屬性

    • #address-cells#size-cells:這兩個屬性定義了子節點reg屬性中地址和大小字段的單元格(cell,即32位值)數量 。這是一種可擴展的地址表示機制。

    • compatible(兼容性字符串):這是連接硬件描述與設備驅動程序的關鍵契約 。它是一個字符串列表,通常由

      vendor,device組成,其中最具體的字符串排在最前面,最通用的排在最后 。驅動程序會使用這個字符串來聲明自己支持哪些硬件 。

    • phandlealiases:設備樹允許節點之間通過phandle進行引用 。這種引用通常通過

      &label的形式來實現,其中label是節點的標簽 。此外,

      /aliases節點為常用的節點路徑提供了簡短的別名,便于訪問 。

第一章:啟動加載階段:DTB的準備與傳遞

2.1 DTB的生成與存儲

設備樹的生命周期始于其源文件。硬件開發者通常會編寫設備樹源文件(.dts),并引用包含SoC級別通用定義的設備樹包含文件(.dtsi) 。這種

.dtsi文件通過#include指令實現模塊化和重用,使得不同板卡可以共享SoC的硬件描述 。

這些.dts.dtsi文件由設備樹編譯器(Device Tree Compiler, dtc)處理,dtc將人類可讀的文本格式轉換為緊湊的、面向機器的二進制格式,即設備樹二進制文件(DTB,文件后綴為.dtb)。生成的DTB文件通常與Linux內核鏡像(如

zImageuImage)一同存儲在系統的非易失性存儲介質(如SD卡、eMMC或NAND Flash)的啟動分區中 。

2.2 U-Boot的職責與DTB的修改

引導加載程序(例如U-Boot)是DTB解析過程的第一階段參與者 。它的主要職責是:

  1. 將內核鏡像和DTB文件從存儲介質加載到RAM中 。

  2. 在內存中對DTB進行必要的運行時修改,例如更新chosen節點中的bootargs(內核命令行參數)、設置RAM的基地址和大小,或者配置網絡接口的MAC地址等 。

  3. 加載完成后,U-Boot將最終的DTB準備好,并將其物理內存地址傳遞給內核 。

這些修改至關重要,它確保了內核接收到的硬件描述是最新、最準確的,能夠反映引導加載程序在啟動時根據用戶配置或探測結果所做的任何調整。

2.3 DTB的關鍵傳遞機制

在ARM架構中,U-Boot將DTB的物理地址傳遞給內核的機制是一個設計精巧的關鍵環節 。在跳轉到內核入口點之前,U-Boot會執行以下操作:

  1. 將CPU的r0寄存器設置為0。

  2. r1寄存器設置為機器類型ID(舊機制)。

  3. r2寄存器設置為DTB在系統RAM中的物理地址 。

然后,U-Boot跳轉到內核的入口點,內核從此接管控制權 。下表對比了設備樹機制與舊的ATAGS機制的差異,突出了前者在靈活性和可擴展性方面的優勢。

表1:ATAGS與設備樹傳遞機制對比

特性ATAGS (舊機制)設備樹 (現代機制)
數據結構一個鏈表,由一系列標簽(tag)組成一個扁平化、樹狀的二進制數據塊(DTB)
傳遞方式引導加載程序通過r2寄存器傳遞一個指向ATAGS鏈表頭部的指針

引導加載程序通過r2寄存器傳遞一個指向DTB二進制數據塊的指針

描述內容

僅限于少量基本信息,如內存大小、命令行參數等

包含完整的硬件拓撲、外設地址、中斷、GPIO等所有非自發現的硬件信息

優點簡單、開銷小

硬件描述與內核代碼完全解耦,支持通用內核鏡像

缺點

缺乏靈活性,板級硬件信息需要硬編碼在內核源碼中

需要額外的dtc工具編譯,DTB文件需要占用一定內存空間
適用范圍

已被棄用,不建議用于新平臺

現代嵌入式Linux的首選,ARM等多種架構強制使用

第二章:內核早期啟動:DTB的初步解析

3.1 內核入口點與DTB的接收

在U-Boot將控制權交給Linux內核后,內核的啟動代碼會開始執行。在start_kernel()函數被調用之前,內核的架構特定啟動代碼(如ARM上的head.S文件)會從r2寄存器中讀取DTB的物理地址 。這個地址隨后會被保存到一個全局變量中,供內核后續使用 。

這個階段非常關鍵,因為此時內存管理單元(MMU)尚未啟用,內核只能訪問物理地址 。這意味著內核無法進行復雜的動態內存分配和構建復雜的C數據結構。然而,它需要一些關鍵信息才能完成MMU的初始化,例如RAM的地址和大小,以及

bootargs中的內核命令行參數 。

3.2 of_scan_flat_dt()libfdt

為了在MMU啟用之前的受限環境中獲取必要信息,內核使用一個輕量級的庫來直接解析DTB的扁平化二進制數據 。這個庫就是

libfdt(Flattened Device Tree library)。

libfdt被集成在內核源碼中,提供了一系列低級API來檢查、讀取和修改DTB二進制文件 。

內核的啟動代碼會調用of_scan_flat_dt()函數來遍歷DTB,并使用回調函數來提取關鍵信息 。例如:

  • early_init_dt_scan_chosen():用于解析/chosen節點下的內核命令行參數 bootargs

  • early_init_dt_scan_memory():用于確定系統RAM的地址和大小 。

這種設計表明內核對DTB的解析并非一次性完成,而是分為兩個階段:早期掃描(pre-MMU)和后期解壓(post-MMU)。這個設計是啟動過程中內存和尋址限制所決定的。在MMU啟用前,內核無法進行復雜的動態內存分配,因此需要libfdt這種能夠在物理內存中直接操作DTB二進制數據的工具。

3.3 DTB的“解壓”:從扁平化到樹形結構

當內核完成了MMU的初始化和虛擬內存的配置后,它就可以進行更復雜的內存操作。此時,一個關鍵的函數unflatten_device_tree()會被調用 。這個函數的核心任務是將靜態的DTB二進制數據轉換成一個動態的、鏈表連接的內存數據結構:

struct device_node樹 。

unflatten_device_tree()的執行標志著DTB的靜態描述階段結束,進入了DT在內存中作為動態數據結構的活躍階段。這種兩階段解析過程是內核為了在有限制的早期啟動環境中獲取關鍵信息,同時在成熟的運行時環境中構建高效、易于訪問的數據結構之間做出的權衡。

第三章:DT的內存表示與驅動程序的接口

4.1 struct device_node:DT在內存中的實體

DTB經過unflatten_device_tree()的轉換后,在內核中被表示為一系列相互連接的struct device_node實例 。

struct device_node是DT中每個節點的內存表示,它包含了指向其父節點、子節點、兄弟節點和屬性列表的指針,從而構成了完整的樹形結構 。

驅動程序不會直接操作DTB二進制數據,而是通過一套標準的of_*家族API來與這個struct device_node樹進行交互 。這些API包括:

  • of_get_next_child():用于遍歷一個節點的所有子節點 。

  • of_find_compatible_node():用于根據兼容性字符串在DT樹中查找匹配的節點 。

  • of_get_property():用于讀取一個節點中特定屬性的值 。

這些高級API將復雜的樹形遍歷和數據解析細節封裝起來,為驅動程序提供了一個簡潔、高效的接口。

4.2 DT與內核設備模型的整合

設備樹的解析為Linux設備模型提供了設備實例化的數據來源。Linux設備模型的核心思想是圍繞著總線(bus)、設備(device)和驅動(driver)這三元組來組織的 。

DT中的節點本身并不是Linux設備模型中的“設備”,而只是對硬件的靜態描述 。內核在解析DT后,會根據這些靜態數據來動態創建

struct device實例。對于SoC上那些無法被自動枚舉的內存映射設備,內核為此創建了一個虛擬總線——platform_bus

of_platform_populate()函數是連接DT解析和Linux設備模型的關鍵橋梁 。它會遍歷DT樹,找到那些具有

compatible屬性的節點,并為它們創建對應的platform_device實例,然后將這些設備注冊到platform_bus上 。對于其他總線類型(如I2C、SPI),其總線驅動的

probe函數會負責為其子節點創建相應的設備實例(如i2c_client),并注冊到各自的總線上 。

這個過程將設備描述從靜態數據轉換為了內核設備模型中的動態實例,從而實現了從設計藍圖到可操作實體的轉變。

第四章:驅動程序綁定與設備實例

5.1 設備與驅動的匹配模型

在Linux設備模型中,一個設備只有在找到與其匹配的驅動程序時,才會被“激活”并進行初始化 。當一個新的設備實例(例如一個

platform_device)被注冊到總線上時,內核的驅動核心會自動遍歷所有已注冊的驅動程序,尋找與該設備匹配的項 。

platform_bus上的匹配過程由platform_match()函數實現 。該函數會嘗試多種匹配方式,其中最重要的一種就是基于設備樹的兼容性匹配 。

5.2 DT與驅動的“兼容”橋梁

設備樹驅動綁定機制的核心是compatible字符串 。這是一種在設備和驅動之間建立“契約”的機制:

  • DT端:設備樹節點通過compatible屬性來聲明其所代表的硬件類型 。該屬性是一個字符串列表,由最具體的兼容性字符串到最通用的兼容性字符串排列 。

  • 驅動端:驅動程序通過定義一個名為of_match_tableconst struct of_device_id數組來聲明自己支持的compatible字符串 。這個數組通常通過

    MODULE_DEVICE_TABLE(of,...)宏導出,供內核驅動核心識別 。

匹配過程由of_match_device()函數執行 。當一個

platform_device被注冊時,內核會調用此函數,將設備的compatible字符串列表與所有已注冊驅動的of_match_table進行比較,如果找到了匹配項,則認為匹配成功 。

表2:DT節點與驅動匹配示例

模塊關鍵元素示例內容作用
設備樹DT節點路徑&i2c1 {... my_device@4a {... } }定義一個在I2C總線1上,地址為0x4a的設備
compatible屬性compatible = "acme-inc,my-device";

聲明該設備的硬件兼容性字符串

驅動程序of_match_tablestatic const struct of_device_id my_device_of_match = { {.compatible = "acme-inc,my-device", }, { } }; MODULE_DEVICE_TABLE(of, my_device_of_match);

聲明該驅動程序支持“acme-inc,my-device”這個兼容性字符串

probe()函數static int my_device_probe(struct platform_device *pdev) {... }

匹配成功后,內核調用的初始化函數

上表展示了compatible字符串如何成為連接設備樹和驅動程序的“魔術字符串”。一個在設備樹中聲明的設備節點,只有當其compatible字符串與某個驅動程序的of_match_table中的一項完全匹配時,才會被內核成功綁定。

5.3 probe()函數的調用與驅動的參與

當內核找到匹配的設備與驅動后,它會自動調用驅動程序提供的probe()函數 。例如,對于

platform_driver,其platform_driver結構體中的probe()函數會被調用,并將對應的platform_device實例作為參數傳入 。

probe()函數是驅動程序參與設備初始化的起點 。在該函數中,驅動程序會:

  1. 獲取DT節點:從傳入的platform_device實例中,通過dev->of_node指針獲取到對應的struct device_node

  2. 讀取屬性:使用of_*家族API(例如of_get_property()of_get_next_child())從DT節點中讀取硬件配置信息 。這些信息可能包括內存映射地址(

    reg)、中斷號(interrupts)、GPIO引腳配置(gpios)等 。

  3. 初始化硬件:利用讀取到的信息,驅動程序對硬件進行具體的初始化和配置 。例如,I2C控制器驅動會根據DT中的

    clock-frequency屬性設置總線速度 。

  4. 注冊設備:完成初始化后,驅動程序會向內核注冊更高層級的設備接口,例如字符設備、塊設備或網絡設備 。

第五章:從DT節點到/sys目錄的最終映射

6.1 kobject基礎設施與設備模型的基石

/sys文件系統是一個虛擬文件系統,它的主要功能是將內核中的數據結構和關系以目錄和文件的形式,層次化地暴露給用戶空間 。

sysfs的核心是kobject

kobject是Linux內核中用于描述和管理對象的通用基礎設施 。每個

kobject都代表內核中的一個對象,并在/sys中對應一個目錄。struct device(如platform_device)是內嵌了kobject的更高級抽象 。當

struct device被注冊時,其內嵌的kobject也會被注冊,從而在sysfs中自動創建相應的目錄結構 。

6.2 probe()函數中的/sys目錄生成

當驅動程序的probe()函數成功返回后,內核設備模型會注冊這個設備實例 。這個注冊過程會自動觸發

kobject的創建和注冊,從而在/sys/devices/platform/.../sys/bus/i2c/devices/...等目錄下創建對應的設備目錄 。這些目錄的名稱通常基于設備的

nameid

6.3 驅動程序如何創建屬性文件

設備目錄創建后,驅動程序可以在其中添加屬性文件,以暴露設備的運行時狀態或提供配置接口 。這些屬性文件由

struct device_attribute結構體定義,其中包含了文件的名稱、訪問權限以及兩個關鍵的回調函數:show()store()

  • show():當用戶空間應用程序通過cat等命令讀取/sys下的屬性文件時,內核會調用這個函數 。驅動程序會執行相應的邏輯,將設備的實時狀態或信息寫入內核提供的緩沖區,然后返回給用戶空間 。

  • store():當用戶寫入屬性文件時,內核會調用這個函數 。驅動程序會接收用戶寫入的數據,并據此配置或控制硬件 。

值得注意的是,用戶在/sys下看到的設備節點并非DT節點的直接鏡像,而是內核設備模型在運行時生成的抽象。DT節點是靜態的硬件描述,而/sys文件是動態的軟件接口。DTB的原始二進制數據可以在/sys/firmware/devicetree/base/proc/device-tree下以只讀形式訪問 。而

/sys/devices/...下的文件則是由設備驅動程序在probe()階段動態創建的。/sys接口的背后是show()store()回調函數實現的具體設備控制邏輯,這些邏輯根據DT中提供的靜態數據(如寄存器地址、中斷號)來操作硬件 。因此,

/sys是內核提供給用戶空間的標準化接口,而DT則是驅動程序實現這些接口所需的“設計藍圖”。

結論與展望

7.1 完整流程回顧

設備樹在Linux內核啟動過程中扮演著至關重要的角色,其解析流程可概括為以下步驟:

  1. DTB的準備:開發者使用dtc工具將.dts源文件編譯成DTB二進制文件,并將其與內核鏡像一同存儲在啟動介質中 。

  2. DTB的傳遞:引導加載程序(如U-Boot)將DTB加載到RAM中,進行必要的運行時修改,并將DTB的物理地址通過特定的CPU寄存器(如ARM上的R2)傳遞給內核 。

  3. 早期解析:內核在早期啟動階段(pre-MMU),利用libfdt庫調用of_scan_flat_dt()函數,提取內存布局和bootargs等關鍵信息 。

  4. 構建數據結構:MMU啟用后,unflatten_device_tree()函數將DTB的扁平化二進制數據轉換成可供內核高效訪問的struct device_node樹形數據結構 。

  5. 設備實例化:內核設備模型遍歷device_node樹,根據節點的compatible屬性創建對應的platform_device或其他總線設備實例 。

  6. 驅動綁定與probe:內核驅動核心將新創建的設備實例與已注冊的驅動程序的of_match_table進行匹配。匹配成功后,內核調用驅動的probe()函數 。

  7. sysfs文件創建:在probe()函數中,驅動程序根據DT信息初始化硬件,并利用kobject基礎設施在/sys目錄下創建設備目錄和屬性文件,從而向用戶空間暴露可讀寫的設備接口 。

7.2 DT的未來與意義

設備樹機制的引入是嵌入式Linux發展的一個里程碑,它將硬件描述從內核源碼中分離,使開發者能夠使用同一個內核二進制文件來支持不同的硬件平臺 。這種從硬編碼到數據驅動的范式轉變極大地提高了內核的可維護性和可移植性。展望未來,設備樹仍然是現代嵌入式系統不可或缺的一部分。例如,設備樹Overlay(DTO)機制允許在運行時動態地加載和應用硬件配置,使得系統能夠支持熱插拔設備或可配置的擴展板 。設備樹的持續演進和廣泛應用確保了Linux在快速變化的嵌入式硬件生態中保持其強大的適應性和靈活性。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/95052.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/95052.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/95052.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

基于深度學習的污水新冠RNA測序數據分析系統

基于深度學習的污水新冠RNA測序數據分析系統 摘要 本文介紹了一個完整的基于深度學習技術的污水新冠RNA測序數據分析系統,該系統能夠從未經處理的污水樣本中識別新冠病毒變種、監測病毒動態變化并構建傳播網絡。我們詳細闡述了數據處理流程、深度學習模型架構、訓練…

寶塔面板配置Nacos集群

一、環境準備 準備三臺及以上的服務器,我這里準備了3臺服務器,172.31.5.123~125;分別安裝好寶塔面板,軟件商店里安裝nacos;二、Nacos集群配置 配置數據庫連接:? 進入每臺服務器上 Nacos 解壓后…

Spring Boot 3.x 全新特性解析

Spring Boot 是企業級 Java 開發中最常用的框架之一。自 Spring Boot 3.x 發布以來,其引入的一系列重大變更與優化,為開發者提供了更現代、更高效的開發體驗。本文將重點解析 Spring Boot 3.x 的關鍵特性及其對項目架構的影響。 一、基于 Jakarta EE 10 …

2025.8.10總結

今天晚上去跑了2公里,跑完還挺爽的,然后花了1.5個小時去公司刷題,沒有進行限時練,花了一周的時間才做完這題,共找了20個bug,雖然沒有進行限時練,但我仿佛對測試技術掌握得更好了,知道…

qt中實現QListWidget列表

使用最基本的QListWidgetItem來創建列表項,具體使用下面setText、setIcon、addItem這三個方法#include "mainwindow.h" #include "ui_mainwindow.h" #include "QDebug"enum CustomRoles {IdRole Qt::UserRole, // 存儲IDPhoneR…

nginx-主配置文件

nginx-主配置文件一、主配置文件nginx.conf內容二、修改配置的文件后的操作三、配置虛擬主機的域名1. 修改nignx.conf配置文件2. 新建域名對應的網頁根目錄3. 重載nginx配置4. 驗證一、主配置文件nginx.conf內容 [rootweb1 conf]# cat nginx.conf#user nobody; # nginx woke…

DBSACN算法的一些應用

以下是 DBSCAN 算法在 Python 中的幾個典型應用示例,涵蓋了基礎使用、參數調優和可視化等方面:import numpy as np import matplotlib.pyplot as plt from sklearn.cluster import DBSCAN from sklearn.datasets import make_moons, make_blobs from skl…

java9學習筆記-part1

G1 成為默認垃圾回收器在 Java 8 的時候,默認垃圾回收器是 Parallel Scavenge(新生代)Parallel Old(老年代)。到了 Java 9, CMS 垃圾回收器被廢棄了,G1(Garbage-First Garbage Collector&#x…

【github.io靜態網頁 怎么使用 github.io 搭建一個簡單的網頁?】

這里是一張展示 GitHub Pages 靜態網站架構與部署流程的示意圖,可以幫助你更直觀理解整個流程。 要使用 github.io(GitHub Pages)搭建一個簡單的網頁,你可以按照以下步驟操作: 快速入門:個人網站&#xff…

記錄一次ubuntu20.04 解決gmock not found問題的過程

在電腦上源碼編譯moveit,系統是ubuntu20.04,有三個電腦,分別叫做A,B,C好了,A和C都可以很順暢地走流程編譯通過,但是B遇到了gmock not found的問題,一開始沒當回事,感覺重裝下庫,或者…

Java基礎編程核心案例:從邏輯到應用

Java編程的核心在于將邏輯思維轉化為可執行的代碼。本專欄通過8個實用案例,覆蓋條件判斷、循環結構、數組操作、用戶交互等基礎知識點,展示如何用Java解決實際問題,從簡單游戲到數據計算,逐步構建編程思維。 案例一:剪…

Starlink衛星終端對星策略是終端自主執行的還是網管中心調度的?

以下文章首先來源于Google Gemini的Deep Research的內容,在Deep Research的報告參考了SpaceX公開信息、FCC技術報告、相關專利(如US9906292B2)以及學術研究的綜合分析,并參考了RFWirelessWorld和APNIC博客等二次來源。 文章完成之后,前后發給了Grok和deepseek,讓Grok和d…

【CDA案例】數據分析案例拆解:解鎖數據分析全流程!

在當今數字化時代,數據如同一座座金礦,蘊含著巨大的價值。企業、組織乃至個人都渴望從海量的數據中挖掘出有用的信息,以指導決策、優化運營、提升競爭力。今天我們以一個實際的數據分析案例為藍本,深入拆解其全過程,帶…

vulnhub-drippingblues靶場攻略

1.打開靶場,我們將網絡連接方式改為NAT模式2.然后使用nmap掃描一下nat的網段3.存在21,22,80端口我們先來看一下21端口的ftp協議,發現可以直接匿名登錄,并且可以下載存在的東西4.但是這個壓縮包被加密了,我們…

afsim2.9_使用QtCreator和VSCode編譯

使用QtCreator和VSCode編譯AFSIM2.9源代碼指南 準備工作 在開始編譯AFSIM2.9源代碼前,需要確保您的開發環境滿足以下條件: 安裝QtCreator安裝Visual Studio Code(最新穩定版)獲取AFSIM2.9源代碼包安裝必要的編譯工具鏈&#xf…

TC39x STM(System Timer)學習記錄

STM有哪些特性?自由運行的 64 位計數器所有 64 位可同步讀取可同步讀取 64 位計數器的不同 32 位部分基于與 STM 部分內容的比較匹配,靈活地產生服務請求在應用復位后自動開始計數若 ARSTDIS.STMxDIS 位清零,應用復位將復位 STM 寄存器&#…

css初學者第四天

<1>snipaste工具的使用snipaste是一個簡單但強大的截圖工具&#xff0c;也可以讓你將截圖貼回屏幕上。常用的快捷方式&#xff1a;1、F1可以截圖&#xff0c;同時測量大小&#xff0c;設置箭頭 書寫文字等2、F3在桌面置頂顯示3、點擊圖片&#xff0c;alt可以取色&#xf…

CompletableFuture實現Excel 多個sheet頁批量導出

CompletableFuture實現Excel 多個sheet頁批量導出 文章目錄 CompletableFuture實現Excel 多個sheet頁批量導出 為什么不能直接合并文件或Sheet? 我的方案合理性 1. 操作實現步驟 1.1、導入所需要的依賴 1.2 、Excel 導入導出對象 1.3、異步生成 Excel 文件到指定路徑 1.4、合并…

搭建本地 Git 服務器

以下是搭建本地 Git 服務器的通用步驟&#xff0c;支持團隊協作或私有倉庫管理&#xff1a;方法 1&#xff1a;基于 SSH 的簡單部署&#xff08;適合小團隊&#xff09; 步驟 1&#xff1a;安裝 Git 在服務器上安裝 Git&#xff08;以 Ubuntu 為例&#xff09;&#xff1a; sud…

【Matplotlib】中文顯示問題

中文顯示問題本地Mac上作圖&#xff0c;可以方便地實現中文字體顯示。比如在Jupter中&#xff0c;通過&#xff1a;方法一&#xff1a;不下載字體庫即可實現中文顯示 (MAC)plt.rcParams[font.family][Arial Unicode MS]方法二&#xff1a;下載指定字體訓即可實現中文顯示plt.rc…