Cortex-M3

在上一篇文档中,我们向大家分享了如何使用IAR本身自带半主机(semihost)模式来调试程序,但是每10ms输出一个字符的速度实在让人难以接受。今天就向大家介绍一个输出速率更快的,使用同样方便的调试方法-SWO引脚的使用。

在Cortex-M3\M4系列MCU中,内核的调试组件都有一个仪器化跟踪单元(ITM)。ITM的一个主要的用途,就是支持调试信息的输出(例如,printf格式输出)。ITM包含了32个刺激端口,允许不同的软件把数据输出到不同的端口,从而让调试主机可以把它们的信息分离开。每个端口都可以独立的使能/除能,还可以允许或禁止用户进程对它执行写操作。那么这些与MCU的SWO引脚有什么关系呢?刚才我们有说ITM包含了32个端口,其中SWO引脚,就是ITM模块的端口0,我们可以直接用它来输出一些调试信息。那么现在就看看如何使用它吧。

把MCU的SWO引脚同J-link等调试工具连接在一起,因为K64开发板已经直接引出SWD接口了,所以我们就直接连接了J-Link。如图 2所示,第6脚就是SWO引脚。

图 2 SWD接口

当MCU连接好J-link之后,我们在工程中的主函数起始处添加stdio.h文件,如下所示。

#include

接下来为了能直接调用printf函数格式化输出,又需要用到我们之前提到的重定向技术了,只是这次不是重定向到串口,而是ITM模块的0通道,即SWO引脚。如程序清单 1所示。

程序清单 1 重定向代码
int fputc(int ch, FILE *f) {
ITM_SendChar(ch);
return(ch);
}

其中ITM_SengChar函数是core_cm4.h内核文件里定义的内联函数,我们可以直接调用。

完成重定向之后,我们写了个定时打印HelloWorld的程序。打开Keil工程的【Options for Target】->【debug】->【settings】->【Trace】,对Trace选项卡进行如图 3所示的配置。

图 3 Trace选项卡配置

点击确定之后,进入调试模式,打开【View】->【Serial Windows】->【Debug(printf) Viewer】,这时我们就可以看到MCU通过J-link向编译器输出的打印信息了,如图 4所示。打印速度还很快哦。

图 4 Debug Viewer窗口

到此我们算是学会了使用SWO引脚来调试输出了,是不是很酷哦。细心的网友可能会发现为什么Cortex-M0\M0+内核的MCU没有找到SWO引脚呢?这是因为它们采用的还是ARM-V6的老架构,内核的调试组件没有ITM模块。

又是一个遗憾,本来以为找到了最合适的调试方法,却对MCU的内核有限制。那么有没有一种调试方同时具有SWO的优点,并同时能在Cortex系列内核的MCU中使用呢?

围观 1894

摘要:设计一款具有自主吸尘功能并且结构简单、成本低的小型家用吸尘机器人,实现了室内半自动或者全自动的清洁工作,从一定程度上代替人们做繁杂的家务。在硬件选型上,以ARM Cortex™⁃M3处理器为核心,设计了专门的电机驱动板,通过光电编码反馈电路实现行走模块的闭环控制。主要对传感器模块进行开发,通过合理布置传感器,采用多种传感器融合,使超声波和红外光电传感器协调工作实现对远近距离障碍物的精确检测,提高了对障碍物的准确识别,能够实现自主避障吸尘。

随着人们生活水平的日益提高,我国人口的老龄化也越来越明显,吸尘机器人作为服务机器人的一种,能够代替人进行清扫房间、车间、墙壁等一些简单劳动。使服务机器人有了广阔的市场,已成为一些企业和科研院所研究的焦点。目前市场上的吸尘机器人虽然也具有智能性,但大多由于结构不尽合理、通用性差、集成度高而导致成本高,不利于普及。在研究总结市场上相对成熟产品的基础上,基于ARM Cortex™⁃M3处理器设计一款具备自我导航功能的室内吸尘机器人。外形紧凑、结构简单、运行平稳、噪音小,并且成本低,操作方便,还具有可扩展接口,用户能够根据实际需要对其功能做进一步开发。

1、吸尘机器人总体构成

利用ARM Cortex™⁃M3 处理器设计一款应用于室内的移动清洁机器人,主要任务是能够自主清扫房间,因此应该具备以下功能:

(1)能正确判断机器人所处的房间和在房间中所处的方位;

(2)能正确检测出房间内的墙壁、家具等障碍物;

(3)在游历完所有房间完成清扫任务后能自主回到出发点,关机。

为了防止机器人在工作时出现堵转现象,并且能自由进入一些家具比如沙发、桌子等的底下,吸尘机器人不能太高,外形采用半圆柱形。底盘由四个轮子共同支撑,其中左右两侧为驱动轮,分别由两个微型直流电机直接驱动,前后两个万向轮起到支撑和导向的作用。采用碰撞、红外传感器、超声波等组成多传感器系统。在机器人的上方装有红外接收传感器,底盘边缘均匀分布装有接近传感器,用来检测障碍物;在机器人的前方装有碰撞传感器;前方和左右装有超声波测距传感器,用来检测周围环境。

总体框架设计如图1所示。

2、硬件主体设计

硬件系统主要由ARM Cortex™⁃M3处理器、传感器模块、电机驱动模块、人机交互模块、无线遥控发射模块组成。

2.1 ARM Cortex™⁃M3处理

机器人控制系统的主要任务是根据传感器和编码器等反馈回来的数据,进行清扫路径规划,控制清扫、吸尘机构,完成各种控制动作。设计合适的人机接口,在LCD上显示机器人状态和运行时间。因此,机器人控制系统包括传感器模块,电机驱动模块,红外遥控接收模块、LED 指示灯和液晶显示模块。采用ARM Cortex™-M3处理器作为机器人控制系统的核心,主要是低成本、小管脚数和低功耗,并且具有极高的运算能力和极强的中断响应能力,工作电流仅为50 mA。

2.2 电机模块

分成小电机驱动电路和两路大功率驱动板,包括用于行走的两个小直流电机和用于吸尘的大功率无刷直流电机、扫地的直流滚刷电机、扫边角的直流边刷电机。因为电机分别决定机器人的行走路径和吸尘功率,所以设计了专门的驱动板,如图2所示。

行走模块的设计对吸尘机器人避障规划有着至关重要的作用,我们将吸尘机
器人设计成一个闭环控制,主要包括驱动电路和光电编码反馈电路。光电编码反馈电路通过计算反馈回来的脉
冲数量和相位而得到当前的电机速度。芯片最高可以驱动25 V 的电机,吸尘机器人里行走电机的工作电压为
24 V,芯片的电压为5 V,芯片输出的PWM 波转化成大电压PWM波控制电机。其极限参数如表1所示。

2.3 传感器模块

主要包括3部分:用于测量和感知障碍物的超声模块、红外和碰撞传感器,用于状态检测的传感器(检测电池电量、尘桶、电机堵转悬空)。传感器模块使机器人对周围环境做出正确判断,为顺利完成任务提供智能决策。

(1)超声波测距传感器模块

室内吸尘机器人由于工作环境的原因,必须具备检测各种大小、高低、颜色的障碍物,超声波是一种非接触式的检测技术,在空气中传播不受光线、烟雾、电磁场等外界因素的干扰,与红外传感器相比,超声传感器感应
距离更远,可靠性高,且成本低。因此,使用高精度的超声波测距系统可以有效地完成障碍物的检测。

本文选用的是US⁃100 超声波测距模块可实现0~4.5 m的非接触测距功能,拥有2.4~5.5 V的宽电压输入范围,静态功耗低于2 mA,自带温度传感器对测距结果进行校正,同时具有GPIO,串口等多种通信方式,工作稳定可靠。在机器人的前后各安装两个超声波传感器,处理器产生40 kHz的脉冲经I/O口输出,再经过与非门以及三极管放大形成极性相反的两路脉冲输入超声波发射头的两个引脚,探头便可发出一连串40 kHz的超声波,遇障碍物后返回给接收电路,处理器同时控制门电路,以实现发射波的间断如图3所示。超声波接收端通过压电转换的原理,把经障碍物反射回的信号转换为电信号经过低噪声放大和带通滤波,再比较产生中断给处理器进行时间测量,从而做出障碍物的距离判断,如图4所示。

(2)红外和碰撞传感器模块

