听痞子衡讲嵌入式开发里的project文件~

嵌入式资讯精选 2020-08-28 00:00

大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家讲的是嵌入式开发里的project文件

前面两节课里,痞子衡分别给大家介绍了嵌入式开发中的两种典型input文件:源文件(.c/.h/.s)、链接文件(.icf)。痞子衡要再次提问了,还有没有input文件呢?答案确实是有,但这次真的是有且仅有了,本文要介绍的主角project文件也属于半个input文件。为什么说是半个?因为project文件不仅包含开发者指定的input信息,还包含很多其他辅助调试的input/output信息,算是嵌入式开发中承前启后的文件。而本文侧重点在于project文件中与开发者应用相关的input信息,仅当得到了这些input信息,再加上前面介绍的source和linker文件,那么你就已经得到了application所有的信息,你可以用它们来可以生成无歧义的可执行image binary。

随着嵌入式软件工程的发展,为了应对日益复杂的需求,现代IDE的功能也越来越强大了,IDE版本更迭让人应接不暇,Keil MDK已然踏入5.0时代,IAR EWARM更是进入了8.0时代,IDE各有千秋,但本文要讲的内容却是每个IDE必须具有的基本功能,还是继续以IAR EWARM为例开始今天的内容:

一、标准IDE功能

在开始今天的主题之前,痞子衡觉得有必要先简要给大家科普一下标准IDE应该具有的功能。现代IDE基本都是由组件构成,嵌入式开发中的每个阶段都对应着相应的组件,由这些组件去实现各阶段的需求。

1.1 IDE组件

标准嵌入式开发应该至少包括以下6个阶段,而IAR里对于每个阶段都有1个或多个组件:

  • 输入(IAR Editor):编辑源文件代码。
  • 编译(ICCARM、IASMARM):编译源文件代码生成可执行二进制机器码。
  • 分析(C-STAT、MISRA-C):编译过程中检查代码中潜在的问题。
  • 链接(ILINK):链接可执行二进制机器码到指定ARM存储空间地址。
  • 下载(I-jet、flashloader):将链接好的可执行二进制机器码下载进芯片内部非易失性存储器。
  • 调试(C-SPY、C-RUN):在线调试代码在芯片中执行情况。

project文件主要用来记录整合上述6个阶段的所有开发需求。

1.2 IDE文件类型

既然IDE有很多组件,那么同时也会存在不同类型的文件以存储这些组件的所需要的信息。IAR里支持的文件扩展类型非常多,痞子衡在这里仅列举你所创建的工程根目录下的与工程同名的扩展文件,相信你一定会觉得眼熟。

.eww           // Workspace file
.ewp // IAR Embedded Workbench project
.ewd // Project settings for C-SPY
.ewt // Project settings for C-STAT and C-RUN</td>
.dep // Dependency information

本文要讲的内容都包含在.ewp文件里,ewp文件记录了开发者为应用指定的不可缺少的input信息,没有这些信息,application工程是不完整的。换句话说,如果你得到了application的所有source文件和linker文件,但没有ewp文件的话,可能导致最终生成的image binary文件是不同的。

Note:更多IAR支持的扩展文件类型请查阅IAR软件安装目录下\IAR Systems\Embedded Workbench xxx\arm\doc\EWARM_IDEGuide.ENU.pdf文档里的File types一节。

二、解析project(ewp)文件

前面痞子衡铺垫了很多IDE/project基础概念,该是直奔主题的时候了,本文主角ewp工程文件到底包含哪些开发者指定的input信息?痞子衡从下面3个方面为大家揭秘:

2.1 源文件组织

一个稍微复杂一点的嵌入式工程,应用代码行数应该是以百行/千行为单位计算的(此处仅指的是由开发者自己创建的文件与代码),我们在组织代码的时候肯定不会只创建一个.c文件,单文件会导致代码功能模块结构不清晰,不方便工程的管理与维护。

当我们为工程创建多个文件时,就会涉及到一个必然问题:引用路径问题(所以路径信息就是本文要说的第一个input信息)。当源文件数目较多时,通常我们会创建不同文件夹把相同功能的源文件都放在一起,当编译器开始编译.c源文件时会搜索include语句所包含的头文件。熟悉C语言的朋友肯定清楚下面两种不同include语句的用法:

