商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > 体系编程、SOC编程那些事儿

体系编程、SOC编程那些事儿

  发布于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,一般还会集成协处理器。因此,体系架构编程通常涵盖以下内容:

  1. 指令集(寻址方式、运算指令)+ 汇编伪指令
  2. 流水线、指令预取与跳转规则:在流水线模式下,指令预取的是当前执行指令之后的N条指令,因此PC指针和执行时的地址并不一致。这就引出一个关键问题:当发生中断或异常时,返回地址应该如何确定?
  3. 协处理器(MMU虚拟内存管理、Cache缓存)
  4. 寄存器使用与参数传递规范(ABI):它要解决的是,在寄存器层面如何实现C语言中的参数传递。关于这一点,可以参考《C/汇编混合编程接口——MIPS ABI》一文。
  5. 异常与中断处理(硬件中断、一般异常、指令陷入等):图中的INT模块管理所有硬件中断(如串口、定时器、外部中断等),并将所有中断引脚通过逻辑“或”之后送入CPU的中断信号线。因此,对于CPU来说,当中断发生时,它并不知道是哪个模块触发了中断——只有INT模块才知道。
  6. 调试规范
  7. 总线规范:对编程人员而言,不一定要深入了解总线规范的细节。但它是SOC芯片设计的重要基石,规定了总线的时序、仲裁规范以及存储工作模式(冯·诺依曼结构还是哈佛结构)。

对于一家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编程和体系编程统称为“体系编程”。这没关系,只要我们能清晰理解它们之间的关系即可。

那么,SOC编程的具体范畴包括哪些?

  1. 通用控制模块:如CLOCK、GPIO、INT、TIMER、UART等。
  2. 专用控制模块:如LCD、蓝牙、编解码器等。

有些模块不需要通过引脚连接外部设备就能独立完成功能,比如TIMER。但大多数模块需要借助引脚与外部设备对接才能工作。因此,芯片片上集成的其实是模块的控制部分。以LCD控制器为例:该控制电路负责生成LCD驱动器(外部设备)所需的数据传输时序、行信号、列信号以及设置接口。换个角度看,即便没有LCD控制器,我们也可以通过GPIO来模拟LCD驱动器的时序。但这样做,对普通开发者来说过于复杂,对CPU来说也是一个沉重的负担。所以,系统设计人员会针对LCD驱动器专门设计专用的控制电路。

那么对于LCD控制器来说,我们进行SOC编程的目的是什么?至少,我们需要给LCD控制器一个标识信号,告诉它何时启动、何时关闭。如何给出这个信号呢?LCD控制电路本质上是时序电路和组合逻辑电路的组合,启动和关闭可以用一个输入信号来表示,而这个信号在CPU眼中,可以映射成一个寄存器中的某一个bit。从这个意义上说,SOC编程就是针对寄存器编程。当然,对于LCD控制编程而言,不可能只有一个寄存器这么简单——因为SOC厂商通常希望兼容市面上尽可能多的LCD驱动器,支持不同的分辨率和图像深度,所以必然需要配置不同的寄存器来进行相应设置。

从教学角度总结,体系编程和SOC编程可以划分为五个层次:

  1. 体系指令集,例如ARM指令集
  2. 特定系列的CPU规范,例如基于ARM体系的Cortex A8核
  3. SOC级:在CPU核的总线基础上,集成clock、timer、interrupt、GPIO等控制器(例如三星的S5PV210和TI的OMAP3430都是基于Cortex A8核)
  4. 板级电路:例如开发板、手机主板电路,其电路图明确了SOC的引脚与外部设备的连接关系。如果GPIO A的第一个引脚接了LED0,那么要控制LED0,就需要对GPIOA0进行相应的控制编程。
  5. 外围设备规格:指板级电路图上所有外围设备的规格参数,例如具体LCD的规格(尺寸、分辨率、延时参数等)。

我们可以给SOC编程的过程下一个定义:基于第1和第2层的指令集和CPU总线控制机制,根据第5层外围设备的特性参数和第4层具体的电路连接关系,对第3层SOC对应控制模块的寄存器进行编程,最终达成控制和使用目标。

三、SOC设计与编程

理解SOC系统设计,对编程有极大的帮助。每一款SOC的控制例程,最初都是由SOC系统设计人员给出的——因为他们自己也需要通过编程来对SOC芯片进行功能测试和验证。