本吸尘机器人在工作时对于远距离障碍物主要利用超声波测距,但是超声波对近距离障碍物不敏感,所以增设红外模块进行近距离检测,根据能量反射法设计红外测量模块。机器人前后安装两组红外传感器,每组由多达14组红外发射接收管组成,在机器人的上面和底盘各安装14个,每上位和下位的2个红外发射和接收管并联并且指向同一个方向构成一组,每一组电路可分为高频脉冲信号产生、红外发射调节与控制、红外发射驱动、红外接收等几个部分。通过38 kHz晶振和非门电路得到一个38 kHz的调制脉冲信号;利用三极管驱动红外发射管(TSAL6200)的发射。发射管发出的红外光经物体反射后被红外接收模块接收,通过接收头(HS0038B)内部自带的集成电路处理后返回一个数字信号,输入到微控制器的I/O口,如图5所示。

接收头如果接收到38 kHz的红外脉冲就会返回输出低电平,否则就会输出高电平。通过对I/O口的检测,便可以判断物体的有无。这样一共可以检测14个方向,覆盖360°范围。机器人对前后的近距离障碍物都能检测,前进后退都能工作,这种由2个红外接收管组成测障传感器有效距离接近2 m,并且还能够在球非常近的范围内(10 cm内)读取障碍物距离结果(没有溢出)。

在机器人的左前、左后、右前、右后4个方位安装四个碰撞开关(常开),通过采集模拟口上电压值的变化,
判断出其中的一个或几个碰撞开关闭合,从而检测出哪个方向有碰撞发生。

2.4 人机交互模块

(1)液晶显示和键盘输入:两者配合使用可以设置机器人各种参数,如自主启动、设置工作时间等。

(2)无线遥控模块:红外遥控使机器人的使用更加方便简单,发射距离超过10 m,能满足需要。

3、结语

通过这样的硬件设计,清洁机器人控制系统,既能满足良好的实用性,还降低了成本,工作稳定可靠。机器人传感器模块能精确定位障碍物,通过软件策略能实现良好的避障。对将来家用服务机器人的研究与开发有着重要现实意义。

围观 452

WiFi物联网小车设计方案,采用电脑上位机软件通过无线WiFi 控制小车的运动,采集小车的信息。与传统的“智能小车”相比,主要特点在于使用32 位高性能单片机控制、互联网通信机制和电脑上位机软件控制。此方案融合了电脑软件、网络通信、图像处理、图形显示、运动控制、速度采集和温度采集等技术,具有“物联网”的相关特点。传统的小车控制大多使用红外通信,使用遥控器进行控制,不但受到距离的限制,而且远没有电脑软件直观美观。互联网通信使小车具备远程控制的能力,这是红外通信望尘莫及的。此外,本方案小车控制芯片采用Cortex-M3单片机,该单片机具有极丰富的外设,这给小车以后功能升级和扩展奠定了基础。

1、总体设计方案

WiFi 物联网小车设计方案需要达到的目的是使用电脑软件(简称上位机)通过互联网与小车控制端(简称下位机) 进行通信,从而控制小车的运动,采集小车的速度、温度以及视频监控等功能。总体设计方案如图1 所示。图中有2 种通信模式可选,其中“WiFi 局域网小车控制”是采用局域网的方式,将上位机、无线路由器和小车组成一个局域网,实现上位机控制小车的目的。“互联网远程小车控制方案”是采用远程互联网的方式,将上位机与小车组成一个互联网,从而实现远程控制小车的目的。2 种方案的技术类似,由于受到实验条件的限制,本设计以局域网小车控制为例进行讲解说明。

图1 总体方案设计

从通信的角度来讲,无线路由器是上位机和下位机的数据中心,上位机通过Winsocket 套接字编程创建一个网络接口与路由器进行连接,小车端通过一个串口转WiFi 模块,将串口数据通过WiFi 模块转换成WiFi 信号与路由器交互。此过程中,上位机和下位机WiFi 模块均有一个独立的局域网IP 地址。通过这个IP 地址上位机和下位机便可以实现网络通信。

从控制的角度来讲,上位机是小车的控制中心,上位机通过“按键”发出指令给小车,小车收到指令后回传相关数据给上位机,上位机收到小车回传的数据,经过解析,将其显示出来。

1.1 上位机软件设计

上位机主要功能是控制小车运动,显示小车的速度、周围的温度以及小车采集的摄像。如图2 所示,这些功能由2 个线程来完成分别是“图像、声音处理线程”和“小车运动控制,速度、温度采集线程”等。前一个线程主要负责接收并处理有小车WiFi摄像头传过来的图像信息和音频信息,此部分主要涉及到DirectShow 相关技术。后一个线程主要负责小车运动的控制,包括“前进、后退、左转、右转、停止、加速、减速、转向灯和喇叭”以及接收处理小车回传的温度和速度信息等,并用虚拟图表显示出来。上位机软件2 个线程都创建了一个互不相干的套接字,前者用于与小车WiFi 摄像头进行数据交互,后者用于与小车串口转WiFi 模块进行数据交互。

图2 上位机软件设计方案

1.2 下位机软件设计

下位机软件设计,即Cortex-M3 核心处理器的程序设计,如图3 所示。设计方案主要包括:摄像的控制、小车4 个电机的控制、DS18B20($2.0074) 温度数据的采集、红外对管速度模块数据的采集以及采集到数据后数据的处理打包发送等内容。其中摄像的控制、电机控制以及温度和速度的采集均以函数的形式获取,当下位机收到上位机的相关命令后,便调用相应的函数获取到结果后用固定的格式发送给上位机。

图3 下位机软件方案

下位机实现WiFi 与无线路由器通信的核心是串口转WiFi 模块,通过这个模块可以将下位机发送的串口数据直接转换成WiFi 信号发射出去。在使用此模块之前可以通过多种方式进行配置,只要配置好了,便可以与制定的WiFi 接入点进行网络通信。

2、设计方案特点及扩展说明

2.1 特点介绍

本方案是基于将电脑软件、互联网通信以及单片机技术相结合的理念构想设计的。从单片机的选型、通信方案的确定以及上位机软件的设计等都与传统的“智能小车”有很大的特别之处。以下是本设计方案的3 大特色:

① 小车的控制芯片采用功能强大的Cortex-M3 32 位高性能、低功耗的处理器,该芯片具有丰富的外设,芯片还支持ARM 公司提供的RLTx 实时操作系统,使用起来非常方便;

② 通信方式采用TCP / IP 通信协议,使用无线WiFi 技术,实现对小车的控制。此通信方案(如图1),在具有私有IP 的情况下可以连接远程网络,可以通过远程网络遥控小车,这在“智能家居”和“远程医疗”等领域将会有不错的使用价值;

③ 利用电脑上位机管理软件,使单片机控制、网络通信和计算机软件有效地结合。此方案设计上位机软件来管理小车,符合将复杂的控制简单化、界面化的设计理念。

2.2 扩展说明

Cortex-M3 单片机强大丰富的外设资源为本设计的扩展奠定了强大的基础。除了已实现的功能外,单片机还剩下2 个串口未用,这使小车还可以添加如下功能:GPS 导航功能、语音功能以及GSM/GPRS 发短信、打电话和无线上网功能。

3、方案难点及关键技术

方案难点有:

① 上位机控制小车的运动对实时性的要求很高,而采集小车的速度并用表盘显示出来,这对通信的稳定性又提出了要求,而对于本来就存在延时的TCP / IP 通信来说更是难上加难;

② 图像处理主要是借鉴网上DirectShow 开发指南中提供的技术,很多内部的处理机制和信号过滤器的使用是难点;

③ 上位机速度表盘显示速度不连贯,偶尔还有“卡死”的现象。

关键技术有:① 通信协议的制定;② 下位机采集并处理信息的方法;③ 上位机套接字编程,速度表盘动态显示速度;④ 上位机显示小车监控视屏;⑤ 小车作为WiFi 接入点接入网络。

4、系统仿真结果分析

4.1 WiFi 物联网小车整体外观

小车整体外观如图4 和图5 所示,系统由上位机和小车组成,小车控制电路放在小车上。小车控制器主要包括:电机控制、测速、测温、通信、图像采集和无线路由等。

图4 WiFi 物联网小车

图5 小车俯视图

4.2 系统整体调试

WiFi 物联网小车控制系统上位机界面主要包括:网络设置、功能设置、视屏监控区、运动控制区、速度显示区、温度显示区以及调试窗口。网络设置用于上位机与小车进行网络连接,输入小车IP 地址,点击“连接”即可。视频监控功能需要小车端安装WiFi摄像头,通过点击视频显示框下面的“Call”按钮可以连接WiFi 摄像头的IP 地址,连接成功即可获取摄像头采集到的图像。运动控制区用于控制小车的运动和显示小车的转向灯、喇叭等。速度显示区是一个速度表盘用于显示小车的实时速度。温度显示区是一个温度计的图形界面,可以显示小车上DS18B20 传感器的温度值。通信调试窗口在调试程序时使用。

