豹哥嵌入式講堂:ARM開發之文件詳解(1)- source文件

来源:https://www.cnblogs.com/henjay724/archive/2018/01/03/8183257.html
-Advertisement-
Play Games

大家好,我是豹哥,獵豹的豹,犀利哥的哥。今天豹哥給大家講的是 嵌入式開發里的source文件 。 眾所周知,嵌入式開發屬於偏底層的開發,主要編程語言是C和彙編。所以本文要講的source文件主要指的就是c文件和彙編文件。 儘管在平常開發中,我們都只會關註自己創建的.c/.h/.s源文件,但實際上我們 ...



  大家好,我是豹哥,獵豹的豹,犀利哥的哥。今天豹哥給大家講的是嵌入式開發里的source文件

  眾所周知,嵌入式開發屬於偏底層的開發,主要編程語言是C和彙編。所以本文要講的source文件主要指的就是c文件和彙編文件。
  儘管在平常開發中,我們都只會關註自己創建的.c/.h/.s源文件,但實際上我們不知不覺中也跟很多不是我們創建的源文件在打交道,那麼問題來了,一個完整的嵌入式工程(以基於ARM Cortex-M控制器的工程為例)到底會包含哪些source文件呢?
  現在就到了豹哥的show time了,豹哥將這些文件按來源分為五類十種,下麵豹哥按類別逐一分析這些文件:

第一類:Provided by Committee

  第一類文件由C標準委員會提供,該類文件伴隨著標準的發佈而逐漸壯大。該類文件主要就是一種,即C標準庫。
1. C standard Library
  大家都知道C語言是有標準的,常見的C標準有ANSI C(C89)、C99、C11,而C標準函數庫(C Standard library)就是所有符合C標準的頭文件的集合,以及常用的函數庫實現程式。C標準庫由Committee制訂發佈,通常會被包含在IDE里。列舉一些常見文件和函數如下,是不是覺得似曾相識?

/* 常用文件 */ assert.h,stdio.h,stddef.h,stdint.h,string.h ...
/* 常用定義 */ bool,NULL,uint8_t,uint16_t,uint32_t...
/* 常用函數 */ assert(),printf(),memset(),memcpy()...

第二類:Provided by IDE(Compiler)

  第二類文件由IDE提供,C語言是編譯型語言,需要編譯器將C程式彙編成機器碼,所有便有了一些跟編譯器特性相關的函數庫。
2. Compiler Library
  我們在開發嵌入式應用時需要藉助集成開發環境(IDE),常見的IDE有GCC(GNUC),Keil MDK(ARMCC),IAR EWARM(ICCARM),這些IDE都有配套的C編譯器,這些編譯器是各有特色的,為了充分展示各編譯器特色,配套的函數庫便應運而生。
  編譯器函數庫是因IDE而異的,此處僅講一個例子以供參考,需要瞭解更多需查看各IDE手冊。
  以IAR EWARM里的DLib_Product_string.h文件為例,該文件中重定義了memcpy的實現:

  #define _DLIB_STRING_SKIP_INLINE_MEMCPY
  #pragma inline=forced_no_body
  __EFF_NENR1NW2R1 __ATTRIBUTES void * memcpy(void * _D, const void * _S, size_t _N)
  {
    __aeabi_memcpy(_D, _S, _N);
    return _D;
  }

第三類:Provided by ARM

  第三類文件由ARM提供,嵌入式程式的執行靠的是控制器內核(此處指的內核便是ARM內核),ARM公司在設計內核時,提供了一些內核模塊的介面,開發者可以通過這些介面訪問內核資源,CMSIS header里就是這些內核模塊資源的介面。
3. CMSIS header
  完整的CMSIS header目錄應該是下麵這個樣子,而必須要關註的只有\CMSIS\Include下麵的core_cmx.h文件