另外需要明确一个观点:对于不同的体系来说,同样的模块在设计思路上基本一致。换句话说,从编程的角度看,片上集成模块的设计控制过程与体系结构没有直接关系(两者有关联的地方主要在总线控制方面,而这与编程人员关系不大)。因此,基于ARM体系的LCD控制器和基于MIPS体系的LCD控制器,其设计思路是一致的;不同体系的GPIO控制逻辑也是一致的。尽管底层的寄存器电路可能存在差异,但对于上层编程人员来说,两者基本可以等同对待——不同的可能只是寄存器名称。比如,51单片机和ARM处理器的GPIO都包含输入寄存器、输出寄存器、方向寄存器、上下拉寄存器等。

下面以CLOCK和GPIO为例,具体说明SOC编程,并尽量提取通用的设计和控制过程。

1. 最小系统

一个最小系统除了CPU和RAM之外,还有一个至关重要的组件就是晶振。SOC也好,CPU也罢,本质上都是一堆逻辑组合电路和时序电路。时序电路需要时钟才能正常工作,而晶振就是提供这个时钟的——它在系统上电后会持续不断地产生时钟信号。

2. CLOCK(时钟模块)

一般的低端单片机没有独立的时钟控制模块,直接依赖晶振(如12MHz或24MHz)工作,也就是说CPU的工作频率就是12MHz或24MHz。但对于高级处理器而言,支持的主频可以达到1GHz甚至更高,而市场上并没有1GHz的晶振。因此,SOC内部必须实现频率调整。PLL(锁相环)倍频技术被广泛应用于处理器的CLOCK模块中,其核心作用是将晶振的频率进行倍频提升。

CLOCK模块除了实现倍频控制外,还需要考虑以下需求:

  • 不同模块的工作频率不同:SOC集成的模块很多,工作频率差异很大。例如,CPU、GPU和RAM的工作频率在GHz级别,LCD的工作频率在100MHz左右,视频编解码模块的工作频率在百MHz级别,而GPIO、串口这类模块的工作频率可能在10MHz级别。因此,CLOCK模块还需要进行分频处理。通常的做法是将模块分类,进行一级分频。例如,S5PV210的CLOCK将频率分为三个域:M域供给CPU、中断异常等,D域供给LCD、JPEG、HDMI等,P域供给GPIO、UART等外围设备。每个域都可以通过寄存器调节其工作频率。
  • 同域内模块频率的差异:处于同一个域内的不同模块,工作频率也可能不同。因此,允许模块内部进行二级分频。

对于高级处理器集成的模块编程来说,设置好CLOCK源频率的相关寄存器是所有工作的第一步。一般情况下,一级分频由操作系统开发人员设定,而二级分频则由各模块的开发人员负责。

3. 引脚复用

芯片封装是芯片成本的重要组成部分,而封装涉及到一个关键技术——引脚复用。不仅如此,引脚复用还直接关系到最终产品的BOM成本。因此,在系统设计阶段如何高效地进行引脚复用,可以说是SOC集成电路公司的“绝密技术”。

对于编程人员来说,我们需要做的是什么呢?记住一个要点:每一个引脚都可能是功能复用引脚。在使用某个引脚之前,必须先设置它的功能。引脚默认情况下是GPIO功能,如果我们要使用这个引脚实现串口或LCD控制线等功能,就必须对该引脚对应的功能寄存器进行设置——这是SOC编程的第二步。

CLOCK设置和引脚功能设置,对所有模块而言都是通用的前置步骤。

4. GPIO

这里我们来谈谈最通用的模块——GPIO。对于GPIO编程,大家应该非常熟悉了:它一定包含输入数据寄存器、输出数据寄存器、输入输出高阻态设置寄存器、上下拉设置寄存器。一般编程流程如下:

  1. 设置上下拉寄存器
  2. 设置引脚的方向(输入还是输出)
  3. 通过输入数据寄存器读入数据,或者写数据到输出数据寄存器

别忘了,功能引脚设置也是必需的。有些高级SOC可能还带有驱动能力等级设置寄存器,用于控制引脚的驱动强度。

5. 中断(INT)

关于中断控制,可以参阅《软件和硬件都是对生活的高度抽象——论中断控制(ARM体系编程)》一文进行更深入的了解。

在以往的教学实践中,笔者常以基于Cortex A8的S5PV210为例进行讲解。后续如果时间允许,再对该SOC各模块的编程方法做系统梳理。

本文转载于:https://blog.csdn.net/weixin_30813225/article/details/97532522 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注