4.2.1 网络连接

网络连接调试使用网上下载的TCP网络调试助手,首先设置TCP调试助手为服务器模式,设置服务器监听IP为192.168.16.110,端口设为345,连接网络,此IP 地址和端口号是UART 转WiFi 模块的IP地址和端口号,通过单片机用AT 指令设定。网络连接成功后,小车上位机会不断的发送“014,SR1,TE1,029.6”,表示小车端当前的温度是29.6 ℃。

4.2.2 小车运动

小车运动控制部分的调试同样采用上位机和TCP 网络调试助手进行调试。连接好网络后,在上位机上分别点击“↑”,“↓”,“←”,“→”,“█”,“加速”,“减速”。在调试助手接收窗口上依次接收到 “:014,SG1,UP1,;” 、“:014,SG1,DO1,;”、“:014,SG1, LE1,;”、“: 014, SG1, RI1,;”、“: 014, SG1,ST1,;”、“: 014, SG1, AD1,;” 和“: 014, SG1,SU1,;”,分别表示“前进”,“后退”,“左转”,“右转”,“停止”,“加速”和“减速”。

4.2.3 温度和速度的显示

温度和速度的测试直接在小车的实际运动过程中进行测试。打开小车,连接上位机,用手捂住小车上的 DS18B20,观察上位机上温度显示区模拟温度计的度数变化,然后用手转动小车的轮子观察上位机速度显示区速度表盘指针的变化,改变温度和速度的大小,发现速度表盘指针和温度指示相应发生变化,因此可以判断温度和速度的传输没有问题。

5、 结束语

通过反复调试和修改代码,可以实现预想的功能。通信稳定,小车的控制可靠,数据采集的准确度和灵敏度达到要求。在不涉及到远程联网控制的情况下,系统的稳定性和可靠性已经远远超过普通的红外遥控小车和无线射频遥控小车。方案的意义在于将电脑软件技术、网络技术和单片机技术有效结合,突出体现并且深化了“物联网”的含义,未来必将广泛应用于社会生活和生产中。方案的应用领域主要有无人驾驶、远程监控和智能家居等。

围观 550

一、uCOS II在ARM处理器上移植过程中的中断处理
  
uCOS II是一个源码公开、可移植、可固化、可剪裁和抢占式的实时多任务操作系统,其大部分源码是用ANSI C编写,与处理器硬件相关的部分使用汇编语言编写。总量约200行的汇编语言部分被压缩到最低限度,以便于移植到任何一种其它的CPU上。
  
uCOS II最多可支持56个任务,其内核为占先式,总是执行就绪态的优先级最高的任务,并支持Semaphore (信号量)、Mailbox (邮箱)、MessageQueue(消息队列)等多种常用的进程间通信机制。与大多商用RTOS不同的是,uCOS II公开所有的源代码。并可以免费获得,只对商业应用收取少量License费用。
  
uCOS II移植跟OS_CUP_C.C、OS_CPU_A.S、OS_CPU.H 3个文件有关,中断处理的移植占据了很大一部分内容。作为移植的一个重点,本文以标准中断(IRQ)为例讨论了移植中的中断处理。
  
1、uCOS II系统结构
  
uCOS II的软硬件体系结构如图1。应用程序处于整个系统的顶层。每个任务都可以认为自己独占了CPU,因而可以设计成为一个无限循环。大部分代码是使用ANSI C语言书写的,因此uCOS II的可移植性较好。尽管如此,仍然需要使用C和汇编语言写一些处理器相关的代码。uCOS II的移植需要满足以下要求:
  
1)处理器的C编译器可以产生可重入代码:可以使用C调用进入和退出Critical Code(临界区代码);
  
2)处理器必须支持硬件中断,并且需要一个定时中断源;
  
3)处理器需能容纳一定数据的硬件堆栈;
  
4)处理器需有能在CPU寄存器与内存和堆栈交换数据的指令。
  
移植uCOS II的主要工作就是处理器和编译器相关代码以及BSP(Board Support Package)的编写。uCOS II处理器无关的代码提供uCOS II的系统服务,应用程序可以使用这些API函数进行内存管理、任务间通信以及创建、删除任务等。
  
2、uCOS II移植过程中需要注意的几个问题
  
uCOS II移植的中断处理跟ARM体系结构和uCOS II处理中断的过程有关,必须注意这2个方面的问题才能高效移植。
  
2.1 ARM 处理器7种操作模式
  
用户模式(USER MODE)是ARM 通常执行状态,用于执行大多数应用程序;快速中断模式(FIQ MODE)支持数据传输或通道处理;中断模式(IRQ MODE)用于通用中断处理;超级用户模式(SVC MODE)是一种操作系统受保护的模式:数据中止模式(ABT MODE)指令预取指中止、数据中止时进入该模式;未定义模式(UND MODE)当执行未定义的指令时进入该模式;系统模式(SYS MODE)是操作系统一种特许的用户模式。
  
除了用户模式之外,其他模式都归为特权模式,特权模式用于中断服务、异常或者访问受保护的资源。
  
特权模式中除系统模式之外另5种模式又称为异常模式,在移植过程中必须设置中断向量表来处理异常。uCOS II的移植主要处理标准中断(IRQ)、快速中断(FIQ)和软件中断(SWI)。
  
2.2 uCOS II中断响应的过程
  
以IRQ中断为例,假设CRPS中I_bit位为0,当有IRQ中断时,CPU强制进入IRQ模式,当前的CPSR拷贝到SPSR_irq中,PC值保存在LR_irq中,置CPSR中的I位以关闭IRQ中断。数据保存之后,CPU强行从0X00000018开始执行,PC值保存了OS_CPU_IRQ_ISR()的地址, 然后执行OS_CPU_IRQ_ISR()。在OS_CPU_IRQ_ISR()中OS_CPU_IRQ_ISR_Handler()被调用来检测中断源并执行中断。OS_CPU_IRQ_ISR_Handler()返回以后,OS_CPU_IRQ_ISR()又调用OSIntExit()来确认是否有比ISR优先级更高的任务要执行。如果当前中断任务仍然是优先级最高的任务,OSIntExit()返回,OS_CPU_IRQ_ISR()弹出中断堆栈,如果优先级更高的任务需要执行,OSIntExit()调用OSIntCtxSw()执行优先级更高的任务。
  
2.3 uCOS II的临界段代码
  
uCOS II使用关中断来保护临界代码。它定义了2个宏来开中断(OS_EXIT_CRITICAL()),关中断(OS_ENTER_CRITICAL())。OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()有3种方法来实现,uCOS II建议使用第3种方法可以保存当前处理器状态的值。
  
3、uCOS II移植过程中的中断处理
  
uCOS II中断处理跟CRT.S、OS_CPU_A.S和BSP.C有关,其移植过程主要有以下几个步骤。
  
3.1 在CRT.S中设置中断向量表
  
ARM的中断向量表位于ROM 的最底部,其地址范围为0X00000000~0X0000001C,设置如下:

  VECTORS:LDR PC,RESET_ADDR
  LDR PC,UNDEF_ADDR
  LDR PC,SWI_ADDR
  LDR PC,PABT_ADDR
  LDR PC,DABT_ADDR
  NOP /*保留向量*/
  LDR PC,IRQ_ADDR
  LDR PC,FIQ_ADDR
  RESET_ADDR:。 WORD RESET_HANDLER
  UNDEF_ADDR:.WORD UNDEF—HANDLER
  SWI_ADDR:.WORD SWI HANDLER
  PABT_ADDR:.WORD PABT_HANDLER
  DABT_ADDR:.WORD DABT_ HANDLER
  .WORD 0 /*保留地址*/
  IRQ_ADDR:.WORD IRQ_HANDLER
  FIQ_ADDR:.WORD FIQ HANDLER
  UNDEF_HANDLER:B UNDEF_HANDLER
  SWI_HANDLER: B SWI_HANDLER
  PABT_HANDLER: B PABT_HANDLER
  DABT_HANDLER: B DABT_HANDLER
  IRQ_HANDLER: B OS_CPU_IRQ_ISR
  /*跳转到OS_CPU_IRQ_ISR(在OS_CPU_A.S中)*/
  FIQ_HANDLER: B OS_CPU_FIQ_ISR
  /*跳转到OS_CPU_FIQ_ISR(在OS_CPU_A.S中) */