\CMSIS
     \Core      
     \DAP            /* ARM debugger實現 */
     \Driver         /* ARM統一的常用外設driver API */
     \DSP_Lib        /* ARM優化實現的DSP Lib */
     \Include        /* ARM內核資源介面 */
            \arm_xx.h
            \cmsis_xx.h
            \core_cmx.h
     \Lib            /* ARM優化實現的標準Lib */
     \Pack
     \RTOS           /* ARM推出的RTOS- RTX */
     \RTOS2
     \SVD
     \Utilities

  core_cmx.h文件里定義了內核資源介面,裡面最常用的三大模塊是SCB,SysTick,NVIC,一個嵌入式開發的老手看到這些模塊應該要向豹哥揮手示意,來,讓豹哥看見你們的雙手~~~

第四類:Provided by Chip Producer

  第四類文件是由ARM晶元生產商提供,我們在選型一個ARM晶元時,除了看ARM內核類型外,還得看晶元內部外設資源,是這些外設導致了ARM晶元差異,於是便有了各大ARM廠商爭奇鬥艷,比如NXP(Freescale), ST, Microchip(Atmel),ARM廠商賦予了ARM晶元各種外設資源,同時也會提供這些外設資源的介面。
  該類別下文件有四種:
4. device.h:晶元頭文件,主要包含中斷號定義(xx_IRQn)、外設模塊類型定義(xx_Type) 、外設基地址定義(xx_BASE)。

/////////////////////////////////////////////////////
// 中斷號定義
typedef enum IRQn {
  NotAvail_IRQn                = -128,
  /* Core interrupts */
  NonMaskableInt_IRQn          = -14,
  HardFault_IRQn               = -13,
  ...
  SysTick_IRQn                 = -1,
  /* Device specific interrupts */
  WDT0_IRQn                = 0,
  ...
} IRQn_Type;
////////////////////////////////////////////////////
// 外設寄存器定義
typedef struct {
  __IO uint32_t MOD;
  ...
  __IO uint32_t WINDOW;
} WWDT_Type;
#define WWDT_WINDOW_WINDOW_MASK       (0xFFFFFFU)
#define WWDT_WINDOW_WINDOW_SHIFT      (0U)
#define WWDT_WINDOW_WINDOW(x)         (((uint32_t)(((uint32_t)(x)) << WWDT_WINDOW_WINDOW_SHIFT)) & WWDT_WINDOW_WINDOW_MASK)
////////////////////////////////////////////////////
// 外設基地址定義
#define WWDT0_BASE                    (0x5000E000u)

5. startup_device.s:晶元中斷向量表文件,主要包含中斷向量表定義(DCD xx_Handler) ,以及各中斷服務程式的弱定義(PUBWEAK)。 Note:該文件因編譯器而異。

;;基於IAR的startup_device.s文件
        MODULE  ?cstartup
        ;; Forward declaration of sections.
        SECTION CSTACK:DATA:NOROOT(3)
        SECTION .intvec:CODE:NOROOT(2)
        PUBLIC  __vector_table
        PUBLIC  __Vectors_End
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 中斷向量表定義
        DATA
__vector_table
        DCD     sfe(CSTACK)
        DCD     Reset_Handler
        DCD     NMI_Handler
        DCD     HardFault_Handler
        ...
        DCD     SysTick_Handler
        ; External Interrupts
        DCD     WDT0_IRQHandler
        ...
__Vectors_End
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 中斷服務程式弱定義
        THUMB
        PUBWEAK WDT0_IRQHandler
        PUBWEAK WDT0_DriverIRQHandler
        SECTION .text:CODE:REORDER:NOROOT(2)
WDT0_IRQHandler
        LDR     R0, =WDT0_DriverIRQHandler
        BX      R0
WDT0_DriverIRQHandler
        B .
        END

6. system_device.c/h:晶元系統初始化文件,主要包含全局變數SystemCoreClock定義(提供晶元內核預設工作頻率)、SystemInit()函數定義(完成最基本的系統初始化,比如WDOG初始化,RAM使能等,這部分因晶元設計而異)。
7. device SDK Library:官方提供的晶元外設SDK driver包文件,有了這個SDK包可以直接使用片內外設設計自己的應用,而不需要查看晶元手冊里的外設模塊寄存器去重寫外設驅動。當然並不是每個廠商都有完善的SDK包,這取決於各廠商對軟體服務的重視程度。

