豹哥嵌入式講堂: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
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...