这里设置了标准中断异常(IRQ)和快速中断异常(FIQ)的中断入口,其余异常都设置为死循环,当发生这些异常的时候,必须使系统复位才能退出死循环。
  
3.2 移植中断任务切换
  
中断任务切换(OSIntCtxSw)和任务切换函数(OSCtxSw)比较相似,主要有以下几步组成:

  1)调用OSTask SwHook()

  2)OSPrioCur=OSPrioHighRdy

  3)OSTCBCur=OSTCBHighRdy

  4)SP=OSTCBHighRdy-》OSTCBStkPtr

  //获取高优先级的任务堆栈指针

  5)从高优先级的任务的堆栈中弹出高优先级的任务上下文

  6)执行高优先级的任务

3.3 移植中断服务程序
  
以IRQ中断为例中断服务程序(OS_CPU_IRQ_ISR)主要依据上面所描述的“uCOS II中断响应的过程”编写,其主要代码如下:

  ……
  LDR R0,OS_IntNesting
  LDRB R1,[R0]
  ADD R1,R1,#1
  STRB R1,[R0]
  CMP R1,#l
  BNE OS_CPU_IRQ_ISR_1
  LDR R4,OS_TCBCur
  LDR R5,[R4]
  STR SP,[R5]
  OS_CPU_IRQ_ISR_1:
  MSR CPSR_c,#(NO_INT | IRQ32_MODE)
  //切换到SVC模式
  LDR R0,OS_CPU_IRQ_ISR_Handler
  MOV LR,PC
  BX R0
  MSR CPSR_c,#(NO_INT | SVC32_MODE)
  //切换到SVC模式
  LDRR0,OS_IntExit //OSIntExit()
  MOV LR,PC
  BX R0
  ……
  
在代码中省略了现场工作寄存器的保护与恢复及工作模式的切换。
  
3.4 移植中断处理程序
  
以IRQ中断为例,移植中断处理程序:
  
C程序
  
