性无码一区二区三区在线观看,少妇被爽到高潮在线观看,午夜精品一区二区三区,无码中文字幕人妻在线一区二区三区,无码精品国产一区二区三区免费

痞子衡
認證:普通會員
所在專題目錄 查看專題
從文件角度看Cortex-M開發(fā)(1) - 源文件
從文件角度看Cortex-M開發(fā)(2) - 鏈接文件
從文件角度看Cortex-M開發(fā)(3) - 工程文件
從文件角度看Cortex-M開發(fā)(4) - 可重定向文件
從文件角度看Cortex-M開發(fā)(5) - 映射文件
從文件角度看Cortex-M開發(fā)(6) - 可執(zhí)行文件
作者動態(tài) 更多
有時候MCU片內(nèi)合封Flash就是個黑盒子!
3天前
有人說高性能MCU片內(nèi)合封Flash不可靠?
5天前
竟有可以從AP直接加載程序啟動的MCU!
2星期前
初識恩智浦MCU里最“浪漫”外設(shè)XBAR
04-15 09:24
MCU偵探社:更換大容量啟動Flash,二級App異常了?
03-21 14:13

從文件角度看Cortex-M開發(fā)(1) - 源文件

大家好,我是痞子衡,是正經(jīng)搞技術(shù)的痞子。今天痞子衡給大家講的是嵌入式開發(fā)里的source文件。

眾所周知,嵌入式開發(fā)屬于偏底層的開發(fā),主要編程語言是C和匯編。所以本文要講的source文件主要指的就是c文件和匯編文件。

盡管在平常開發(fā)中,我們都只會關(guān)注自己創(chuàng)建的.c/.h/.s源文件,但實際上我們不知不覺中也跟很多不是我們創(chuàng)建的源文件在打交道,那么問題來了,一個完整的嵌入式工程(以基于ARM Cortex-M控制器的工程為例)到底會包含哪些source文件呢?

現(xiàn)在就到了痞子衡的show time了,痞子衡將這些文件按來源分為五類十種,下面痞子衡按類別逐一分析這些文件:

第一類:Provided by Committee

第一類文件由C標準委員會提供,該類文件伴隨著標準的發(fā)布而逐漸壯大。該類文件主要就是一種,即C標準庫。

1. C standard Library  

大家都知道C語言是有標準的,常見的C標準有ANSI C(C89)、C99、C11,而C標準函數(shù)庫(C Standard library)就是所有符合C標準的頭文件的集合,以及常用的函數(shù)庫實現(xiàn)程序。C標準庫由Committee制訂發(fā)布,通常會被包含在IDE里。列舉一些常見文件和函數(shù)如下,是不是覺得似曾相識?

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

第二類:Provided by IDE(Compiler)

第二類文件由IDE提供,C語言是編譯型語言,需要編譯器將C程序匯編成機器碼,所有便有了一些跟編譯器特性相關(guān)的函數(shù)庫。

2. Compiler Library  

我們在開發(fā)嵌入式應(yīng)用時需要借助集成開發(fā)環(huán)境(IDE),常見的IDE有GCC(GNUC),Keil MDK(ARMCC),IAR EWARM(ICCARM),這些IDE都有配套的C編譯器,這些編譯器是各有特色的,為了充分展示各編譯器特色,配套的函數(shù)庫便應(yīng)運而生。

編譯器函數(shù)庫是因IDE而異的,此處僅講一個例子以供參考,需要了解更多需查看各IDE手冊。

以IAR EWARM里的DLib_Product_string.h文件為例,該文件中重定義了memcpy的實現(xiàn):

#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提供,嵌入式程序的執(zhí)行靠的是控制器內(nèi)核(此處指的內(nèi)核便是ARM內(nèi)核),ARM公司在設(shè)計內(nèi)核時,提供了一些內(nèi)核模塊的接口,開發(fā)者可以通過這些接口訪問內(nèi)核資源,CMSIS header里就是這些內(nèi)核模塊資源的接口。

3. CMSIS header  

完整的CMSIS header目錄應(yīng)該是下面這個樣子,而必須要關(guān)注的只有\(zhòng)CMSIS\Include下面的core_cmx.h文件

\CMSIS
     \Core      
     \DAP            /* ARM debugger實現(xiàn) */
     \Driver         /* ARM統(tǒng)一的常用外設(shè)driver API */
     \DSP_Lib        /* ARM優(yōu)化實現(xiàn)的DSP Lib */
     \Include        /* ARM內(nèi)核資源接口 */
            \arm_xx.h
            \cmsis_xx.h
            \core_cmx.h
     \Lib            /* ARM優(yōu)化實現(xiàn)的標準Lib */
     \Pack
     \RTOS           /* ARM推出的RTOS- RTX */
     \RTOS2
     \SVD
     \Utilities

