发布于2026-07-21 阅读(0)
扫一扫,手机访问
从芯片系统设计角度看嵌入式编程:体系编程与SOC编程的边界
大多数嵌入式开发者的学习路径,都是从最简单的51单片机编程起步的。随后,我们会慢慢接触到PIC、A VR、STM32等不同系列或型号的控制器,甚至进一步转向三星S5PV210、Exynos4412这样的高端处理器编程。
这个过程中,一个典型的开发流程是:先读懂该型号控制器或处理器的指令集和datasheet,然后通过一些基础例程(最常见的莫过于GPIO、中断和定时器)开始动手编程。当接触过多种类型处理器之后,大家很容易产生一个归纳式的疑问:
在include一个代表该型号IC寄存器映射的头文件之后,为什么某些系列芯片的控制编程几乎一模一样?而不同系列芯片的控制编程也非常相似,唯一的区别似乎仅仅是寄存器命名的不同?这背后的原因是什么?
要回答这些问题,关键在于厘清“体系编程”的范畴与边界。要想深刻理解它,我们不妨从芯片的系统设计角度出发,看看一颗芯片究竟是怎么造出来的。关于这一点,可以参见《集成电路设计和分工》一文。
CPU核心与SOC的关系,是一个至关重要的概念。
全球有能力研发SOC(片上系统)的公司非常多,大到苹果、三星这样的行业巨头,小到深圳那些名不见经传但利润可观的芯片设计公司,都属于这个阵营。但说到CPU核,放眼全球,有能力设计CPU知识产权核的玩家就那么几家:Intel的X86、ARM公司的ARM核、MIPS公司的MIPS核,当然,51内核也算一个。这里需要特别指出的是,中国目前在这方面还处于追赶阶段——尽管国家在大力扶持集成电路产业,但高层也很清楚,这并非砸重金就能立刻见效的事,更务实的做法是先把封装、工艺这些基础环节做扎实。如今市面上的Android智能手机,清一色基于ARM核。如果好奇ARM之父是谁,不妨了解一下大师Steve Furber——他曾在广东工业大学做过专题演讲。
SOC的研发,都是根据市场需求和功能定位,在某一类CPU核的基础上,集成各种通用的外围模块控制器(例如前面提到的GPIO、中断和定时器),以及一些专用模块控制器(比如TI公司的蓝牙单芯片CC2541,就集成了蓝牙基带和射频控制器)。SOC与CPU核之间的关系,可以用一个简单的结构图来概括。
体系编程,顾名思义是针对体系结构的编程,而体系的核心载体就是CPU。从这个角度看:89C51、CC2541都属于51体系编程;PIC32、ATJ213X基于MIPS体系编程;而S5PV210和S3C2440则属于ARM体系编程。对一家CPU核设计公司来说,它没有理由把自己的CPU核设计成风格迥异的两套东西。同一家公司旗下的不同处理器系列,必然遵循同一个体系结构。那么,体系结构的范畴到底是什么?简单说,就是图中红色部分——包括CPU核的设计,以及总线的时序与控制标准。CPU核又可细分为CU(控制单元)和PU(运算单元),CU再往下分,包括取指、译码、访问寄存器、回写存储单元等流水线操作。更高端的CPU,一般还会集成协处理器。因此,体系架构编程通常涵盖以下内容:
对于一家CPU核设计公司来说,它通常会向SOC芯片设计公司提供两样东西:一是体系设计相关规范,例如ARMV7指令集,详细描述了每一条指令执行的伪代码过程(这里的伪代码是针对硬件语言如HDL的);二是特定系列CPU的设计规范,以及基于该规范实现的CPU IP核(寄存器级电路)。
那么,同一个体系下不同系列之间的差异到底在哪里?
以ARM公司为例,它现在的产品线布局非常清晰:Cortex A系列面向高端消费类电子(如手机、平板);Cortex R系列主打军工、航空航天等对实时性要求极高的场合;Cortex M系列则瞄准低端控制器市场(比如STM32、STM8等)。这三者的底层体系都是ARM架构,但工艺、功耗、性能差异巨大。更重要的是,CPU核内部集成的组件也不一样:例如M系列没有集成Cache,而与A系列相比,M系列的MMU也是一个简化版本。
体系编程是嵌入式架构师和操作系统开发人员需要精通的领域,普通开发者接触相对较少。以上分析更多停留在理论层面。而SOC编程,则面向广大的普通开发者,接下来我们将从系统设计的角度,引导大家掌握如何进行SOC编程。
所谓SOC编程,就是针对片上集成模块进行寄存器级的控制编程。在开发实践中,很多人习惯把SOC编程和体系编程统称为“体系编程”。这没关系,只要我们能清晰理解它们之间的关系即可。
那么,SOC编程的具体范畴包括哪些?
有些模块不需要通过引脚连接外部设备就能独立完成功能,比如TIMER。但大多数模块需要借助引脚与外部设备对接才能工作。因此,芯片片上集成的其实是模块的控制部分。以LCD控制器为例:该控制电路负责生成LCD驱动器(外部设备)所需的数据传输时序、行信号、列信号以及设置接口。换个角度看,即便没有LCD控制器,我们也可以通过GPIO来模拟LCD驱动器的时序。但这样做,对普通开发者来说过于复杂,对CPU来说也是一个沉重的负担。所以,系统设计人员会针对LCD驱动器专门设计专用的控制电路。
那么对于LCD控制器来说,我们进行SOC编程的目的是什么?至少,我们需要给LCD控制器一个标识信号,告诉它何时启动、何时关闭。如何给出这个信号呢?LCD控制电路本质上是时序电路和组合逻辑电路的组合,启动和关闭可以用一个输入信号来表示,而这个信号在CPU眼中,可以映射成一个寄存器中的某一个bit。从这个意义上说,SOC编程就是针对寄存器编程。当然,对于LCD控制编程而言,不可能只有一个寄存器这么简单——因为SOC厂商通常希望兼容市面上尽可能多的LCD驱动器,支持不同的分辨率和图像深度,所以必然需要配置不同的寄存器来进行相应设置。
从教学角度总结,体系编程和SOC编程可以划分为五个层次:
我们可以给SOC编程的过程下一个定义:基于第1和第2层的指令集和CPU总线控制机制,根据第5层外围设备的特性参数和第4层具体的电路连接关系,对第3层SOC对应控制模块的寄存器进行编程,最终达成控制和使用目标。
理解SOC系统设计,对编程有极大的帮助。每一款SOC的控制例程,最初都是由SOC系统设计人员给出的——因为他们自己也需要通过编程来对SOC芯片进行功能测试和验证。
另外需要明确一个观点:对于不同的体系来说,同样的模块在设计思路上基本一致。换句话说,从编程的角度看,片上集成模块的设计控制过程与体系结构没有直接关系(两者有关联的地方主要在总线控制方面,而这与编程人员关系不大)。因此,基于ARM体系的LCD控制器和基于MIPS体系的LCD控制器,其设计思路是一致的;不同体系的GPIO控制逻辑也是一致的。尽管底层的寄存器电路可能存在差异,但对于上层编程人员来说,两者基本可以等同对待——不同的可能只是寄存器名称。比如,51单片机和ARM处理器的GPIO都包含输入寄存器、输出寄存器、方向寄存器、上下拉寄存器等。
下面以CLOCK和GPIO为例,具体说明SOC编程,并尽量提取通用的设计和控制过程。
一个最小系统除了CPU和RAM之外,还有一个至关重要的组件就是晶振。SOC也好,CPU也罢,本质上都是一堆逻辑组合电路和时序电路。时序电路需要时钟才能正常工作,而晶振就是提供这个时钟的——它在系统上电后会持续不断地产生时钟信号。
一般的低端单片机没有独立的时钟控制模块,直接依赖晶振(如12MHz或24MHz)工作,也就是说CPU的工作频率就是12MHz或24MHz。但对于高级处理器而言,支持的主频可以达到1GHz甚至更高,而市场上并没有1GHz的晶振。因此,SOC内部必须实现频率调整。PLL(锁相环)倍频技术被广泛应用于处理器的CLOCK模块中,其核心作用是将晶振的频率进行倍频提升。
CLOCK模块除了实现倍频控制外,还需要考虑以下需求:
对于高级处理器集成的模块编程来说,设置好CLOCK源频率的相关寄存器是所有工作的第一步。一般情况下,一级分频由操作系统开发人员设定,而二级分频则由各模块的开发人员负责。
芯片封装是芯片成本的重要组成部分,而封装涉及到一个关键技术——引脚复用。不仅如此,引脚复用还直接关系到最终产品的BOM成本。因此,在系统设计阶段如何高效地进行引脚复用,可以说是SOC集成电路公司的“绝密技术”。
对于编程人员来说,我们需要做的是什么呢?记住一个要点:每一个引脚都可能是功能复用引脚。在使用某个引脚之前,必须先设置它的功能。引脚默认情况下是GPIO功能,如果我们要使用这个引脚实现串口或LCD控制线等功能,就必须对该引脚对应的功能寄存器进行设置——这是SOC编程的第二步。
CLOCK设置和引脚功能设置,对所有模块而言都是通用的前置步骤。
这里我们来谈谈最通用的模块——GPIO。对于GPIO编程,大家应该非常熟悉了:它一定包含输入数据寄存器、输出数据寄存器、输入输出高阻态设置寄存器、上下拉设置寄存器。一般编程流程如下:
别忘了,功能引脚设置也是必需的。有些高级SOC可能还带有驱动能力等级设置寄存器,用于控制引脚的驱动强度。
关于中断控制,可以参阅《软件和硬件都是对生活的高度抽象——论中断控制(ARM体系编程)》一文进行更深入的了解。
在以往的教学实践中,笔者常以基于Cortex A8的S5PV210为例进行讲解。后续如果时间允许,再对该SOC各模块的编程方法做系统梳理。
上一篇:编程从小学起,宝宝编程启蒙
下一篇:编程和我
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8