void OS_CPU_IRQ_ISR_Handler(void){PFNCT pfnct; //定义中断函数指针pfnct=(PFNCT)VICVectAddr; //获取函数地址while(pfnct!=(PFNCT)0){(*pfnct)(); //调用中断函数pfnct=(PFNCT)VICVectAddr; //获取新的中断函数} //所有中断都执行完毕退出}
  
中断处理程序依赖中断控制器的中断响应顺序,所以uCOS II把OS_CPU_IRQ_ISR_Handler()归属于用户程序的一部分。在中断返回之前,中断处理程序要处理完所有的中断响应,以避免在多个中断同时响应或中断处理过程中响应中断的情况下, 进入OS_CPU_IRQ_ISR () 和退出OS_CPU_IRQ_ISR()时,OS_CPU_IRQ_ISR()耗尽保存CPU寄存器的堆栈空间。
  
另外,在OS_CPU_IRQ_ISR_Handler()中不要清CPSR的I位来开放中断,因为没有必要使用中断嵌套,OS_CPU_IRQ_ISR_Handler()在返回之前会检查并处理所有的中断。
  
3.5 编写中断函数
  
中断函数一般采用C语言编写,uCOS II建议中断函数应尽量短,一般做法是在中断函数中缓存数据,给任务发送一个信号来处理数据。中断函数的地址在系统初始化的时候要置人中断向量寄存器(VICVectAddr0~15)。由于向量中断控制器(VIC)的特殊结构,在中断函数中要写一次中断向量寄存器(VICV粗体ectAddr)。
  
4、中断处理的应用示例
  
uCOS II要提供周期性信号源,用于实现时间延时和确认超时。节拍率应为10~100 Hz。时钟节拍源可以由专门的硬件定时器产生,以下就以IRQ中断方式产生节拍源为示例。
  
初始化中断控制器:

C程序
  
void VICInit(void){
VICIntEnClr=0xfffff;
VICDefVectAddr=-(INT32U)Non_Vect_IRQ_Handler;VICVectAddr0= (INT32U)OSTickISR;
VICVectCntl0= (0x20 | 0x04);
VICIntEnable= 1《《4;
}
  
定时器0中断函数:
  
C程序

  void OSTickISR(void)
{
TO_IR = 0xff;
OSTimeTick(); //调用OSTimeTick()
VICVectAddr=0; //通知中断控制器中断结束
}
  
当定时中断发生时调用OS_CPU_IRQ_ISR Handler(),得到OSTickISR()的地址并执行,在OSTickISR()中调用OSTimeTick()为uCOS II提供周期性信号源。
  
此代码在GNU工具链ARM-GCC下编译通过,并在EasyARM2100开发实验板上得到验证。
  
通过示例讲述了在uCOS II移植过程中的中断处理所需要注意的几个问题和通用方法,经笔者在GNU工具链下编译、调试,并在实验板上得到很好的验证。这种移植方案的中断函数都使用C语言编写,具有较好的移植性,有利于对不同需求的用户进行中断扩充,增强了中断嵌套时uCOS II运行的稳定性,使移植具有更好的通用性。
  
二、μCOS-II 在ARM处理器上的移植要点
  
1、设置OS_CPU.H 中与处理器和编译器相关的代码

  /********************************************************************
  *
* 与编译器相关的数据类型
  *********************************************************************
  /
  typedef unsigned char BOOLEAN;
  typedef unsigned char INT8U; //8 位无符号整数
  typedef signed char INT8S; //8 位有符号整数
  typedef unsigned int INT16U; //16 位无符号整数
  typedef signed int INT16S; //16 位有符号整数
  typedef unsigned long INT32U; //32 位无符号整数
  typedef signed long INT32S; //32 位有符号整数
  typedef float FP32; //单精度浮点数
  typedef double FP64; //双精度浮点数
  typedef unsigned int OS_STK; //堆栈入口宽度为16 位
  #define BYTE INT8S //字节型
  #define UBYTE INT8U //为了与uC/OS V1.xx.兼容
  #define WORD INT16S // 。。. uC/OS-II.
  #define UWORD INT16U
  #define LONG INT32S
  #define ULONG INT32U
  /********************************************************************
* 与ARM 处理器相关的代码
  ********************************************************************/
  #define OS_ENTER_CRITICAL() ARMDisableInt() /*关闭中断*/
  #define OS_EXIT_CRITICAL() ARMEnableInt() /*开启中断*/
  /* 设施堆栈的增长方向*/
  #define OS_STK_GROWTH 1 /*堆栈由高地址向低地址增长*/
  
2、用C 语言编写六个操作系统相关的函数(OS_CPU_C.C)

  void *OSTaskStkInit (void (*task)(void *pd),void *pdata, void *ptos, INT16U opt)
  {
  unsigned int *stk;
  opt = opt; /* 因为‘opt’ 变量没有用到,防止编译器产生警告*/
  stk = (unsigned int *)ptos; /*装载堆栈指针*/
  /* 为新任务创建上下文*/
  *--stk = (unsigned int) task; /* pc */
  *--stk = (unsigned int) task; /* lr */
  *--stk = 0; /* r12 */
  *--stk = 0; /* r11 */
  *--stk = 0; /* r10 */
  *--stk = 0; /* r9 */
  *--stk = 0; /* r8 */
  *--stk = 0; /* r7 */
  *--stk = 0; /* r6 */
  *--stk = 0; /* r5 */
  *--stk = 0; /* r4 */
  *--stk = 0; /* r3 */
  *--stk = 0; /* r2 */
  *--stk = 0; /* r1 */
  *--stk = (unsigned int) pdata; /* r0 */
  *--stk = (SVC32MODE|0x0); /* cpsr IRQ, 关闭FIQ */
  *--stk = (SVC32MODE|0x0); /* spsr IRQ, 关闭FIQ */
  return ((void *)stk);
  }
  void OSTaskCreateHook (OS_TCB *ptcb)
  {
  ptcb=ptcb;//防止编译时出现警告
  }
  void OSTaskDelHook (OS_TCB *ptcb)
  {
  ptcb=ptcb;//防止编译时出现警告
  }
  void OSTaskSwHook (void)
  void OSTaskStatHook (void)
  void OSTimeTickHook (void)
  
后5 个函数为钩子函数,可以不加代码。
  
3、用汇编语言编写四个与处理器相关的函数(OS_CPU.ASM)
  
(1)OSStartHighRdy();运行优先级最高的就绪任务

  LDR r4, addr_OSTCBCur ; 得到当前任务的TCB 地址
  LDR r5, addr_OSTCBHighRdy ; 得到高优先级任务的TCB 地址
  LDR r5, [r5] ;得到堆栈指针
  LDR sp, [r5] ;切换到新的堆栈
  STR r5, [r4] ; 设置新的当前任务的TCB 地址
  LDMFD sp!, {r4}
  MSR SPSR_cxsf, r4
  LDMFD sp!, {r4} ; 从栈顶得到新的声明
  MSR CPSR_cxsf, r4
  LDMFD sp!, {r0-r12, lr, pc } ; 开始新的任务
  END

(2)OSCtxSw();任务级的任务切换函数

  STMFD sp!, {lr} ; 保存PC 指针
  STMFD sp!, {lr} ; 保存lr 指针
  STMFD sp!, {r0-r12} ;保存寄存器文件和ret 地址
  MRS r4, CPSR
  STMFD sp!, {r4} ; 保存当前PSR
  MRS r4, SPSR
  STMFD sp!, {r4}
  ; OSPrioCur = OSPrioHighRdy
  LDR r4, addr_OSPrioCur
  LDR r5, addr_OSPrioHighRdy
  LDRB r6, [r5]
  STRB r6, [r4]
  ; 得到当前任务的TCB 地址
  LDR r4, addr_OSTCBCur
  LDR r5, [r4]
  STR sp, [r5] ; 保存栈指针在占先任务的TCB 上
  ; 取得高优先级任务的TCB 地址
  LDR r6, addr_OSTCBHighRdy
  LDR r6, [r6]
  LDR sp, [r6] ;得到新任务的堆栈指针
  ; OSTCBCur = OSTCBHighRdy
  STR r6, [r4] ; 设置当前新任务的TCB 地址set new current task TCB
  address
  LDMFD sp!, {r4}
  MSR SPSR_cxsf, r4
  LDMFD sp!, {r4}
  MSR CPSR_cxsf, r4
  LDMFD sp!, {r0-r12, lr, pc}
  (3)OSIntCtxSw();中断级的任务切换函数
  LDMIA sp!,{a1-v1, lr}
  SUBS pc, lr, #4
  SUB lr, lr, #4
  MOV r12, lr
  MRS lr, SPSR
  AND lr, lr, #0xFFFFFFE0
  ORR lr, lr, #0xD3
  MSR CPSR_cxsf, lr
  (4)OSTickISR();中断服务函数
  STMDB sp!,{r0-r11,lr}
  ;interrupt disable(not nessary)
  mrs r0, CPSR
  orr r0, r0, #0x80 ; 设置中断禁止标
  msr CPSR_cxsf, r0 ;中断结束
  ; rI_ISPC= BIT_TIMER0;
  LDR r0, =I_ISPC
  LDR r1, =BIT_TIMER0
  STR r1, [r0]
  BL IrqStart
  BL OSTimeTick
  BL IrqFinish
  LDR r0, =need_to_swap_context
  LDR r2, [r0]
  CMP r2, #1
  LDREQ pc, =_CON_SW
  
完成了上述工作以后,μCOS-II 就可以正常运行在ARM 处理器上了。

文章来源:互联网(版权归原著作者所有)

围观 528

最近写一个程序,需要在用户模式下关中断,但ARM 7的体系结构决定了中断必须在特权模式下才可以更改,所以想到使用ARM的软中断来实现关中断和开中断。

使用软中断,首先要有硬件指令的支持,ARM有条指令是SWI。

SWI 指令的格式为:

SWI {条件} 24 位的立即数

SWI 指令用于产生软件中断,以便用户程序能调用操作系统的系统例程。操作系统在 SWI 的异常处理程序中提供相应的系统服务,指令中 24 位的立即数指定用户程序调用系统例程的类型,相关参数通过通用寄存器传递,当指令中 24 位的立即数被忽略时,用户程序调用系统例程的类型由通用寄存器 R0 的内容决定,同时,参数通过其他通用寄存器传递。

指令示例:

SWI 0x02 ;该指令调用操作系统编号位02的系统例程。

在keil MDK中,关键字__svc可以产生硬件SWI指令,使得处理器能响应软件中断。关键字__svc、keil MDK帮助文件中这样描述:

__svc 关键字声明超级用户调用 (SVC) 函数,该函数最多使用四个类似于整数的参数,并通过 value_in_regs 结构最多返回四个结果。

__svc 是一个函数限定符。它影响函数的类型。

语法

__svc(int svc_num) return-type function-name([argument-list]);

其中:

svc_num 是在 SVC 指令中使用的立即值。

它是一个表达式,其计算结果为以下范围内的整数:

• 在 ARM 指令中为 0 到 224–1 (24 位值)

• 在 16 位 Thumb 指令中为 0-255 (8 位值)。

要在keil MDK中使用软件中断,要做好两件事:第一件,更改启动文件,编写软件中断的汇编入口。在这个汇编入口中主要根据软件中断命令号进行相应的函数跳转;第二件,编写相应命令号的C语言服务函数。下面举例怎么样用软件中断实现开中断和关中断:

第一步:更改启动代码

keil MDK自带的启动代码有类似下面的语句:

Vectors LDR PC, Reset_Addr
LDR PC, Undef_Addr
LDR PC, SWI_Addr
LDR PC, PAbt_Addr
LDR PC, DAbt_Addr

蓝色语句是程序复位后要执行的第一条指令,即复位异常入口;而红色语句就是执行一个软件中断指令后,要跳转到的软件中断异常入口。通过语句"SWI_Addr DCD SWI_Handler"进行中转,软件中断会跳转到标号为SWI_Handler的语句处,该处即处理软件中断的命令号、源代码如下:

EXPORT SWI_Handler
extern EnableIrqFunc ;使能中断函数名,用C语言实现
extern DisableIrqFunc ;禁止中断函数名,用C语言实现
SWI_Handler
STMFD SP!, {R0,R12,LR} ;入栈
LDR R0, [LR,#-4] ;取指令
BIC R0,R0,#0xFF000000 ;取软件中断命令号
CMP R0,#0 ;和0比较,因为我的使能中断用了软件中断命令0,禁止中断使用了软件中断命令1
BLEQ EnableIrqFunc ;为零调用使能中断函数
BLNE DisableIrqFunc ;不为零调用禁止中断函数
LDMFD SP!,{R0,R12,PC}^ ;出栈

第二部:编写相应命令号的C语言服务函数。

声明软件中断:

__svc(0x00) void EnableIrq(void); //使能中断
__svc(0x01) void DisableIrq(void); //禁止中断

编写服务函数:

void DisableIrqFunc(void)
{
int temp;
__asm
{
MRS temp,SPSR
ORR temp,temp,#0x80
MSR SPSR_c,temp
}
}
void EnableIrqFunc(void)
{
int temp;
__asm
{
MRS temp,SPSR
BIC temp,temp,#0x80
MSR SPSR_c,temp
}
}

到此,使能和禁止中断的软中断就结束了,下面看一下执行过程。

在程序中,如果想关中断,只需使用:DisableIrq();

MDK编译器在执行这句函数时,自动用软中断指令代替,即: SWI 0x01

ARM执行这条软件中断指令后,发生软件中断异常,程序跳转到软件中断异常服务函数处,即汇编代码标号为SWI_Handler处,在这里判断软件中断命令号是0x01,然后执行 BLNE DisableIrqFunc 语句,调用禁止中断函数,实现关中断。

文章来源:博客园

围观 472
围观 307

要使用低成本的 32位处理器,开发人员面临两种选择,基于Cortex-M3内核或者ARM7TDMI内核的处理器。如何做出选择?选择标准又是什么?本文主要介绍了ARM Cortex-M3内核微控制器区别于ARM7的一些特点,帮助您快速选择。

1.ARM实现方法  

ARM Cortex-M3是一种基于ARM V7架构的最新ARM嵌入式内核,它采用哈佛结构,使用分离的指令和数据总线;ARM7是冯诺伊曼结构 冯诺伊曼结构下,数据和指令共用一条总线 。从本质上来说,哈佛结构在物理上更为复杂,但是处理速度明显加快。根据摩尔定理,复杂性并不是一件非常重要的事,而吞吐量的增加却极具价值。  

ARM公司对Cortex-M3的定位是:向专业嵌入式市场提供低成本、低功耗的芯片。在成本和功耗方面,Cortex-M3具有相当好的性能,ARM公司认为它特别适用于汽车和无线通信领域。和所有的ARM内核一样,ARM公司将内该设计授权给各个制造商来开发具体的芯片。迄今为止,已经有多家芯片制造商开始生产基于Cortex-M3内核的微控制器。  

ARM7TDMI(包括ARM7TDMIS)系列的ARM内核也是面向同一类市场的。这类内核已经存在了十多年之久,并推动了ARM成为处理器内核领域的主导者。众多的制造商(据ARM宣称,多达16家)出售基于ARM7系列的处理器以及其他配套的系统软件、开发和调试工具。在许多方面,ARM7TDMI都可以称得上是嵌入式领域的实干家。 

2.两者差异  

除了使用哈佛结构, Cortex-M3 还具有其他显著的优点:具有更小的基础内核,价格更低,速度更快。与内核集成在一起的是一些系统外设,如中断控制器、总线矩阵、调试功能模块,而这些外设通常都是由芯片制造商增加的。 Cortex-M3 还集成了睡眠模式和可选的完整的八区域存储器保护单元。它采用 THUMB-2指令集,最大限度降低了汇编器使用率。 

3.指令集   

ARM7可以使用ARM和Thumb两种指令集,而 Cortex-M3只支持最新的 Thumb-2指令集。这样设计的优势在于: 

• 免去 Thumb和ARM代码的互相切换,对于早期的处理器来说,这种状态切换会降低性能。 

• Thumb-2指令集的设计是专门面向C语言的,且包括If/Then结构(预测接下来的四条语句的条件执行)、硬件除法以及本地位域操作。 

• Thumb-2指令集允许用户在C代码层面维护和修改应用程序,C代码部分非常易于重用。 • Thumb-2指令集也包含了调用汇编代码的功能:Luminary公司认为没有必要使用任何汇编语言。 

• 综合以上这些优势,新产品的开发将更易于实现,上市时间也大为缩短。 

4.中断  

Cortex-M3的另一个创新在于 嵌套向量中断控制器 NVIC( Nested Vector Interrupt Controller)。相对于ARM7使用的外部中断控制器,Cortex-M3内核中集成了中断控制器,芯片制造厂商可以对其进行配置,提供基本的32个物理中断,具有8层优先级,最高可达到240个物理中断和256个中断优先级。此类设计是确定的且具有低延迟性,特别适用于汽车应用。  

NVIC使用的是基于堆栈的异常模型。在处理中断时,将程序计数器,程序状态寄存器,链接寄存器和通用寄存器压入堆栈,中断处理完成后,在恢复这些寄存器。堆栈处理是由硬件完成的,无需用汇编语言创建中断服务程序的堆栈操作。  

中断嵌套是可以是实现的。中断可以改为使用比之前服务程序更高的优先级,而且可以在运行时改变优先级状态。使用末尾连锁( tail-chaining )连续中断技术只需消耗三个时钟周期,相比于 32个时钟周期的连续压、出堆栈,大大降低了延迟,提高了性能。  

如果在更高优先级的中断到来之前, NVIC已经压堆栈了,那就只需要获取一个新的向量地址,就可以为更高优先级的中断服务了。同样的,NVIC不会用出堆栈的操作来服务新的中断。这种做法是完全确定的且具有低延迟性。 

5.睡眠  

Cortex-M3的电源管理方案通过NVIC支持Sleep Now, Sleep on Exit (退出最低优先级的ISR) and SLEEPDEEP modes这三种睡眠模式。为了产生定期的中断时间间隔, NVIC还集成了系统节拍计时器,这个计时器也可以作为RTOS和调度任务的心跳。这种做法与先前的ARM架构的不同之处就在于不需要外部时钟。 

6.存储器保护单元  

存储器保护单元是一个可选组建。选用了这个选项,内存区域就可以与应用程序特定进程按照其他进程所定义的规则联系在一起。例如,一些内存可以完全被其他进程阻止,而另外一部分内存能对某些进程表现为只读。还可以禁止进程进入存储器区域。可靠性,特别是实时性因此得到重大改进。 

7.调试  

对 Cortex-M3 处理器系统进行调试和追踪是通过调试访问端口( Debug Access Port )来实现的。调试访问端口可以是一个 2针的串行调试端口( Serial Wire Debug Port )或者串行 JTAG调试端口( Serial Wire JTAG Debug Port )。通过 Flash片、断点单元、数据观察点、跟踪单元,以及可选的嵌入式跟踪宏单元( Embedded Trace Macrocell )和指令跟踪宏单元( Instrumentation Trace Macrocell )等一系列功能相结合,在内核部分就可以采用多种类型的调试方法及监控函数。例如,可以设置断点、观察点、定义缺省条件或执行调试请求、监控停止操作或继续操作。所有的这些功能在 ARM架构的产品中已经实现,只是 Cortex-M3 将这些功能整合起来,方便开发人员使用。 

8.应用范围  

虽然 ARM7内核并没有像Cortex系列那样集成很多外设,但是大量的基于ARM7的器件,从通用MCU,到面向应用的MCU、SOC甚至是Actel公司基于ARM7内核的FPGA,都拥有更为众多的外围设备。大约有150种MCU是基于ARM7内核的(根据不同的统计方法,这个数字可能会更高)。   

你会发现 ARM7都可以实现几乎所有的嵌入式应用,或采用定制的方式来满足需求。基于标准内核,芯片厂商可以加入不同类型、大小的存储器和其他外围设备,比如串行接口、总线控制器、存储器控制器和图形单元,并针对工业、汽车或者其他要求苛刻的领域,使用不同的芯片封装,提供不同温度范围的芯片版本。芯片厂商也可能绑定特定的软件,比如TCP/IP协议栈或面向特定应用的软件。

芯片厂商也可以选择利于开发人员开发产品的措施,比如采用 ARM的 嵌入式跟踪宏单元 ETM( Embedded Trace Macrocell ),并提供开发和调试工具。  

9.配套工具

ARM7应用已经非常普及,它已经有非常多第三方的开发和调试工具支持。在ARM的网站上有超过130家工具公司名称列表。   

大多数厂商提供了基本的开发板,并提供下载程序的接口、调试工具以及外部设备的驱动,包括 LED灯的显示状态或者屏幕上的单行显示。通常,开发套件包括编译器、一些调试软件以及开发板。更为高级的套件包括第三方的集成开发环境(IDE),IDE中包含编译器、链接器、调试器、编辑器和其他工具,也可能包括仿真硬件,比如说JTAG仿真器。   

内电路仿真器( ICE)是最早的也是最有用的调试工具形式之一,很多厂商都在ARM7上提供了这一接口。   

软件开发工具范围很广:从建模到可视化设计,到编译器。现在很多的产品也用到实时操作系统( RTOS)和中间件,以加速开发进程、降低开发难度。另外,还有一个非常重要的因素,很多的开发人员对 ARM7的开发经验非常丰富。   

虽然现在已经有新兴的 Cortex-M3 工具,但显然还是有一定的差距。不过, Cortex-M3的集成调试性能使调试变得简单且有效,且无需用到内电路仿真器ICE。  

10.决策   

那么,你应该如何做出何种选择呢?如果成本是最主要考虑因素,您应该选择 Cortex-M3;如果在低成本的情况下寻求更好的性能和改进功耗,您最好考虑选用Cortex-M3;特别是如果你的应用是汽车和无线领域,最好也采用Cortex-M3,这正是Coretex-M3的主要定位市场。由于 Cortex-M3内核中的多种集成元素以及采用Thumb-2指令集,其开发和调试比ARM7TDMI要简单快捷。   

然而,由于重定义 ARM7TDMI的应用不是一件困难的事,特别是在使用了RTOS的情况下。保守者可能会沿用ARM7TDMI内核的芯片,并避免使用那些会使重定义变得复杂的功能。

围观 543

一、Cortex M3的GPIO口特性

在介绍GPIO口功能前,有必要先说明一下M3的结构框图,这样能够更好理解总线结构和GPIO所处的位置。

Cortex M3结构框图

从图中可以看出,GPIO口都是接在APB总线上的,而且M3具有两个AHB到APB桥,GPIO则直接接在AHB矩阵上,这样可以减少CPU和DMA控制器之间的竞争冲入,获得较高性能。APB总线桥配置为写缓冲区,使得CPU或DMA控制器可直接操作APB外设,而无需等待总线写操作完成。

M3数字I/O功能:

高速GPIO口,其寄存器被移到外设AHB总线,可以字节,半字和字寻址。

位电平置位和清零寄存器允许单指令置位和清零一个端口的任意位。

所有GPIO口寄存器支持M3位带操作。

整个端口值可以用一条指令写入。

GPIO口寄存器可由GPDMA控制器进行访问,可以进行DMA数据操作,使之与DMA请求同步。

单个I/O口方向可以控制。

所有I/O口在复位后默认作为上拉输入。(Why?因为微控制器连接了很多设备,如果复位后作为输出,则由于控制器电平状态不定,可能会导致外围设备产生动作,从而产生不利影响,故复位后一半都作为输入状态。)

M3可产生中断的数字端口:

PORT0 和 PORT2 端口的每个引脚都可以提供中断功能;

每个端口上的中断可被编程为上升沿、下降沿或边沿产生中断;

边沿检测是异步的,因此可以在没有时钟的情况下(例如掉电模式)操作。使用这种特性,就无需电平触发中断;

可掉电唤醒;

寄存器为软件提供挂起的上升沿中断、挂起的下降沿中断和整个挂起的 GPIO中断;

GPIO0 和 GPIO2 中断与外部中断 3 事件共用相同的 NVIC 通道。

二、GPIO口的寄存器描述

Cortex M3引脚的寄存器描述:

PINMODEx表示引脚模式选择寄存器,在使用前要配置好。

引脚模式选择寄存器位

PINMODEx
功能
复位后的值
00
引脚使能上拉电阻
00
01
中继模式
10
引脚无片内上拉或下拉电阻
11
引脚使能下拉电阻

中继模式说明:当引脚处于逻辑高电平,中继模式能使能上拉电阻;当引脚处于逻辑低电平时,中继模式会使能下拉电阻,这样当引脚配置为输入且没有外部驱动时,能够保持上一个已知状态。

PINSELx:功能选择寄存器。用来设定PORT引脚的功能,当PINSELx各位为0时,才用作GPIO端口。

FIOxDIR:GPIO口方向寄存器,单独控制每个端口管脚的方向,可作为字节(8位),半字(16位)和字长(32位)的数据进行访问。

FIOxMASK:屏蔽寄存器。任何写、读的操作只在该寄存器对应位为“0“时才有效。

FIOxPIN:管脚值寄存器。只要管脚不配置为ADC,其他所有方式都可以从该位读出端口当前的实际状态。注:如果读FIOPIN寄存器,那么不管物理引脚的状态如何,在 FIOMASK寄存器中被“1”屏蔽的位将始终读出0。

FIOxSET:输出引脚的状态。写 1 使相应的端口引脚产生高电平。写 0 没有影响。读该寄存器,返回端口输出寄存器的当前内容。只可以更改 FIOMASK 中为 0 的位,即非屏蔽位。

FIOxCLR:控制输出引脚的状态。写 1 使相应的端口引脚产生低电平。写 0 没有影响。只可以更改 FIOMASK 中为 0 的位,即非屏蔽位。

2.1 GPIO端口方向寄存器FIOxDIR(FIO0DIR??FIO4DIR- 0x2009 C000??0x2009 C080)
  
当引脚被配置为 GPIO功能时,该寄存器可用来控制引脚的方向。务必根据引脚功能来设置每个引脚的方向。
注:GPIO引脚 P0.29和P0.30 与USB D+/-引脚共用,并且具有相同的方向。如果FP0DIR位29或位30在FIO0DIR寄存器中被配置为零,则P0.29 和P0.30都为输入。如果FP0DIR位29和位30被配置为1,则P0.29和P0.30都为输出。

高速GPIO端口方向寄存器位描述

符号
描述
复位值
31:0(字长数据)
FP0DIR
FP1DIR
FP2DIR
FP3DIR
FP4DIR
0
 
1
控制的引脚为输入引脚
 
控制的引脚为输出引脚
0

字和半字的操作基本类似,只是可以通过8位寄存器或者16位的寄存器分别控制方向而已。

2.2 GPIO端口输出设置寄存器FIOxSET(FIO0SET??FIO7SET - 0x2009 C018??0x2009 C098)
  
当引脚在输出模式中被配置为 GPIO 时,该寄存器在端口引脚产生高电平输出。向该寄存器的某些位写入“1”时,对应的引脚产生高电平。写入“0”无效。如果需要引脚输出低电平或第二种功能,那么写 1 到 FIOxSET 的相应位无效。 读FIOxSET 寄存器返回该寄存器的值,该值由前一次对 FIOxSET 和 FIOxCLR(或前面提到的 FIOxPIN)的写操作确定,它不反映任何外部环境对 I/O引脚的影响。 通过 FIOxSET 寄存器访问的端口引脚受到 FIOxMASK 寄存器相应位的限制。

高速GPIO端口输出设置寄存器位描述

符号
描述
复位值
31:0(字长数据)
FP0SET
FP1SET
FP2SET
FP3SET
FP4SET
0
 
1
控制的引脚输出不改变         
控制的引脚输出被设为高电平
0

2.3 GPIO端口输出清零寄存器FIOxCLR(FIO0CLR??FIO07CLR - 0x2009 C01C??0x2009 C09C)
  
当引脚在输出模式中被配置为 GPIO 时,该寄存器在端口引脚产生低电平输出。向某些位写入“1”会使相应的引脚产生低电平,同时清零 FIOxSET 寄存器的相应位。写入“0”无效。如果引脚被配置为输入或其它功能,那么写 FIOxCLR 对引脚没有影响。 通过FIOxCLR寄存器访问的端口引脚受到FIOxMASK寄存器相应位的限制.

高速GPIO端口输出清零寄存器位描述

符号
描述
复位值
31:0(字长数据)
FP0CLR
FP1CLR
FP2CLR
FP3CLR
FP4CLR
0
 
1
控制的引脚输出不改变         
控制的引脚输出被设为低电平
0

  
2.4 GPIO端口引脚值寄存器FIOxPIN(FIO0PIN??FIO7PIN- 0x2009 C014??0x2009 C094)
  
该寄存器提供了端口引脚的值,可配置这些值来执行仅为数字的功能。该寄存器将给出引脚的当前逻辑值,而不管引脚是否配置为输入或输出,或作为 GPIO或作为其它可选的数字功能。
  
例如,特殊的端口引脚可能具有 GPIO输入、GPIO 输出、UART 接收和 PWM 输出等可选功能。无论该引脚配置成何种功能,都可以从相应的 FIOxPIN 寄存器中读出其当前的逻辑状态。 如果引脚配置为模拟功能,当选择了模拟配置时,引脚状态不能被读出。将引脚选择用作A/D输入会断开与引脚数字部分的连接。在这种情况下,从 FIOxPIN 寄存器中读出的引脚值无效。
  
写 FIOxPIN 寄存器时, FIOxPIN 寄存器的值会保存到端口输出寄存器,而无需使用 FIOxSET和 FIOxCLR寄存器来获得整个写入值。由于这种特性影响整个端口,因此在应用中时要小心。 通过 FIOxPIN 寄存器访问的端口引脚受到 FIOxMASK 寄存器相应位的限制。 只有在屏蔽寄存器中用0 屏蔽的引脚与高速 GPIO 端口引脚值寄存器的当前内容相互关联。

高速GPIO端口引脚值寄存器位描述

符号
描述
复位值
31:0(字长数据)
FP0VAL
FP1VAL
FP2VAL
FP3VAL
FP4VAL
0
 
1
控制的引脚输出设为低电平
控制的引脚输出设为高电平
0

2.5 高速GPIO端口屏蔽寄存器FIOxMASK (FIO0MASK??FIO7MASK - 0x2009 C010??0x2009 C090)
  
该寄存器用来屏蔽某些端口引脚,被屏蔽的引脚将无法通过 FIOxPIN、 FIOxSET 或 FIOxCLR寄存器写访问。当读FIOxPIN 寄存器时,屏蔽寄存器还将过滤相应端口的内容。

通过读或写访问,该寄存器中为“0”的位使能相应物理引脚的访问。如果该寄存器中的位为“1”,则相应位将不会通过写访问改变,并且读操作时将不会在更新的 FIOxPIN 寄存器中反映出来。

高速GPIO端口引脚值寄存器位描述

符号
描述
复位值
31:0(字长数据)
FP0VAL
FP1VAL
FP2VAL
FP3VAL
FP4VAL
0
 
1
控制的引脚输出设为低电平
控制的引脚输出设为高电平
0

对于常见的ARM处理器,它们的GPIO口基本上可以配置为输入模式、输出模式、开漏或推挽模式。

开漏输出与推挽输出的区别:
  
推挽输出:推挽结构一般是指两个三极管分别受两互补信号的控制,总是在一个三极管导通的时候另一个截止。可以输出高,低电平,连接数字器件,正常的拉出/灌入电流为4mA,短时间极限值可以达到40mA,但不是每个引脚都能输出这么多
  
开漏输出:输出端相当于三极管的集电极。要得到高电平状态需要上拉电阻才行。适合于做电流型的驱动,其吸收电流的能力相对强(一般20mA以内)。
  
开漏电路概念中提到的“漏”就是指MOS FET的漏极。同理,开集电路中的“集”就是指三极管的集电极。开漏电路就是指以MOS FET的漏极为输出的电路。一般的用法是会在漏极外部的电路添加上拉电阻。完整的开漏电路应该由开漏器件和开漏上拉电阻组成。
  
组成开漏形式的电路有以下几个特点:
  
1. 利用外部电路的驱动能力,减少IC内部的驱动。当IC内部MOSFET导通时,驱动电流是从外部的VCC流经R pull-up,MOSFET到GND。IC内部仅需很小的栅极驱动电流。如图1。
  
2. 可以将多个开漏输出的Pin,连接到一条线上。形成 “与逻辑” 关系。如图,当PIN_A、PIN_B、PIN_C任意一个变低后,开漏线上的逻辑就为0了。这也是I2C,SMBus等总线判断总线占用状态的原理。
  
3. 可以利用改变上拉电源的电压,改变传输电平。IC的逻辑电平由电源Vcc1决定,而输出高电平则由Vcc2决定。这样我们就可以用低电平逻辑控制输出高电平逻辑了。
  
4. 开漏Pin不连接外部的上拉电阻,则只能输出低电平(因此对于经典的51单片机的P0口而言,要想做输入输出功能必须加外部上拉电阻,否则无法输出高电平逻辑)。

问题集锦

一、准双向IO结构的特点是

1 输出结构类似 OC门,输出低电平时,内部NMOS导通,驱动能力较强(800uA);输出高电平靠内部上拉电阻,驱动能力弱(60uA)。

2 永远有内部电阻上拉,高电平输出电流能力很弱,所以即使IO口长时间短路到地也不会损坏IO口(同理,IO口低电平输出能力较强,作低电平输出时不能长时间短路到VCC)

3 作输入时,因为OC门有"线与"特性,必须把IO口设为高电平(所以按键多为共地接法)

4 作输出时,输出低电平可以推动LED(也是很弱的),输出高电平通常需要外接缓冲电路(所以LED多为共阳接法)

5 软件模拟 OC结构的总线反而比较方便-----例如 IIC总线

* OC门:三极管的叫集电极开路,场效应管的叫漏极开路,简称开漏输出。具备"线与"能力,有0得0。
* 为什么设计成输出时高电平弱,低电平强----是考虑了当年流行的TTL器件输入

二、IO不同模式的区别?

简单的说:

“准双向IO口”在读前必须先用写指令置"1",才能读入;写则无须此步。

“真正的双向IO口”可直接读写。

“三态IO口”有高,低电平,高阻状态,高阻本人理解:相当此脚与内部电路断开。

文章来源:博客园

围观 1011

1、基本概念(CMSIS):

Cortex Micro-controller Software Interface Standard,微控制器软件接口标准。

2、CMSIS标准的文件结构:

a) core_cm.c (stdint.h)

b) system_.c (core_cm, system_)

