前言
介绍
开发嵌入式系统是一件令人激动的事!现代微控制器(Microcontroller Unit,MCU)以很低的成本提供了非凡的性能,因特网又提供了充足的源码和文件。将廉价的硬件平台(比如Arduino、树莓派和Beaglebone)和适当的软件(将细节抽象化,指导用户)合并起来,就可以帮助我们降低开发嵌入式系统的门槛。
但在上升到有着更严格限制的更大、更复杂系统时,这些支持却成为了束缚。嵌入式系统的工业设计师会选择科学的方法来满足各种要求(比如速度、响应、成本、重量、可靠性或能耗)。
很多硬件工具内置于MCU中:执行软件的中央处理器(Central Processing Unit,CPU)、能对事件做出快速响应的高效中断系统、存放程序与数据的快速存储器、降低高速CPU需求的特定硬件外设电路。硬件外设也能通知和控制其他外设,消除对CPU上软件的需求。MCU提供了一系列低功率模式,让设计者可以权衡性能和功耗。
其他工具则由软件提供,典型软件由C或C++编写,被编译后用处理器本地机器语言表示;软件的使用避免了运行时延迟与解释或撰写脚本的内存开销;多任务软件使用中断和调度程序在CPU上进行调度。调度程序可以是协同式的(例如状态机)或者抢占式的(例如实时内核)。
总的来说,成功的嵌入式系统设计使用外设和带轻量化上下文切换的CPU上优秀的软件来保证响应的并发性。本书的写作目的是解释如何使用行业内的标准方法来开发基于微控制器的嵌入式系统,以及如何使用现今嵌入式计算中最广泛使用的处理器架构:Arm架构。
嵌入式系统教学的挑战
在大学学习或者教授嵌入式系统课程都存在着很多挑战。首先,这个领域建立在几个学科之上:计算机工程(Computer Engineering,CPE)、电子工程(Electrical Engineering,EE)和计算机科学(Computer Science,CS)。有些读者会攻读联合学位、双学位或三学位,但大多数读者不会。其次,这些概念和解决方案都是针对嵌入式系统设计空间的,与主流的大多数课程涵盖的多用途或高性能计算设计空间不符。最后,有太多学科的知识需要覆盖,读者很容易把注意力集中在熟悉的地方,而忽略了不熟悉的地方,因为很难用有限的内容来涵盖这些学科。
挑战1:跨越电子和计算机工程与计算机科学
成功的嵌入式系统设计者需要掌握CPE、EE和CS中的多种技能,相关知识如本书目录所列。这些技能分别来自于电子和计算机工程(Electrical and Computer Engineering,ECE)和计算机科学两个专业背景。但现实却是CPE和CS课程的培养方向倾向于更高的计算性能和抽象程度(通过计算机性能的提高增加的应用程序复杂度),这增大了和嵌入式系统设计空间的差距。
下列CPE和EE的知识是读者学习嵌入式系统时需要掌握的关键内容。
• 计算机组成和汇编语言编程是理解CPU、内存、外设、中断系统的基础。
• 进行数字化设计必须理解CPU和外设电路的作用。这些数字化电路(例如GPIO、定时器和DMA)独立于CPU运行,提供了廉价的并发性。避免使用计算复杂度高的软件任务而采用相对缓慢的MCU,提供低功耗、低成本、精确的定时和可预测的性能,这是一种很好的设计理念。
• 增加外部电路比如LED、开关和传感器时需要基础的模拟电路设计和分析技能。调试时则需要用示波器或者逻辑分析仪来检查和分析系统中事件的时序。
下列CS的知识是读者学习嵌入式系统时需要掌握的关键内容。
• C语言是编写嵌入式系统的主要语言。
• 编译器和汇编语言编程则涉及CPU如何执行源码指定的工作。了解程序如何被编译和结构化能帮助我们避免错误(比如抢占),调试、设计出有效的系统并提升系统性能。
• 操作系统的任务调度程序概念使读者了解了如何在嵌入式系统的多个并发活动中共享一个CPU,包括多任务、抢占和优先次序。读者需要了解如何设计中断通信和同步来避免如数据争用风险等故障。
挑战2:以ES设计空间为目标
对每个提到的领域,实际的解决方法则由设计空间决定。大多数嵌入式系统的设计空间因其不同的驱动和限制而不同于通用和高性能计算系统。举例如下。
• 计算机组成:嵌入式处理器不需要通用或者高性能计算系统那么高的处理速度。因此不需要高速的时钟以及深处理器流水线和多层存储器系统的支持。
• 操作系统:资源丰富的Linux系统既有抢占调度程序、大量的计算和内存资源,又有硬件支持的虚拟内存系统和用户与管理员模式,不用提供嵌入式系统需要的既复杂又能耗高且昂贵的精确定时控制。读者必须将任务调度、同步和通信的概念应用于建立中断、外设和简单调度程序(不论是抢占式实时内核还是协同式调度程序)的系统中。
• 编程:嵌入式系统使用编译语言而非脚本语言或解释型语言,因为编译语言的可预测性、有效性和简洁性,所以嵌入式系统设计一般使用C和C++开发。但很多编程人员使用Java(或者脚本化语言)开发,这引发了很多嵌入式系统在底层和实现上的问题。
挑战3:提供足够(但不过量)的覆盖率
本书覆盖了以上的领域,很容易使读者更注意熟悉的地方而忽略不熟悉的地方。此外,由于读者试着运行实例代码来理解重要概念,这种嵌入式系统课程的实践特点通常减慢了教学进程。
本书尝试以足够的知识讲解来得出实际的设计空间解决方法。但本书不给出完成某项任务的所有方法,而是通过给定的限制条件提出最实际的解决办法。
给老师的建议
为何使用本书?
在本书中我以连贯并引人注目的形式提出了嵌入式系统最重要的主题。
第一,本书使用实践的方法调动读者的积极性。每一章节都阐述了基于实际MCU评估板的工作实例,这些实例在前面章节便给出,例如在第2章就展示了使用GPIO和C语言通过开关控制LED灯。
第二,本书很早就介绍了并发和响应的概念。第3章使用根据开关位置扫描LED的实例介绍了创建模块、响应和高效系统的概念。循序渐进地引入这些概念,将给读者打下研究实时内核的扎实基础。并发和响应按照如下顺序介绍。
(1)以简单的程序开始:推动开关控制LED灯、使用忙等待进行延迟。
(2)重构软件任务。
(3)协同式地调度任务。
(4)通过使用状态机跳出长操作来改进协同调度任务的响应。
(5)使用中断和事件驱动软件取代开关。
(6)使用定时器外设取代忙等待循环。
(7)优先化任务。
(8)抢占式地调度任务。
第三,本书介绍了使用外设硬件代替软件来提升性能的内容。用模拟波形生成器作为实例,它其实是一个数模转换应用,有着完全依赖于软件执行速度的时序。该实例又出现在定时器一章,使用定时器驱动的ISR更新DAC来改善定时的稳定性。最终出现在DMA章节,DMA控制器在定时器的控制下自动地将存储器缓存中的数据复制到DAC中。
第四,本书提供了由编译器以汇编语言实现的C代码,主要目的是帮助读者了解为什么自己的代码很慢、很长,以及如何改善,了解共享数据的抢占风险并且以源码和目的代码级的讲解帮助读者调试程序。本书不要求读者以汇编语言编程,尽管在以后的课程中可能会需要,这里只是给出基础知识的讲解。
课程材料的链接
本书适用于一学期或两学期课程,主要向读者讲解嵌入式系统。补充了Arm大学计划的高效嵌入式系统设计与编程教育工具(Efficient Embedded Systems Design and Programming Education Kit)。如果你是一位老师,可以通过向EDUweixin@armchina.com发送邮件来免费申请一份教育套件。本教育套件包括课件和Arm公司Keil MDK-ARM专业版软件的使用许可。但读者需要有C语言编程、数字化设计和基础电路知识作为先修课程。
目标平台
本书面向Arm Cortex-M0+处理器。处理器是一种微控制器内的组件,可以执行程序的指令。微控制器可以添加电路来为处理器计时,添加内存来存储程序和数据,添加外设来简化程序以提升性能。该处理器适用于大多数制造业中的微控制器。
目标平台是来自NXP半导体公司的FRDM-KL25Z开发板,价格低于20美元。它使用了Kinetis Lultra-low-power系列的NXP KL25Z128VLK4微控制器。该设备的特征是有Cortex-M0+处理器,可以以48MHz的速率运行,有128KB的ROM,16KB的RAM和很多外围设备。开发板中添加了USB调试接口(OpenSDA)、电源、输入和输出设备,还添加了三轴加速度计,用于检测加速度。因为可以探测重力,它也能用于检测板卡的倾斜程度。触摸板滑块可以用电容传感器测量指尖的位置。三合一输出设备包括三色(红色、绿色和蓝色)高亮度LED,这些LED可以通过控制亮度呈现出不同的颜色。
本书中的内容也可以用于其他Cortex-M0+平台。前五章基本上是独立的MCU外设,可以应用于所有的Cortex-M0+处理器。其他章节和附录则与外围设备紧密结合。NXP公司的其他Kinetis MCU使用很多与KL25Z相同的外设,可以简单地使用其他MCU和有关的FRDM评估板。针对来自不同供应商的MCU系列产品需要对实例代码进行移植。
软件开发环境
本书的软件实例用C语言编写,编译后不需操作系统即可运行。Arm公司的Keil MDK-ARM集成开发环境在本书所有实例中均有使用。MDK-ARM的免费版本支持本书的所有实例代码和相关的课程资料。给老师的建议:如果目标代码大于免费版的限制(32KB),请向Arm公司请求MDK-ARM专业版许可。
教材结构
第1章讲述了基于MCU的嵌入式系统的概念和与通用型计算机的不同点。之后介绍了Arm Cortex-M0+ CPU、Kinetis KL25Z MCU和FRDM-KL25Z MCU开发板。
第2章讲述了通用输入/输出外设,用C语言给出了初级可实践的开关控制LED的实例。还讲解了简化软件访问外设方法的CMSIS硬件抽象层。
第3章以减少CPU开销并提升响应和软件模块性为目标,讲述了CPU上的多任务。讲解了中断、外设和调度程序(协同式和抢占式)的相互作用。
第4章讲解了Arm Cortex-M0+处理器内核,包括结构、寄存器、存储器和指令集。之后讨论了中断和异常,包括CPU响应和硬件配置。还讨论了如何为带中断的系统设计软件,包括程序设计(和划分工作)、中断配置、用C语言编写中断处理函数和给定抢占后安全地共享数据。
第5章首先讲解了工具链,工具链可以将程序从C语言代码转换为可执行目标代码。然后讲解了源代码和工具链生成的目标代码。涉及的内容包括函数、参数、返回值、活动记录、异常处理函数、循环和选择的控制流结构、存储器的分配和使用、内存中访问数据。
第6章讲解了模拟接口相关的理论和实现,包括模数转换和数模转换的基础知识,量化和采样以及DAC、ADC和模拟比较器外设的相关知识。
第7章讲解了既可用于生成周期性中断或者脉冲宽度调制信号,也可用于测量经过时间或者信号频率的定时器外设,以及用于检测和重置失控程序的看门狗定时器,还讲解了SysTick、PIT、TPM、COP定时器的使用。
第8章讨论了串口通信问题。首先讲解了数据串行化、框架、差错检测、介质访问控制和寻址等基础知识。软件队列用于说明在通信ISR和其他部分程序之间的数据缓冲机制。然后讲解了三种协议(SPI、UART、I2C)和它们的外设,其中,UART通信使用FRDM-KL25Z的调试MCU作为串口将USB桥接到PC,I2C通信使用FRDM-KL25Z的带I2C接口的内置三轴加速度计加以验证。
第9章引入了直接内存访问外设(DMA),它具有的自主发送数据的能力可以从CPU卸载工作并且使其性能得到极大的提升。实例包括使用DMA进行批量数据复制和基于DAC精确定时的模拟波形生成。
附录讲解了如何测量FRDM-KL25Z评估板的功耗,包括断开调试MCU来降低功率;最后讲解了使用超电容测量能耗的方法。