#include <file.h>           // 引用编译器类库下的头文件(IDE安装路径)
#include "file.h"           // 引用当前工程下的头文件(project路径)

所以在ewp文件里会包含路径信息,所有路径都应该列在Options->C/C++ Compiler->Preprocessor下有Additional include directories里,这个路径既可以是当前PC的绝对路径,也可以是以ewp文件为基准的相对路径,为了保证工程可以在任意PC任意位置下正常编译,推荐使用如下相对路径方式列出所有路径:

ewp当前路径:$PROJ_DIR$/
ewp下级路径:$PROJ_DIR$/xxFolder/
ewp上级路径:$PROJ_DIR$/../

说到路径问题,痞子衡在这里顺便给大家介绍一种经典的嵌入式工程文件目录组织方式:

\projectDir
\doc --放置工程文档

\bsp --放置bsp(板级)相关的source file
\linker --工程linker文件
\src --板级相关的源文件(比如pinout,clock等)
\builds\xxBuild\.ewp --工程ewp文件
.eww --工程workspace文件

\src --放置bsp无关的source file
\platform --芯片头文件及CMSIS文件
\drivers --芯片片内外设driver
\include --要被所有source引用的头文件
\startup --标准的startup code
\utilities --标准的通用函数
\middleware --独立的中间件
\components --板级外设组件driver
\application --当前应用主逻辑代码

2.2 全局宏定义

经常使用条件编译的朋友肯定知道workspace文件与project文件的关系,一个项目通常只会有一个eww文件,但却可能会有多个ewp文件,这是因为源代码里常常会有条件编译,我们有时候会给项目不同的配置从而编译出不同的结果(速度优先/面积优先,特性控制...),这些配置就是由全局宏定义来实现的,打开Options->C/C++ Compiler->Preprocessor下的Defined symbols,在框内写入你需要定义的全局宏:

MACRO1            // 等价于源文件里的#define MACRO1 (1)
MACRO2=2 // 等价于源文件里的#define MACRO2 (2)

全局宏信息就是本文要说的第二个input信息,如果全局宏信息丢失,有时候工程编译并不会报错,因为编译器在处理如下普遍用法里的条件编译语句时会默认未定义的宏为0,而在处理普遍用法里的条件编译语句则会报错,所以推荐大家使用第二种条件编译用法来规避全局宏问题。

// 普遍用法
#if MACRO
    // your code block 1
#else
    // your code block 2
#endif

// 推荐用法
#if !defined(MACRO)
    #error "No valid MACRO defined!"
#elif (MACRO == 1)
    // your code block 1
#else
    // your code block 2
#endif

2.3 编译选项

编译选项包含了编译器所需要的所有信息,代码需经过编译器编译才能生成二进制机器码,不同的编译器选项配置会生成不同的机器码,那么需要指定哪些选项呢?打开project的Options选项卡,分别设置下表item:

Position Item Description
General Options->Target-> Processor variant->Core 指定ARM内核版本
Endian mode 指定内核大小端模式
Floating point settings->FPU 指定内核支持的FPU版本
General Options->Library Configuration-> Library 选择C/C++动态链接库版本
General Options->Library Option 2-> Heap selection 选择HEAP实现版本
C/C++ Compiler-> Language 1->Language 指定编程语言类型
Language 1->C dialect 指定C语言标准
Language 1->Language conformance 选择对标准C/C++的遵循程度
Language 2->Plain 'char' is 选择对char的符号性默认处理方法
Language 2->Floating-point semantics 选择对浮点数的处理遵循C标准的程度
Code->Process mode 指定内核指令集模式
Code->Position-independence 选择要生成位置无关代码的对象
Optimizations->Level 选择优化等级

Note:更多ewp文件中option解释请查阅IAR软件安装目录下\IAR Systems\Embedded Workbench xxx\arm\doc\EWARM_IDEGuide.ENU.pdf文档里的General Options和Compiler Options俩小节。