c) startup_.s

其中core_cm.c以及core_cm中为内核外设访问层,其中定义了内核中的外设以及一些内核的访问及控制函数。
startup_.s文件是系统的启动文件,其包括堆和栈的初始化配置、中断向量表的配置以及将程序引导到main()函数等功能。

system_和system_.c文件则是由ARM公司提供模版,各芯片制造商根据自己芯片的特点来编写的。

3、注解startup_.s文件

此文件主要完成三项工作:堆栈以及堆的初始化、定位中断向量表、调用Reset Handler

a) 堆栈以及堆的初始化

; Stack Configuration
; Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
;
Stack_Size EQU 0x00000200
AREA STACK, NOINIT, READWRITE, ALIGN=3
;指明8字节对齐(ALIGN=3)

Stack_Mem SPACE Stack_Size
__initial_sp ;此标号有一层隐含的意思那,就是在M3中堆栈是满递减堆栈,
;因为它指定了堆栈指针位于堆栈的高地址(在//Stack_Mem之后)

; Heap Configuration
; Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
;

Heap_Size EQU 0x00000000
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit

以上堆和栈的具体地址可以在工程编译后产生的*.map文件中看到。

b) 定位中断向量表

PRESERVE8 ;PRESERVE8指定了以下的代码位8字节对齐
THUMB ;THUMB指定了接下来的代码为THUMB指令集

