这是一篇阐述如何对嵌入式SOC外部中断进行控制编程的方法论文章。希望读者理解本篇文章后,能够具备对市场上所有已经面世和将来面世的嵌入式芯片的外部中断进行控制编程的能力。
笔者原创的技术分享一直都恪守以下原则:
从需求的角度去理解嵌入式各种软件和硬件模块的作用和组成,并从芯片系统设计的角度去阐述如何进行控制编程。前者对于理解复杂的系统(如linux的各个子系统)是非常有效的;后者所讲的是代表一个芯片设计工程师的视觉,芯片模块由他负责设计,他对于该模块的控制编程自然是最有发言权的。
笔者还想传递给读者一个重要的嵌入式控制理论的观点:
不同SOC芯片中的类似功能模块(例如51内核集成的TIMER和ARM内核集成的TIMER)的设计理念是基本一致的,尽管各家集成电路厂商的制程工艺、总线技术标准、功耗等技术不一样,但对于编程人员来说,类似功能模块呈现的硬件接口(即寄存器编程)是基本一致的。无论是基于高级ARM核、MIPS核,还是基于简单的51核,各个核所集成的时钟控制、GPIO、中断、TIMER等模块的设计都是相仿的。其中最重要的原因就是,目标模块所完成的目标功能(可以理解为硬件需求)都是一样的,即ARM核的中断和51核的中断,其完成的功能是一样的,GPIO完成控制功能也是一样的。
所以,笔者希望从系统设计的角度来阐述GPIO外部中断的控制编程,使读者能够跳开某个具体芯片而掌握所有芯片的GPIO外部中断的控制编程。
一、 中断综述
细细数来,笔者已经针对中断写了三篇文章了。每篇篇幅都很大,阐述的重点都不一样。这里给出参考,大家如有时间可以先系统地看完这三篇文章,再来阅读本文。
《软件和硬件都是对生活的高度抽象---论中断控制(ARM体系编程)》, 摘要是:硬件模块设计又是高度抽象于现实需求,很多时候,X86、ARM和MIPS只有底层寄存器和指令级别的差异,对于软件驱动基本是一致的。本文论及ARM体系的中断控制,以基于Cortex-A8的S5PV210为例。中断是一种异步工作机制,也是嵌入式处理器的一个核心工作机制,对于实时操作系统来说必不可少。
《从需求的角度去理解Linux之二:Linux中断完全分析》, 摘要是:学习本文将可以对linux中断有全面而又深刻的认识。本文对Linux中断所涉及的需求、管理机制、中断实现、中断接口(上半部和下半部)、驱动使用进行完全分析。
《体系编程、SOC编程那些事儿》, 摘要是:笔者将从芯片IC的系统设计的角度去诠释如何掌握体系编程和SOC编程。笔者有超过10年的嵌入式研发经验,作为架构师多次主导过多媒体SOC研发并成功量产案例,在高端处理器体系编程和嵌入式Linux方面有丰富的教学经验,希望本文能给嵌入式学习者和从业者有较深刻的指引。
二、 外部中断控制设计框图
外部中断控制是在中断控制模块上接入GPIO,外部中断就是GPIO中断控制。外部中断控制的核心是中断支持GPIO边沿触发、电平触发。设计框图如下,该图是TI蓝牙单芯片CC2541的中断控制框图局部,CC2541基于8051内核。
从之前的参考文章,我们可以知道,要完成中断控制功能,必须以下组成部分:
三、 外部中断控制设计分析
针对以上框图,我们来进行解构分析。
1.中断分级
曾记得,8位单片机鼻祖80251的外部只有2个引脚,中断控制只有一级。那么这里为什么要分两级呢?那是因为80251只有简单的外部中断、timer中断等中断源,而蓝牙单芯片不仅集成timer,还有串口,DMA、射频、PWM等等,而且GPIO P0,P1,P2大部分引脚都可以复用为中断引脚,因此中断源有很多。而8位单片机的中断指示pending寄存器就只有8个bit,怎么能够表述那么多中断源呢?只有中断分级来解决,将中断源分为一级中断和二级中断。
2.一级中断控制
一级中断的中断源一般以子模块为单位,即串口1给出一个中断源,串口2给出一个中断源,P1(8个引脚)给出一个中断源,TIMER0给出一个中断源,TIMER1给出一个中断源。
每个中断源都对应以下寄存器或者寄存器位:
一级pending位,代表该中断产生中断(只是中断产生,CPU并不一定响应)。
一级mask选通位,选通该位才允许中断。
全局中断mask位,这个bit是全局中断开关,必须要允许才能使用CPU的中断控制。
一级中断矢量寄存器,代表中断后PC跳转的地址。
一级优先级位,当多个中断源同时产生时,CPU将选择最高优先级的中断源对应的中断矢量地址进行PC跳转响应。
从中,我们看出,一级pending位在中断响应里面要主动去清零,否则中断会重复产生。
3.二级中断控制
二级中断的中断源以子模块内部的子功能为单位,如串口1的接收中断、发送中断,P1的8个引脚P1.0,P1.1,…P1.7的引脚中断。这些中断源都会接入到对应的或电路,并输出一个中断源,作为一级中断源。
各个二级中断源同样对应以下寄存器或者寄存器位:
二级pending位,代表该中断产生中断(只是中断产生,CPU并不一定响应)。
二级mask选通位,选通该位才允许中断。
对于GPIO外部中断来说,还需要配置以下寄存器:
二级边沿触发位,每个引脚都要配置对应的触发方式,上升沿,下降沿还是高低电平触发。
此外,我们还需要谨记,在《体系编程、SOC编程那些事儿》提到,CLOCK和引脚复用是SOC各模块的公共组成部分。所以模块都需要先配置这两个模块。对于GPIO来说,时钟一般按上电默认设置即可。但引脚的复用设置一般是普通的GPIO,而不是中断功能。因此,我们还需要对GPIO的中断进行配置,将其设置为中断功能。
同样,中断响应里面需要对二级pending位清0,否则会重复中断。
4.中断响应
一般在有操作系统的固件中,中断都有一个统一的入口,然后按优先级查询一级pending位,以做出响应服务。如果要进一步提高中断响应速度,将各个具体的中断服务程序入口直接放到对应中断矢量地址上。
记得清一级pending和二级pending。
四、 外部中断控制编程方法
理解了以上外部中断控制的设计框图,进行控制编程应该是非常容易的。各种不同SOC的中断控制的设计都是一致的,不同的是代表各部分的寄存器的命名是不一样的。一般的方法过程是:
1. 找出各个具体的SOC datasheet的中断控制框图。
2. 分别找出中断控制框图中的代表各部分的寄存器或者寄存器位,并根据datasheet的指示值进行配置控制。
3. 对于GPIO中断控制来说,包括一级中断、二级中断、引脚复用配置。这对所有SOC都是一致的。
五、51核CC2541外部中断编程
我们按照以上方法找到分别对应的寄存器,假设我们先要对P1.2进行下降沿触发控制。
1. 一级中断
一级pending
一级mask选通
二级pending位
二级mask选通位
二级边沿触发
GPIO引脚复用,P1.2要设置为1,选择为中断功能。
六、ARM核S5PV210外部中断控制编程
请参考《软件和硬件都是对生活的高度抽象---论中断控制(ARM体系编程)》。
七、不同SOC外部中断控制的可能差异
以上我们阐述了外部中断控制的设计和编程,其中强调的一致性。接下来,我们说说不同SOC中断控制的可能差异。这些差异跟SOC的应用场景有关。
1. 低端SOC的中断源少,可能只有一级中断。
2. 低端SOC使用8位核或者16位核,一个pending位最多表示8个或者16个中断源,而中断源可能超过16个,因此一级中断源可能由多个寄存器来表达。CC2541即是这样。
3. 高级SOC的中断更强调快递响应,特别针对某一类对时间要求特别高的中断源,提供快速中断响应模式,一般的场景则使用普通中断响应。即有FIQ和IRQ方式。基于ARM核的SOC即是这样。我们都知道在中断响应里面,中断上下文要先保存用户态上下文,而FIQ快速中断响应则不需要保存用户态上下文,因为在FIQ状态有单独的一组寄存器供服务程序使用,这组寄存器跟用户态上下文的寄存器组是无关的。
4. 在统一的中断服务入口里面,可能会按照pending的优先级来查询并响应,但如果硬件能够自动判别最高优先级,那么响应里面就可以直接读这个寄存器的值来跳转即可,避免for循环遍历,以提高响应性能。S5PV210的中断响应即支持这种机制。
怎样,有信心以不变应万变了吗?
更多嵌入式和物联网原创技术分享请关注微信公众号:嵌入式企鹅圈