听痞子衡讲嵌入式开发里的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中的位带操作,用好了让代码更简洁!

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

嵌入式资讯精选 掌握最鲜资讯,尽领行业新风
评论
  • 一、SAE J1939协议概述SAE J1939协议是由美国汽车工程师协会(SAE,Society of Automotive Engineers)定义的一种用于重型车辆和工业设备中的通信协议,主要应用于车辆和设备之间的实时数据交换。J1939基于CAN(Controller Area Network)总线技术,使用29bit的扩展标识符和扩展数据帧,CAN通信速率为250Kbps,用于车载电子控制单元(ECU)之间的通信和控制。小北同学在之前也对J1939协议做过扫盲科普【科普系列】SAE J
    北汇信息 2024-12-11 15:45 114浏览
  • 习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习笔记&记录学习习笔记&记学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记
    youyeye 2024-12-12 10:13 46浏览
  • 首先在gitee上打个广告:ad5d2f3b647444a88b6f7f9555fd681f.mp4 · 丙丁先生/香河英茂工作室中国 - Gitee.com丙丁先生 (mr-bingding) - Gitee.com2024年对我来说是充满挑战和机遇的一年。在这一年里,我不仅进行了多个开发板的测评,还尝试了多种不同的项目和技术。今天,我想分享一下这一年的故事,希望能给大家带来一些启发和乐趣。 年初的时候,我开始对各种开发板进行测评。从STM32WBA55CG到瑞萨、平头哥和平海的开发板,我都
    丙丁先生 2024-12-11 20:14 78浏览
  • 时源芯微——RE超标整机定位与解决详细流程一、 初步测量与问题确认使用专业的电磁辐射测量设备,对整机的辐射发射进行精确测量。确认是否存在RE超标问题,并记录超标频段和幅度。二、电缆检查与处理若存在信号电缆:步骤一:拔掉所有信号电缆,仅保留电源线,再次测量整机的辐射发射。若测量合格:判定问题出在信号电缆上,可能是电缆的共模电流导致。逐一连接信号电缆,每次连接后测量,定位具体哪根电缆或接口导致超标。对问题电缆进行处理,如加共模扼流圈、滤波器,或优化电缆布局和屏蔽。重新连接所有电缆,再次测量
    时源芯微 2024-12-11 17:11 115浏览
  • 全球智能电视时代来临这年头若是消费者想随意地从各个通路中选购电视时,不难发现目前市场上的产品都已是具有智能联网功能的智能电视了,可以宣告智能电视的普及时代已到临!Google从2021年开始大力推广Google TV(即原Android TV的升级版),其他各大品牌商也都跟进推出搭载Google TV操作系统的机种,除了Google TV外,LG、Samsung、Panasonic等大厂牌也开发出自家的智能电视平台,可以看出各家业者都一致地看好这块大饼。智能电视的Wi-Fi连线怎么消失了?智能电
    百佳泰测试实验室 2024-12-12 17:33 66浏览
  • 本文介绍瑞芯微RK3588主板/开发板Android12系统下,APK签名文件生成方法。触觉智能EVB3588开发板演示,搭载了瑞芯微RK3588芯片,该开发板是核心板加底板设计,音视频接口、通信接口等各类接口一应俱全,可帮助企业提高产品开发效率,缩短上市时间,降低成本和设计风险。工具准备下载Keytool-ImportKeyPair工具在源码:build/target/product/security/系统初始签名文件目录中,将以下三个文件拷贝出来:platform.pem;platform.
    Industio_触觉智能 2024-12-12 10:27 81浏览
  • 应用环境与极具挑战性的测试需求在服务器制造领域里,系统整合测试(System Integration Test;SIT)是确保产品质量和性能的关键步骤。随着服务器系统的复杂性不断提升,包括:多种硬件组件、操作系统、虚拟化平台以及各种应用程序和服务的整合,服务器制造商面临着更有挑战性的测试需求。这些挑战主要体现在以下五个方面:1. 硬件和软件的高度整合:现代服务器通常包括多个处理器、内存模块、储存设备和网络接口。这些硬件组件必须与操作系统及应用软件无缝整合。SIT测试可以帮助制造商确保这些不同组件
    百佳泰测试实验室 2024-12-12 17:45 74浏览
  • 在智能化技术快速发展当下,图像数据的采集与处理逐渐成为自动驾驶、工业等领域的一项关键技术。高质量的图像数据采集与算法集成测试都是确保系统性能和可靠性的关键。随着技术的不断进步,对于图像数据的采集、处理和分析的需求日益增长,这不仅要求我们拥有高性能的相机硬件,还要求我们能够高效地集成和测试各种算法。我们探索了一种多源相机数据采集与算法集成测试方案,能够满足不同应用场景下对图像采集和算法测试的多样化需求,确保数据的准确性和算法的有效性。一、相机组成相机一般由镜头(Lens),图像传感器(Image
    康谋 2024-12-12 09:45 81浏览
  • 铁氧体芯片是一种基于铁氧体磁性材料制成的芯片,在通信、传感器、储能等领域有着广泛的应用。铁氧体磁性材料能够通过外加磁场调控其导电性质和反射性质,因此在信号处理和传感器技术方面有着独特的优势。以下是对半导体划片机在铁氧体划切领域应用的详细阐述: 一、半导体划片机的工作原理与特点半导体划片机是一种使用刀片或通过激光等方式高精度切割被加工物的装置,是半导体后道封测中晶圆切割和WLP切割环节的关键设备。它结合了水气电、空气静压高速主轴、精密机械传动、传感器及自动化控制等先进技术,具有高精度、高
    博捷芯划片机 2024-12-12 09:16 87浏览
  • 习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习笔记&记录学习习笔记&记学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记
    youyeye 2024-12-11 17:58 88浏览
  • RK3506 是瑞芯微推出的MPU产品,芯片制程为22nm,定位于轻量级、低成本解决方案。该MPU具有低功耗、外设接口丰富、实时性高的特点,适合用多种工商业场景。本文将基于RK3506的设计特点,为大家分析其应用场景。RK3506核心板主要分为三个型号,各型号间的区别如下图:​图 1  RK3506核心板处理器型号场景1:显示HMIRK3506核心板显示接口支持RGB、MIPI、QSPI输出,且支持2D图形加速,轻松运行QT、LVGL等GUI,最快3S内开
    万象奥科 2024-12-11 15:42 88浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