; Vector Table Mapped to Address 0 at Reset
AREA RESET, DATA, READONLY ;此语句声明RESET数据段
EXPORT __Vectors ;导出向量表标号,EXPORT作用类似于C语言中的extern
__Vectors
DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
DCD MemManage_Handler ; MPU Fault Handler
DCD BusFault_Handler ; Bus Fault Handler
DCD UsageFault_Handler ; Usage Fault Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVC_Handler ; SVCall Handler
DCD DebugMon_Handler ; Debug Monitor Handler
DCD 0 ; Reserved
DCD PendSV_Handler ; PendSV Handler
DCD SysTick_Handler ; SysTick Handler
; External Interrupts
DCD WDT_IRQHandler ; 16: Watchdog Timer
DCD TIMER0_IRQHandler ; 17: Timer0
DCD TIMER1_IRQHandler ; 18: Timer1
DCD TIMER2_IRQHandler ; 19: Timer2
DCD TIMER3_IRQHandler ; 20: Timer3
DCD UART0_IRQHandler ; 21: UART0
;(……省略)

c) 调用Reset Handler

; Reset Handler

Reset_Handler
PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP

注释:引导程序进入__main(此__main是C_Library中的函数,非main())

d) 堆栈以及堆的初始化行为

; User Initial Stack & Heap
IF :DEF:__MICROLIB
EXPORT __initial_sp
EXPORT __heap_base
EXPORT __heap_limit
ELSE
IMPORT __use_two_region_memory
EXPORT __user_initial_stackheap
__user_initial_stackheap
LDR R0, = Heap_Mem
LDR R1, = (Stack_Mem + Stack_Size)
LDR R2, = (Heap_Mem + Heap_Size)
LDR R3, = Stack_Mem
BX LR

