By Toradex秦海
1). 简介
在工业领域,很多时候会遇到实时任务和主控界面同时需要的场景,比如工业自动化的控制器等,通常情况下传统做法是分别使用两个独立的处理器,比如一个Cortex-M4 ARM处理器来完成实时任务,另外再使用一个Cortex-A系列的ARM处理器来处理主控界面和命令控制,两个处理器之间再通过某种通讯总线来互联互通,比如串口,SPI之类。
这样做的好处是两个处理器相对分隔独立,但缺点也很明显,系统复杂性提高,数据面和控制面要单独建立,正式基于此NXP提出了一个新的思路,就是在一个芯片中集成这两个功能核心。
而本文所演示的ARM平台来自于Toradex Apalis iMX7 ARM嵌入式平台,这是一个基于NXP iMX7 ARM处理器的ARM计算机模块,在这个芯片中,NXP将Cortex-A7 ARM核心和Cortex-M4 ARM核心集成到了同一个芯片里面,并且两个核心共享存储和外设资源,这使得对于上面提到的应用模式可以更精巧,高效的实现,接下来本文会基于这个平台进行一个简单的应用开发以及调试示例。
2. 准备
a).
Colibri iMX7S ARM核心版配合
Colibri Evaluation Board,分别连接A7核心默认调试串口UART1(载板X27)和M4核心默认调试串口UART2(载板X25上)到开发主机方便调试,另外由于iMX7S只支持一个USB接口,需要通过载板X30连接一个USB Hub后来扩展键盘鼠标外设。更多关于Colibri iMX7的说明请参考
Datasheet和
Linux开发上手指南。
b). Colibri iMX7 A7核心系统使用集成Qt运行库的Linux BSP V2.7版本,如何编译和部署集成Qt image以及配置Qt开发环境请参考
这里。
c). 另外,由于本文演示示例使用到了载板上面的LED和按键资源,需要连接如下:
X10 SODIMM-106 -> X21 LED3
X10 SODIMM-135 -> X21 LED1
X10 SODIMM-133 -> X21 SW6
X10 SODIMM-127 -> X21 LED2
d). SEGGER J-Link 仿真器,USB一端连接开发主机,JTAG一端连接载板X13。
3). Colibri iMX7 M4核心FreeRTOS基本资料
a). Colibri iMX7 架构基本说明请参考如下:
https://developer.toradex.cn/knowledge-base/freertos-on-the-cortex-m4-of-a-colibri-imx7
b). 本示例中M4核心运行FreeRTOS v8系统,相关的源代码和sample程序请从下面git下载:
http://git.toradex.cn/cgit/freertos-toradex.git/
c). 基本的SDK配置和编译请参考如下:
https://developer.toradex.cn/knowledge-base/freertos-on-the-cortex-m4-of-a-colibri-imx7#Linux_support
d). 编译好的M4 firmware如何在Colibri iMX7上面加载运行请参考如下:
https://developer.toradex.cn/knowledge-base/freertos-on-the-cortex-m4-of-a-colibri-imx7#Running_a_Firmware_on_CortexM4
e). 几个自带的sample代码简单说明请参考如下:
https://developer.toradex.com/knowledge-base/freertos-on-the-cortex-m4-of-a-colibri-imx7#Examples
4). Colibri iMX7 M4核心调试环境配置
a). 在上一章节编译部分资料中有提到编译自带sample code只需要执行项目中的 build_all.sh 脚本,就可以生成release和debug项目,然后进入debug项目目录,打开“build_debug.sh”脚本,可以看到通过“-G”参数指定了编译系统,这里默认是“Eclipse CDT4 - Unix Makefiles”,支持的是Eclipse指定了,因此本文示例就基于Eclipse进行调试。
b). 由于Ubuntu 16.04 系统自带的Eclipse版本比较低,不支持后续需要的plugin,因此需要手动安装最新版本的Eclipse:
./ 首先安装最新版本的openjdk
-------------------------------
$ sudo add-apt-repository ppa:openjdk-r/ppa
$ sudo apt-get update
$ sudo apt-get install openjdk-8-jdk
-------------------------------
./ 从下面地址下载最新的Eclipse CPP,解压后可以直接运行,无需安装。
http://www.eclipse.org/downloads/packages/
c). 下载安装J-Link software and documentation pack,安装好第一次运行,会自动检查J-Link firmware并升级到最新版本。
https://www.segger.com/products/debug-probes/j-link/
d). 运行Eclipse CPP,安装J-Link GDB plugin
-------------------------------
// Main menu -> Help -> install new software
// 输入下面地址
https://dl.bintray.com/gnu-mcu-eclipse/updates/
// 在列表里面安装下面plugin
GNU ARM C/C++ J-Link Debugging
-------------------------------
e). 在Eclipse 中导入需要debug的项目
-------------------------------
./ 选择 File -> Import -> General -> Existing Projects into Workspace
./ 在 “Select root directory”,输入项目“armgcc/debug”文件夹目录地址,此时会自动识别出已经编译好的debug项目,完成项目导入,比如本次示例项目名字为gpio-freertos,导入如下:
f). 在Eclipse 中进行debug GDB参数配置
./ 打开 Run –> Debug Configurations,可以看到左边侧栏中 GDB SEGGER J-Link Debugging项目下一般会自动出现刚才导入的项目,右边是对应的一些选项。
./ Main选项卡,一些基本名字等信息
./ Debugger 选项卡
需要注意的地方:
// Device name,Colibri iMX7对应就是这个名字,具体的列表可以参考
这里
// Interface选择使用的仿真器接口,我这里使用的是JTAG的
// Other options,非常关键,-scriptfile指定的文件请从
这里下载使用即可,其他参数一样就行,当然熟悉配置的话也可以进行修改。
// GDB Client Setup -> Executable,设定为SDK目录下的bin/arm-none-eabi-gdb文件
./ Startup 选项卡
需要注意的地方:
// 取消 Enable flash breakpoints
// 添加命令行 monitor reset 0
// 勾选 RAM application (reload after each reset/restart)
g). 至此,GDB配置完毕,点击Debug按钮即可进行debug了。
5). Colibri iMX7 M4核心示例程序
a). 本程序主要实现三个并行任务:
./ LED1, LED2和LED3的跑马灯任务,时间间隔从最小100ms到最大1000ms,每档间隔为100ms。
./ 按键中断任务,每按键一次,跑马灯的时间间隔增加100ms,如果已经到达1000ms上限,再次按键则回到100ms初始值。同时在每次跑马灯时间间隔更改后,给A7核心系统发消息通知。
./ 和A7核心通讯任务,当接收到A7发来的跑马灯时间间隔指令后,按指令配置跑马灯时间间隔,同时配置完成后给A7核心发消息通知。
b). 具体代码请见如下git地址
https://github.com/simonqin09/iMX7_M4_Runniung_LED_Demo/tree/master/gpio_freertos
./ 代码中对应上面三个任务分别由三个task实现
跑马灯 – ToggleTask
按键 – SwitchTask
通讯 – StrEchoTask
./ ToggleTask就是简单的通过vTaskDelay实现了跑马灯的间隔时间
./ SwitchTask 通过GPIO中断响应,来捕获按键同时更新间隔时间,并通知A7
./ StrEchoTask主要通过OPAMP/Rpmsg实现和A7消息的接收,另外通过Semaphore来实现几个task之间的切换,关于Semaphore的使用是异构双核架构下M4编程的重点,具体可以参考下面FreeRTOS官方文档说明:
https://www.freertos.org/a00113.html
6). Colibri iMX7 A7核心示例程序
a). 在展示A7程序代码之前需要先进行一些关于A7 Linux系统的说明:
./ 由于iMX7 A7和M4是共享外设,因此在开发前需要先区分好M4所需要的外设,同时在A7 Linux的device tree
中将这些外设disable,以免产生冲突,比如本示例,主要就使用了几个GPIO资源,以及M4调试串口,因此需要在A7 device tree中确保未使用对应的GPIO和串口资源,具体关于device tree的修改编译这里就不详述了,具体可以参考
这里。当然,如果只是临时测试,也可以直接在uboot中配置,详细可以参考如下:
https://developer.toradex.cn/knowledge-base/freertos-on-the-cortex-m4-of-a-colibri-imx7#Running_a_Firmware_on_CortexM4
./ 如果需要M4和A7通过Rpmsg进行通信,需要在A7 Linux下加载相关驱动,目前Toradex Linux BSP V2.7版本已经包含了驱动,只需要通过下面方式加载即可:
-------------------------------
modprobe imx_rpmsg_tty
-------------------------------
另外,如果需要开机自动加载,可以增加一个systemd自启动项目来实现。
b). A7 Rpmsg通讯的Qt应用代码如下:
https://github.com/simonqin09/iMX7_M4_Runniung_LED_Demo/tree/master/qt-rpmsg
./ 程序分为两个线程,主线程mainwindow实现主要图形界面显示,同时实现发送消息功能;另外一个子线程主要负责实时获取M4发来的消息并显示在主界面的对应位置。
./ 由于Rpmsg Linux驱动加载后,会虚拟出一个串口设备,因此基本的发送接收就是Linux下串口的基本操作,具体说明可以参考
这里。
7). 完整程序的部署测试
a). 首先在uboot下通过SD卡或者tftp将编译好的M4核心firmware下载保存到imx7 flash里面并开机自动加载,通过SD卡相关命令可以参考
这里。
-------------------------------
// download
# ubi part ubi
# tftp ${loadaddr} gpio_freertos.elf
# ubi write ${loadaddr} m4firmware ${filesize}
// autorun
# setenv m4boot 'ubi read ${loadaddr} m4firmware && bootaux ${loadaddr}'
# saveenv
-------------------------------
b). 然后进入linux,创建两个开机自启动服务,一个用于加载imx_rpmsg_tty驱动,另外一个用于加载Qt应用程序qt-rpmsg
-------------------------------
// script to start imx_rpmsg_tty
$ cd /home/root
$ vi rpmsg
#!/bin/bash
modprobe imx_rpmsg_tty
exit 0
// system service file to autorun rpmsg on startup
$ cd /etc/systemd/system
$ vi rpmsg-load.service
[Unit]
Description=load Rpmsg driver
After=multi-user.target
[Service]
Type=simple
ExecStart=/home/root/rpmsg
[Install]
WantedBy=multi-user.target
$ systemctl enable rpmsg-load.service
-------------------------------
关于qt应用qt-rpmsg的开机自动加载请参考这里
说明,这里就不赘述。
c). 重新启动,可以看到在开机马上uboot启动瞬间LED跑马灯已经开始运转,证明M4 firmware已经运行起来,然后Linux启动后Qt应用起来,可以对跑马灯时间间隔进行增加和减少操作,同时按键更改跑马灯时间间隔的结果也会即时反馈到应用界面上来。
8). 总结
通过上述示例可见,通过iMX7这样异构多核架构的处理器,可以更简洁高效的实现原来需要两个分立处理器来完成的任务,简化的硬件设计,软件开发也相对更统一,数据面分享可以直接通过内存共享非常方便,相信未来会有越来越多的嵌入式应用采用这样的方案。