0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

从文件角度了解Cortex-M开发(1)

电子设计 来源:电子设计 作者:电子设计 2020-10-30 10:44 次阅读

今天痞子衡给大家讲的是嵌入式开发里的 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)


{


// Your task code


}


int main(void)


{


printf("hello world/r/n");


taskn();


...


return 0;


}


至此,嵌入式开发里的各种来源的 source 文件痞子衡便介绍完毕了,掌声在哪里~~~

审核编辑 黄昊宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Cortex-M
    +关注

    关注

    2

    文章

    229

    浏览量

    29761
收藏 人收藏

    评论

    相关推荐

    如何使用Ozone分析Cortex-M异常

    Ozone可以帮助用户快速分析和查找导致CPU故障的软件bug。本文解释如何使用Ozone的调试功能,深入了解Cortex-M架构上的这些错误。
    的头像 发表于 11-29 11:14 715次阅读
    如何使用Ozone分析<b class='flag-5'>Cortex-M</b>异常

    度了解SiC的晶体结构

    SiC是由硅(Si)和碳(C)按1:1的化学计量比组成的晶体,因其内部结构堆积顺序的不同,形成不同的SiC多型体,本篇章带你了解SiC的晶体结构及其可能存在的晶体缺陷。
    的头像 发表于 11-14 14:57 613次阅读
    深<b class='flag-5'>度了解</b>SiC的晶体结构

    【RA-Eco-RA2E1-48PIN-V1.0开发板试用】RA-Eco-RA2E1-48PIN-V1.0开发板基于Keil MDK环境搭建

    与 RA2L1 产品群引脚和外围设备兼容,特别适用于电池供电应用以及空间受限应用,以及其他需要高性能和低功耗的系统。 RA2L1 基于 ARM® Cortex®-M23 核心(现今 A
    发表于 11-04 22:58

    树莓派Pico 2发布,搭载RP2350双核RISC-V和Arm Cortex-M33微控制器!

    复杂得多的设计,具有: – 两个 150MHz Arm Cortex-M33 内核,支持浮点和 DSP – 内置 520KB SRAM – 围绕 Arm TrustZone for Cortex-M
    发表于 08-13 10:07

    使用Keil uVision对TLE9893_2QK Evalkit进行编程,显示\"未找到Cortex-M SW设备\",为什么?

    我正在使用 Keil uVision 对 TLE9893_2QK Evalkit 进行编程。 当我尝试调试时,得到以下错误信息。 我还收到一个窗口,显示\"未找到 Cortex-M SW
    发表于 06-03 08:10

    stm32单片机学习路线

    ARM体系结构和Cortex-M核:STM32是基于ARM Cortex-M核的单片机,了解ARM体系结构和Cortex-M核的特性和架构可以帮助你更好地理解STM32的工作原理和特点
    发表于 05-10 15:34

    请问cortex-M7核单片机主要应用在哪些领域?

    看到st和nxp的M7核单片机,动不动几百兆的主频,有的还要外置DDR,还有的成本低于1刀。想知道这些单片机的目标应用场合是哪些? 单片机发展,51过渡到cortex
    发表于 04-17 07:49

    嵌入式微处理器的架构分为哪几类型

    首先,让我们宏观的角度了解嵌入式微处理器的架构分类。它们主要可以分为以下几类
    的头像 发表于 04-07 15:25 687次阅读

    CW32F003E4芯片入门学习:1.开发环境安装

    、学生、学者等群体非商业免费评估和使用。 没有代码大小限制。 支持Arm Compiler 6:可为所有基于Arm Cortex-M的产品提供精简的代码和强大的性能。 可访问超过9500款支持
    的头像 发表于 03-27 09:27 565次阅读
    CW32F003E4芯片入门学习:<b class='flag-5'>1</b>.<b class='flag-5'>开发</b>环境安装

    Cortex-M0+内核介绍

    和8位的价位实现32位性能。处理器的低门数使其能够部署在需要简单功能的应用中。 作为ARM Cortex-M处理器系列的最新成员,32位Cortex-M0+处理器采用了低成本90纳米低功耗(LP)工艺,耗电量仅9μA/MHz,约为主流8位或16位处理器的
    的头像 发表于 03-27 09:13 1053次阅读
    <b class='flag-5'>Cortex-M</b>0+内核介绍

    Cortex-M3芯片有哪些

    Cortex-M3芯片是一款基于ARM架构的低功耗、高性能的嵌入式处理器。目前市面上有众多厂商生产了基于Cortex-M3内核的芯片,如意法半导体的STM32F系列、恩智浦半导体的LPC1800系列等。这些芯片广泛应用于工业控制、智能家居、物联网等领域。
    的头像 发表于 03-11 17:07 1592次阅读

    Cortex-M85内核单片机如何快速上手

    2022年4月,Arm推出了全新的MCU级内核Cortex-M85。截止目前(2024年2月),Cortex-M85是最新、最强的Cortex-M内核。
    发表于 02-29 09:35 745次阅读
    <b class='flag-5'>Cortex-M</b>85内核单片机如何快速上手

    强大的Arm® Cortex®-M3内核(下)

    经过前一期的芝识课堂,我们了解了东芝MCU产品所基于Arm Cortex-M3内核的基本结构和寄存器分配的细节。
    的头像 发表于 01-25 09:25 1251次阅读
    强大的Arm® <b class='flag-5'>Cortex</b>®-<b class='flag-5'>M</b>3内核(下)

    请问mbed物联网操作系统会成为cortex-m中的android吗?

    mbed 物联网操作系统会成为cortex-m中的android吗?
    发表于 01-17 07:14

    Arm Cortex-M52的主要特性和规格

    Arm Cortex-M52是一款采Arm Helium 技术的新型微控制器内核,旨在将AI功能引入更小、成本更低的物联网设备,而不是基于Arm Cortex-M55内核的SoC,Arm Cortex-M52架构如下图所示。
    的头像 发表于 01-02 11:12 1490次阅读
    Arm <b class='flag-5'>Cortex-M</b>52的主要特性和规格