e) ARM m3 C是怎么调用startup.s文件的?

startup.s大部分内容不是被C调用的,而是在C程序之前运行的。m3上电之后会先从0地址处读取MSP,然后从0x4地址处读取复位向量,接着跳转到复位异常服务程序Reset_Handler(这些是m3内核自动做的,不需要编程)。如果你用MDK的话,在工程设置Debug下的run to main()上的勾去掉,然后进入调试,你会发现你运行的第一句就是Reset_Handler的第一句。
  
Reset_Handler就是在startup.s中定义的,它一般会对系统初始化,然后进入main函数。
  
向量表也是在startup.s中定义的,至于为什么程序编译之后向量表一定在0地址处,是因为向量表的前面会有类似AREA RESET, CODE, READONLY的声明。在MDK生成的分散加载文件中,RESET被设置在flash的0地址处,这样就规定了向量表的地址。

文章来源 : 博客园

围观 847

keil MDK也是可以借助h-jtag进行单步调试,写出来与大家一起分享一下:

keil MDK编译器使用V4.01版本,下载地址:

http://www.embedinfo.com/down-list.asp?id=714 (需要注册一下)

h-jtag使用V1.0版本(请注意,一定要用V1.0或者以上版本才可以与mdk兼容),下载地址

http://www.hjtag.com/download/H-JTAG%20V1.0%20Preview.zip

分别安装MDK与h-jtag

两个软件都安装完成后,首先,需要运行H-JTAG 安装目录下的TOOLCONF.EXE 程序,对KEIL 安装目录下的TOOLS.INI 配置文件进行更新。如下图所示。点击Config 按钮,对TOOLS.INI 进行配置,然后退出。注意在点击Config之前,要退出keil编译器。

接下来,就可以在 KEIL 下对项目进行配置。首先,重新运行KEIL,并在KEIL 中打开一个项目,然
后点击Project -> Options for Target…菜单,接下来,会弹出下图所示的Options 配置窗口。

在上图所示的Options 配置窗口中,选择Debug 设置,点击标签下的如图所示下拉按键,就可以看到H-JTAG ARM 调试驱动。如下图所示:

选中使用h-jtag硬件仿真,点击 OK 按钮,回到KEIL 的主窗口,KEIL 的设置就完成了。

然后编译程序,生成hex的目标文件,利用h-jtag的flash下载工具将目标文件下载到硬件。

下载完毕后,使用Crtl+F5进入单步调试界面。

围观 457

页面

订阅 RSS - Cortex-M3