编译设置信息就是本文要说的第三个input信息,当在project中组织好源文件并设置好正确的全局宏定义和编译选项,那么恭喜你,你的application设计工作已经基本完成了。

三、创建demo工程

为方便后续课程的进行,本节课在最后顺便创建一个demo工程,以下是demo工程的信息:

IDE:        IAR EWARM v8.11.2
Device: NXP MKL25Z128VLH4
project layout:
\D\myProject\bsp\builds\demo\demo.ewp
\D\myProject\bsp\linker\iar\KL25Z128xxx4_flash.icf
\D\myProject\bsp\src\startup_MKL25Z4.s (仅保留前16个系统中断)
\D\myProject\bsp\src\system_MKL25Z4.c (仅做关闭WDOG操作)
\D\myProject\bsp\src\system_MKL25Z4.h
\D\myProject\bsp\helloArm.eww
\D\myProject\src\platfrom\CMSIS
\D\myProject\src\platfrom\devices\MKL25Z4
\D\myProject\src\startup\reset.s
\D\myProject\src\startup\startup.c
\D\myProject\src\startup\startup.h
\D\myProject\src\application\main.c
\D\myProject\src\application\task.c
\D\myProject\src\application\task.h
// main.c
//////////////////////////////////////////////////////////
#include "task.h"
const uint32_t s_constant = 0x7f;
int main(void)
{
    uint32_t l_variable = 0x7f;
    if (s_constant == l_variable)
    {
        normal_task();
        ram_task();
        heap_task();
    }
    while (1);
}

// task.c
//////////////////////////////////////////////////////////
#include "task.h"
static    uint32_t s_variable0;
__no_init uint32_t n_variable1;
static    uint32_t s_variable2 = 0x5a;
static uint8_t s_array[16];
void normal_task(void)
{
    s_variable0 *= 2;
}
__ramfunc void ram_task(void)
{
    n_variable1++;
}
void heap_task(void)
{
    uint8_t *heap = (uint8_t *)malloc(16 * sizeof(uint8_t));
    if (heap != NULL)
    {
        memset(heap, 0xa5+s_variable2, 16);
        memcpy(s_array, heap, 16);
        s_variable0 = (uint32_t)heap;
        free(heap);
    }
}

番外一、几个小技巧

又来到痞子衡番外时间了,细心的朋友看到上表有两处标蓝,是的没错,今天的番外内容就是标蓝的项目有关。

技巧1:运行于异构双核

目前嵌入式产品越来越复杂,对MCU的性能要求也越来越高,各大ARM厂商也在不断推出性能越来越强劲的ARM MCU产品,超高主频,双核,四核MCU已经不鲜见了。对于其中的一些异构双核MCU产品,有时在开发中会有这样的需求:你有一份的middleware会被异构双核同时调用,而两个不同内核的指令集有可能是不一致的,怎么解决这个问题?有朋友会想到分别在每个核下面都编译一份binary放置于存储器不同位置,运行时各自指向对应的binary,这是一个办法,但比较浪费存储空间,且有可能会搞混淆导致误调用。有没有更好的方法?

为了能做到Cortex-M软件重用,ARM公司在设计Cortex-M处理器时为其赋予了处理器向下兼容软件二进制向上兼容特性。通俗的话来说就是在较低版本处理器上编译的代码可以在较高版本处理器上执行。所以解决方法就是选用异构双核里较低版本的内核在编译middleware,这样这份middleware可以同时被两个核调用。

技巧2:生成PIC代码

经常和bootloader打交道的朋友肯定知道,代码在经过链接阶段生成binary文件后,这个binary并不是可以放在任意位置的,必须放到linker文件指定的位置,如果位置没有放正确,可能会导致执行出错。究其原因,是因为编译器在汇编源代码时因为一些策略并不总是将所有function都汇编成位置无关代码。如果我们借助于IDE编译选项将middleware汇编成PIC代码,那么我们可以在工程中直接加入middleware的binary,然后借助linker的自定义section功能将其放置于任意某个位置,最后只要为这个middleware binary建立一个以binary首地址为基准的函数指针地址列表即可无障碍调用这个middleware。

