Blog:
NXP iMX7 异构双核心开发调试
简介
在工业领域,很多时候会遇到实时任务和主控界面同时需要的场景,比如工业自动化的控制器等,通常情况下传统做法是分别使用两个独立的处理器,比如一个 Cortex-M4 Arm 处理器来完成实时任务,另外再使用一个 Cortex-A 系列的 Arm 处理器来处理主控界面和命令控制,两个处理器之间再通过某种通讯总线来互联互通,比如串口,SPI之类。
这样做的好处是两个处理器相对分隔独立,但缺点也很明显,系统复杂性提高,数据面和控制面要单独建立,正式基于此 NX P提出了一个新的思路,就是在一个芯片中集成这两个功能核心。
而本文所演示的 Arm 平台来自于 Toradex Apalis iMX7 Arm 嵌入式平台,这是一个基于 NXP iMX7 Arm 处理器的 Arm 计算机模块,在这个芯片中,NXP 将 Cortex-A7 Arm 核心和Cortex-M4 Arm 核心集成到了同一个芯片里面,并且两个核心共享存储和外设资源,这使得对于上面提到的应用模式可以更精巧,高效的实现,接下来本文会基于这个平台进行一个简单的应用开发以及调试示例。
准备
Colibri iMX7S Arm 核心版配合 Colibri Evaluation Board,分别连接 A7 核心默认调试串口 UART1(载板X27)和 M4 核心默认调试串口 UART2(载板X25上)到开发主机方便调试,另外由于 iMX7S 只支持一个 USB 接口,需要通过载板 X30 连接一个 USB Hub 后来扩展键盘鼠标外设。更多关于 Colibri iMX7 的说明请参考 Datasheet 和 Linux 开发上手指南。
Colibri iMX7 A7 核心系统使用集成 Q t运行库的 Linux BSP V2.7 版本,如何编译和部署集成 Qt image 以及配置 Qt 开发环境请参考这里。
另外,由于本文演示示例使用到了载板上面的 LED 和按键资源,需要连接如下:
X10 SODIMM-106 -> X21 LED3
X10 SODIMM-135 -> X21 LED1
X10 SODIMM-133 -> X21 SW6
X10 SODIMM-127 -> X21 LED2
SEGGER J-Link 仿真器,USB 一端连接开发主机,JTAG一端连接载板 X13。
Colibri iMX7 M4核心FreeRTOS基本资料
Colibri iMX7 架构基本说明请参考如下:
https://developer.toradex.cn/knowledge-base/freertos-on-the-cortex-m4-of-a-colibri-imx7
本示例中 M4 核心运行 FreeRTOS v 8系统,相关的源代码和 sampl e程序请从下面 git下载:
http://git.toradex.cn/cgit/freertos-toradex.git/
基本的 SD K配置和编译请参考如下:
https://developer.toradex.cn/knowledge-base/freertos-on-the-cortex-m4-of-a-colibri-imx7#Linux_support
编译好的 M4 firmware 如何在 Colibri iMX7 上面加载运行请参考如下:
https://developer.toradex.cn/knowledge-base/freertos-on-the-cortex-m4-of-a-colibri-imx7#Running_a_Firmware_on_CortexM4
几个自带的 sample 代码简单说明请参考如下:
https://developer.toradex.com/knowledge-base/freertos-on-the-cortex-m4-of-a-colibri-imx7#Examples
Colibri iMX7 M4核心调试环境配置
在上一章节编译部分资料中有提到编译自带 sample code 只需要执行项目中的 build_all.sh 脚本,就可以生成 release 和 debug 项目,然后进入 debug 项目目录,打开“build_debug.sh” 脚本,可以看到通过 “-G” 参数指定了编译系统,这里默认是 “Eclipse CDT4 - Unix Makefiles”,支持的是 Eclipse 指定了,因此本文示例就基于 Eclipse 进行调试。
由于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/
- 下载安装 J-Link software and documentation pack,安装好第一次运行,会自动检查 J-Link firmware 并升级到最新版本。
https://www.segger.com/products/debug-probes/j-link/
- 运行 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
- 在 Eclipse 中导入需要 debug 的项目
选择 File -> Import -> General -> Existing Projects into Workspace。
在 “Select root directory”,输入项目“armgcc/debug”文件夹目录地址,此时会自动识别出已经编译好的 debug 项目,完成项目导入,比如本次示例项目名字为 gpio-freertos,导入如下:
- 在 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)
- 至此,GDB 配置完毕,点击 Debug 按钮即可进行 debug 了。
Colibri iMX7 M4 核心示例程序
本程序主要实现三个并行任务:
- LED1, LED2 和 LED3 的跑马灯任务,时间间隔从最小 100ms 到最大 1000ms,每档间隔为 100ms。
- 按键中断任务,每按键一次,跑马灯的时间间隔增加 100ms,如果已经到达 1000ms 上限,再次按键则回到 100ms 初始值。同时在每次跑马灯时间间隔更改后,给 A7 核心系统发消息通知。
- 和 A7 核心通讯任务,当接收到 A7 发来的跑马灯时间间隔指令后,按指令配置跑马灯时间间隔,同时配置完成后给 A7 核心发消息通知。
具体代码请见如下 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
Colibri iMX7 A7 核心示例程序
在展示 A7 程序代码之前需要先进行一些关于 A7 Linux 系统的说明:
由于 iMX7 A7 和 M4 是共享外设,因此在开发前需要先区分好 M4 所需要的外设,同时在 A7 Linux 的 device tree 中将这些外设 disable,以免产生冲突,比如本示例,主要就使用了几个GPIO 资源,以及 M4 调试串口,因此需要在 A7 device tree 中确保未使用对应的 GPIO 和串口资源,具体关于 device tree 的修改编译这里就不详述了,具体可以参考这里。当然,如果只是临时测试,也可以直接在 uboo t中配置,详细可以参考如下:
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 自启动项目来实现。
A7 Rpmsg 通讯的 Qt 应用代码如下:
https://github.com/simonqin09/iMX7_M4_Runniung_LED_Demo/tree/master/qt-rpmsg
程序分为两个线程,主线程 mainwindow 实现主要图形界面显示,同时实现发送消息功能;另外一个子线程主要负责实时获取 M4 发来的消息并显示在主界面的对应位置。
由于 Rpmsg Linux 驱动加载后,会虚拟出一个串口设备,因此基本的发送接收就是 Linux 下串口的基本操作,具体说明可以参考这里。
完整程序的部署测试
首先在 uboot 下通过 SD 卡或者 tftp 将编译好的 M4 核心 firmware 下载保存到 imx7 flash 里面并开机自动加载,通过 SD 卡相关命令可以参考这里。
# ubi part ubi # tftp ${loadaddr} gpio_freertos.elf # ubi write ${loadaddr} m4firmware ${filesize} # setenv m4boot 'ubi read ${loadaddr} m4firmware && bootaux ${loadaddr}' # saveenv
然后进入 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 的开机自动加载请参考这里说明,这里就不赘述。
重新启动,可以看到在开机马上 uboo t启动瞬间 LED 跑马灯已经开始运转,证明 M4 firmware 已经运行起来,然后 Linux 启动后 Qt 应用起来,可以对跑马灯时间间隔进行增加和减少操作,同时按键更改跑马灯时间间隔的结果也会即时反馈到应用界面上来。
总结
通过上述示例可见,通过 iMX7 这样异构多核架构的处理器,可以更简洁高效的实现原来需要两个分立处理器来完成的任务,简化的硬件设计,软件开发也相对更统一,数据面分享可以直接通过内存共享非常方便,相信未来会有越来越多的嵌入式应用采用这样的方案。