// 來自於NXP SDK的WWDT driver API
void WWDT_GetDefaultConfig(wwdt_config_t *config);
void WWDT_Init(WWDT_Type *base, const wwdt_config_t *config);
void WWDT_Deinit(WWDT_Type *base);
void WWDT_ClearStatusFlags(WWDT_Type *base, uint32_t mask);
void WWDT_Refresh(WWDT_Type *base);

第五類:Created by Developer

  第五類文件是開發者自己創建,用於實現開發者自己的嵌入式應用,分為應用系統啟動文件,應用系統初始化文件,應用文件。其中應用系統啟動和初始化文件屬於main函數之前的文件,一般可以通用,大部分開發者並不關心其具體內容,但是瞭解其過程可以加深對嵌入式系統結構的理解。
8. reset.s: 應用系統複位啟動文件,瞭解ARM原理的都知道,image前8個位元組數據分別是晶元上電的初始SP, PC,其中PC指向的便是本文件里的Reset_Handler,這是晶元執行的第一個函數入口,該函數主要用於完成應用系統初始化工作,包含應用中斷向量表重定向、調用晶元系統初始化、ARM系統寄存器rx清零、初始化應用程式各數據段、初始化ARM系統中斷、跳轉main函數。

// 一段經典的startup code
        SECTION .noinit : CODE
        THUMB
        import SystemInit
        import init_data_bss
        import main
        import CSTACK$$Limit
        import init_interrupts
        EXTERN __vector_table
        REQUIRE __vector_table
#define SCB_BASE            (0xE000ED00)
#define SCB_VTOR_OFFSET     (0x00000008)
        PUBLIC  Reset_Handler
        EXPORT  Reset_Handler