core_cmx.h文件里定義了內(nèi)核資源接口,里面最常用的三大模塊是SCB,SysTick,NVIC,一個嵌入式開發(fā)的老手看到這些模塊應(yīng)該要向痞子衡揮手示意,來,讓痞子衡看見你們的雙手~~~

第四類:Provided by Chip Producer

第四類文件是由ARM芯片生產(chǎn)商提供,我們在選型一個ARM芯片時,除了看ARM內(nèi)核類型外,還得看芯片內(nèi)部外設(shè)資源,是這些外設(shè)導(dǎo)致了ARM芯片差異,于是便有了各大ARM廠商爭奇斗艷,比如NXP(Freescale), ST, Microchip(Atmel),ARM廠商賦予了ARM芯片各種外設(shè)資源,同時也會提供這些外設(shè)資源的接口。該類別下文件有四種:

4. device.h:芯片頭文件,主要包含中斷號定義(xx_IRQn)、外設(shè)模塊類型定義(xx_Type) 、外設(shè)基地址定義(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;
////////////////////////////////////////////////////
// 外設(shè)寄存器定義
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)
////////////////////////////////////////////////////
// 外設(shè)基地址定義
#define WWDT0_BASE                    (0x5000E000u)

5. startup_device.s:芯片中斷向量表文件,主要包含中斷向量表定義(DCD xx_Handler) ,以及各中斷服務(wù)程序的弱定義(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
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 中斷服務(wù)程序弱定義
        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:芯片系統(tǒng)初始化文件,主要包含全局變量SystemCoreClock定義(提供芯片內(nèi)核默認工作頻率)、SystemInit()函數(shù)定義(完成最基本的系統(tǒng)初始化,比如WDOG初始化,RAM使能等,這部分因芯片設(shè)計而異)。

7. device SDK Library:官方提供的芯片外設(shè)SDK driver包文件,有了這個SDK包可以直接使用片內(nèi)外設(shè)設(shè)計自己的應(yīng)用,而不需要查看芯片手冊里的外設(shè)模塊寄存器去重寫外設(shè)驅(qū)動。當然并不是每個廠商都有完善的SDK包,這取決于各廠商對軟件服務(wù)的重視程度。

// 來自于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

第五類文件是開發(fā)者自己創(chuàng)建,用于實現(xiàn)開發(fā)者自己的嵌入式應(yīng)用,分為應(yīng)用系統(tǒng)啟動文件,應(yīng)用系統(tǒng)初始化文件,應(yīng)用文件。其中應(yīng)用系統(tǒng)啟動和初始化文件屬于main函數(shù)之前的文件,一般可以通用,大部分開發(fā)者并不關(guān)心其具體內(nèi)容,但是了解其過程可以加深對嵌入式系統(tǒng)結(jié)構(gòu)的理解。

8. reset.s:應(yīng)用系統(tǒng)復(fù)位啟動文件,了解ARM原理的都知道,image前8個字節(jié)數(shù)據(jù)分別是芯片上電的初始SP, PC,其中PC指向的便是本文件里的Reset_Handler,這是芯片執(zhí)行的第一個函數(shù)入口,該函數(shù)主要用于完成應(yīng)用系統(tǒng)初始化工作,包含應(yīng)用中斷向量表重定向、調(diào)用芯片系統(tǒng)初始化、ARM系統(tǒng)寄存器rx清零、初始化應(yīng)用程序各數(shù)據(jù)段、初始化ARM系統(tǒng)中斷、跳轉(zhuǎn)main函數(shù)。

// 一段經(jīng)典的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:應(yīng)用系統(tǒng)初始化文件,該文件里主要包含兩個初始化函數(shù),init_data_bss()、  init_interrupts(),data, bss段數(shù)據(jù)的初始化是為了保證嵌入式系統(tǒng)中所有全局變量能有一個開發(fā)者指定的初值。由于data,bss段的位置是在鏈接階段確定的,所以此處需要配合linker文件才能找到正確的data,bss位置,linker文件是因IDE而異的,所有本文件要想做到通用,必須增加各IDE條件編譯,此處僅以IAR下的實現(xiàn)為例:

//基于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段 (執(zhí)行在RAM中的函數(shù)(由IAR指定的__ramfunc修飾的函數(shù))).
    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:應(yīng)用文件,此處便是主函數(shù)以及各功能函數(shù)的集合了,嵌入式老司機們,請開始你的表演~~~

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

至此,嵌入式開發(fā)里的各種來源的source文件痞子衡便介紹完畢了,掌聲在哪里~~~

聲明:本內(nèi)容為作者獨立觀點,不代表電子星球立場。未經(jīng)允許不得轉(zhuǎn)載。授權(quán)事宜與稿件投訴,請聯(lián)系:editor@netbroad.com
覺得內(nèi)容不錯的朋友,別忘了一鍵三連哦!
贊 4
收藏 4
關(guān)注 41
成為作者 賺取收益
全部留言
0/200
成為第一個和作者交流的人吧