技巧3:引用.c文件

在项目开发中,我们在一个workspace下会创建多个project,常常是因为不同project需要包含不同的.c文件以完成不同的功能。那么能不能只创建一个project呢能实现不同功能呢?当然可以!通常情况下我们在.c文件中只会用#include "xx.h"语句来引用.h头文件,其实我们也同样可以引用.c文件,比如这样#include "xx.c",只是需要注意尽量不要在.h文件中引用.c文件(除非该.h只会被一个.c文件include)。看到这里的朋友如果脑洞再大一点,你甚至可以做到工程里只需要添加一个.c文件,而其他.c文件全部由添加进工程的那个.c文件逐级(仅能单级)引用进工程。

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

1.嵌入式系统中,哪些应用正被重点关注?

2.听嵌入式大牛讲解硬核单片机编程思想!

3.软件神器TortoiseGit,让你优雅管理单片机程序版本!

4.TrustZone for Armv8-M和 TrustZone是什么关系?

5.外专业“入坑”嵌入式的开心成长记!

6.STM32中的位带操作,用好了让代码更简洁!

免责声明:本文系网络转载,版权归原作者所有。如涉及作品版权问题,请与我们联系,我们将根据您提供的版权证明材料确认版权并支付稿酬或者删除内容。

嵌入式资讯精选 掌握最鲜资讯,尽领行业新风
评论
  • 01. 什么是过程能力分析?过程能力研究利用生产过程中初始一批产品的数据,预测制造过程是否能够稳定地生产符合规格的产品。可以把它想象成一种预测。通过历史数据的分析,推断未来是否可以依赖该工艺持续生产高质量产品。客户可能会要求将过程能力研究作为生产件批准程序 (PPAP) 的一部分。这是为了确保制造过程能够持续稳定地生产合格的产品。02. 基本概念在定义制造过程时,目标是确保生产的零件符合上下规格限 (USL 和 LSL)。过程能力衡量制造过程能多大程度上稳定地生产符合规格的产品。核心概念很简单:
    优思学院 2025-01-12 15:43 471浏览
  • 新年伊始,又到了对去年做总结,对今年做展望的时刻 不知道你在2024年初立的Flag都实现了吗? 2025年对自己又有什么新的期待呢? 2024年注定是不平凡的一年, 一年里我测评了50余块开发板, 写出了很多科普文章, 从一个小小的工作室成长为科工公司。 展望2025年, 中国香河英茂科工, 会继续深耕于,具身机器人、飞行器、物联网等方面的研发, 我觉得,要向未来学习未来, 未来是什么? 是掌握在孩子们生活中的发现,和精历, 把最好的技术带给孩子,
    丙丁先生 2025-01-11 11:35 428浏览
  • PNT、GNSS、GPS均是卫星定位和导航相关领域中的常见缩写词,他们经常会被用到,且在很多情况下会被等同使用或替换使用。我们会把定位导航功能测试叫做PNT性能测试,也会叫做GNSS性能测试。我们会把定位导航终端叫做GNSS模块,也会叫做GPS模块。但是实际上他们之间是有一些重要的区别。伴随着技术发展与越发深入,我们有必要对这三个词汇做以清晰的区分。一、什么是GPS?GPS是Global Positioning System(全球定位系统)的缩写,它是美国建立的全球卫星定位导航系统,是GNSS概
    德思特测试测量 2025-01-13 15:42 447浏览
  • 随着数字化的不断推进,LED显示屏行业对4K、8K等超高清画质的需求日益提升。与此同时,Mini及Micro LED技术的日益成熟,推动了间距小于1.2 Pitch的Mini、Micro LED显示屏的快速发展。这类显示屏不仅画质卓越,而且尺寸适中,通常在110至1000英寸之间,非常适合应用于电影院、监控中心、大型会议、以及电影拍摄等多种室内场景。鉴于室内LED显示屏与用户距离较近,因此对于噪音控制、体积小型化、冗余备份能力及电气安全性的要求尤为严格。为满足这一市场需求,开关电源技术推出了专为
    晶台光耦 2025-01-13 10:42 455浏览
  • 流量传感器是实现对燃气、废气、生活用水、污水、冷却液、石油等各种流体流量精准计量的关键手段。但随着工业自动化、数字化、智能化与低碳化进程的不断加速,采用传统机械式检测方式的流量传感器已不能满足当代流体计量行业对于测量精度、测量范围、使用寿命与维护成本等方面的精细需求。流量传感器的应用场景(部分)超声波流量传感器,是一种利用超声波技术测量流体流量的新型传感器,其主要通过发射超声波信号并接收反射回来的信号,根据超声波在流体中传播的时间、幅度或相位变化等参数,间接计算流体的流量,具有非侵入式测量、高精
    华普微HOPERF 2025-01-13 14:18 443浏览
  • ARMv8-A是ARM公司为满足新需求而重新设计的一个架构,是近20年来ARM架构变动最大的一次。以下是对ARMv8-A的详细介绍: 1. 背景介绍    ARM公司最初并未涉足PC市场,其产品主要针对功耗敏感的移动设备。     随着技术的发展和市场需求的变化,ARM开始扩展到企业设备、服务器等领域,这要求其架构能够支持更大的内存和更复杂的计算任务。 2. 架构特点    ARMv8-A引入了Execution State(执行状
    丙丁先生 2025-01-12 10:30 430浏览
  •   在信号处理过程中,由于信号的时域截断会导致频谱扩展泄露现象。那么导致频谱泄露发生的根本原因是什么?又该采取什么样的改善方法。本文以ADC性能指标的测试场景为例,探讨了对ADC的输出结果进行非周期截断所带来的影响及问题总结。 两个点   为了更好的分析或处理信号,实际应用时需要从频域而非时域的角度观察原信号。但物理意义上只能直接获取信号的时域信息,为了得到信号的频域信息需要利用傅里叶变换这个工具计算出原信号的频谱函数。但对于计算机来说实现这种计算需要面对两个问题: 1.
    TIAN301 2025-01-14 14:15 76浏览
  • 随着通信技术的迅速发展,现代通信设备需要更高效、可靠且紧凑的解决方案来应对日益复杂的系统。中国自主研发和制造的国产接口芯片,正逐渐成为通信设备(从5G基站到工业通信模块)中的重要基石。这些芯片凭借卓越性能、成本效益及灵活性,满足了现代通信基础设施的多样化需求。 1. 接口芯片在通信设备中的关键作用接口芯片作为数据交互的桥梁,是通信设备中不可或缺的核心组件。它们在设备内的各种子系统之间实现无缝数据传输,支持高速数据交换、协议转换和信号调节等功能。无论是5G基站中的数据处理,还是物联网网关
    克里雅半导体科技 2025-01-10 16:20 424浏览
  • 随着全球向绿色能源转型的加速,对高效、可靠和环保元件的需求从未如此强烈。在这种背景下,国产固态继电器(SSR)在实现太阳能逆变器、风力涡轮机和储能系统等关键技术方面发挥着关键作用。本文探讨了绿色能源系统背景下中国固态继电器行业的前景,并强调了2025年的前景。 1.对绿色能源解决方案日益增长的需求绿色能源系统依靠先进的电源管理技术来最大限度地提高效率并最大限度地减少损失。固态继电器以其耐用性、快速开关速度和抗机械磨损而闻名,正日益成为传统机电继电器的首选。可再生能源(尤其是太阳能和风能
    克里雅半导体科技 2025-01-10 16:18 319浏览
  • 根据Global Info Research(环洋市场咨询)项目团队最新调研,预计2030年全球无人机电池和电源产值达到2834百万美元,2024-2030年期间年复合增长率CAGR为10.1%。 无人机电池是为无人机提供动力并使其飞行的关键。无人机使用的电池类型因无人机的大小和型号而异。一些常见的无人机电池类型包括锂聚合物(LiPo)电池、锂离子电池和镍氢(NiMH)电池。锂聚合物电池是最常用的无人机电池类型,因为其能量密度高、设计轻巧。这些电池以输出功率大、飞行时间长而著称。不过,它们需要
    GIRtina 2025-01-13 10:49 161浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