Reset_Handler
        // Mask interrupts
        cpsid   i
        // Set VTOR register in SCB first thing we do.
        ldr     r0,=__vector_table
        ldr     r1,=SCB_BASE
        str     r0,[r1, #SCB_VTOR_OFFSET]
        // Init the rest of the registers
        ldr     r2,=0
        ldr     r3,=0
        ldr     r4,=0
        ldr     r5,=0
        ldr     r6,=0
        ldr     r7,=0
        mov     r8,r7
        mov     r9,r7
        mov     r10,r7
        mov     r11,r7
        mov     r12,r7
        // Initialize the stack pointer
        ldr     r0,=CSTACK$$Limit
        mov     r13,r0
        // Call the CMSIS system init routine
        ldr     r0,=SystemInit
        blx     r0
        // Init .data and .bss sections
        ldr     r0,=init_data_bss
        blx     r0
        // Init interrupts
        ldr     r0,=init_interrupts
        blx     r0
        // Unmask interrupts
        cpsie   i
        // Set argc and argv to NULL before calling main().
        ldr     r0,=0
        ldr     r1,=0
        ldr     r2,=main
        blx     r2
__done
        B       __done
        END

9. startup.c:應用系統初始化文件,該文件里主要包含兩個初始化函數,init_data_bss()、 init_interrupts(),data, bss段數據的初始化是為了保證嵌入式系統中所有全局變數能有一個開發者指定的初值。由於data,bss段的位置是在鏈接階段確定的,所以此處需要配合linker文件才能找到正確的data,bss位置,linker文件是因IDE而異的,所有本文件要想做到通用,必須增加各IDE條件編譯,此處僅以IAR下的實現為例:

//基於IAR的startup.c文件
#if (defined(__ICCARM__))
#pragma section = ".intvec"
#pragma section = ".data"
#pragma section = ".data_init"
#pragma section = ".bss"
#pragma section = "CodeRelocate"
#pragma section = "CodeRelocateRam"
#endif

void init_data_bss(void)
{
#if defined(__ICCARM__)
    uint8_t *data_ram, *data_rom, *data_rom_end;
    uint8_t *bss_start, *bss_end;
    uint8_t *code_relocate_ram, *code_relocate, *code_relocate_end;
    uint32_t n;
// 初始化data段 .data section (initialized data section)
    data_ram = __section_begin(".data");
    data_rom = __section_begin(".data_init");
    data_rom_end = __section_end(".data_init");
    n = data_rom_end - data_rom;
    if (data_ram != data_rom)
    {
        while (n--)
        {
            *data_ram++ = *data_rom++;
        }
    }
// 初始化bss段 .bss section (zero-initialized data)
    bss_start = __section_begin(".bss");
    bss_end = __section_end(".bss");
    n = bss_end - bss_start;
    while (n--)
    {
        *bss_start++ = 0;
    }
// 初始化CodeRelocate段 (執行在RAM中的函數(由IAR指定的__ramfunc修飾的函數)).
    code_relocate_ram = __section_begin("CodeRelocateRam");
    code_relocate = __section_begin("CodeRelocate");
    code_relocate_end = __section_end("CodeRelocate");
    n = code_relocate_end - code_relocate;
    while (n--)
    {
        *code_relocate_ram++ = *code_relocate++;
    }
#endif
}

void init_interrupts(void)
{
    NVIC_ClearEnabledIRQs();
    NVIC_ClearAllPendingIRQs();
}

10. application.c/h: 應用文件,此處便是主函數以及各功能函數的集合了,嵌入式老司機們,請開始你的表演~~~

void taskn(void)
{
    ...
}
int main(void)
{
    printf("hello world\r\n");
    taskn();
    ...
    return 0;
}

  至此,嵌入式開發里的各種來源的source文件豹哥便介紹完畢了,掌聲在哪裡~~~


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Linux的root密碼破解不像Windows的密碼破解,windows的登錄密碼破解需要介入工具進行破解。Centos6和centos7的密碼方法也是不一樣的,具體如下: 首先是Centos 6的Root密碼破解 開機按esc 按 e 鍵進入編輯模式 選擇Kernel /vmlinz-2.6.32 ...
  • 上章分析了uboot啟動流程後,接下來便來配置新的單板,實現nor、nand啟動 1.首先在uboot里新建單板2440 1.1將2410的單板文件夾拷貝成2440: 然後將smdk2440下的smdk2410.c改為smdk2440.c,以及修改更改好的Makefile 1.2 將2410的頭文件 ...
  • 這是我在項目實戰中的個人總結,寫的倉促,有些東西也不一定准確,有些是自己推斷的,還希望各位多多指教,多多評論。 關於QCombox如果不需要自定義,其實寫UI是很簡單的。 創建實例:QComboBox* m_pMicrophoneCombox = new QComboBox; 我是用的QSS去的寫樣 ...
  • 安裝apache 1.安裝yum -y install httpd 2.設置apache服務開機啟動systemctl enable httpd.service 3.開啟apache服務systemctl start httpd.service 使用公網訪問能看到apache就說明安裝成功;如果未成 ...
  • 1、顯示硬碟及所屬分區情況。在終端視窗中輸入如下命令 可以看到要掛在的2T磁碟 2、對硬碟進行分區。在終端視窗中輸入如下命令: 如下圖所示:在Command (m for help)提示符後面輸入m顯示一個幫助菜單。 在Command (m for help)提示符後面輸入n,執行 add a ne ...
  • 在向伺服器拷貝文件的時候卡死,直接任務管理器結束應用程式,但是隨之引發一個問題,就是之後不能從本地向伺服器拷貝文件了,只能伺服器自己複製粘貼。 解決辦法重啟rdpclip.exe,先在任務管理器中結束rdpclip.exe 進程,然後重新運行(開始->運行->rdpclip.exe ),解決問題。 ...
  • 上次介紹了ES集群搭建的方法,希望能幫助大家,這兒我再接著介紹kafka集群,接著上次搭建的效果。 首先我們來簡單瞭解下什麼是kafka和zookeeper? Apache kafka 是一個分散式的基於push-subscribe的消息系統,它具備快速、可擴展、可持久化的特點。它現在是Apache ...
  • 一個正常的UAC設備插入Android 7.0是預設打開UAC配置的,列印的log如下: 而Android4.0是沒有預設打開,是需要進行相應的配置的;這裡可以看到其驅動程式為snd-usb-audio,依據這個關鍵詞在內核中查找到如下內容: 需要在 /kernel/arch/arm/configs ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...