1). 简介
FreeRTOS是广泛使用的开源实时操作系统, 被众多芯片厂商包括NXP所支持, 本文就展示在NXP iMX7 ARM处理器上面的M4核心上面部署FreeRTOS.
NXP iMX7 ARM处理器是NXP最新推出的异构双核处理器, 主核心为单核或者双核Cortex-A7,通常运行Linux/WinCE操作系统来作为嵌入式应用主程序界面环境; 副核心为Cortex-M4, 通常运行实时操作系统来为嵌入式应用提供高效可靠的实时应用处理. 一个简略的iMX7芯片框图如下所示.
由上图可见, 多种类型的内存可供使用, 包括M4专属的内存空间 (Tightly Coupled Memory, TCM), 虽然很小但是CPU可以无延迟访问; 多个OCRAM区域 (On-Chip RAM, 通常是SRAM), 同样访问非常快而且提供相对大的容量; 最后就是DRR3主内存空间. 出于性能考虑, 请尽可能优先使用片内内存资源.
另外, M4有两个总线连接到AXI/AHB interconnect, 一个负责数据传输,另一个负责指令传输, 因此为了最好的性能优化, 我们需要将数据放置与连接数据总线的区域,而指令代码放置与连接指令总线的区域. 例如, 对于TCM,则放置代码于TCML空间, 而放置数据于TCMU空间.
然后关于Resource Domain Controller (RDC), 对于iMX7,由于Cortex-A7和Cortex-M4核心内存和外设的访问都是共享且平等的,为了保证不产生资源冲突,通过这个控制器来从硬件层面对指定内存和外设的访问权限进行保护. RDC 允许定义最多4个resource domains, 并将不同的内存和外设资源指定到这些resource domain中. 默认情况下, A7核心和相关外设被指定于domain 0, 当FreeRTOS firmware运行后, M4核心以及相关外设最初也是domain
0, 但马上被重新指定到domain 1. 因此如果一个外设需要被M4使用, 但同时A7 Linux kernel也使用了, 就需要修改A7 Linux Device Tree来禁止这个外设 (详细操作方法请见
这里).
本文就基于Toradex
Colibri iMX7 (基于NXP iMX7 SoC) ARM计算机模块搭配
Colibri
Eva Board开发板来演示编译和部署FreeRTOS应用. 区别与传统的MCU处理器, firmware通常从内置的NOR Flash加载, Colibri iMX7则并没有这样的配置, 而是将firmware存放于外部存储设备中如SD卡或者模块上的Nand Flash, 同时这些存储并不是“memory mapped”, 因此CPU无法直接执行存储在这里的firmware, 而是要先被加载到内存区域后才能被执行.
对于Colibri iMX7, 系统总是由Cortex-A7核心来启动, 先执行内部boot ROM后启动如U-boot这样的boot loader,然后由boot loader从上述的存储设备加载firmware到内存,最后在触发Cortex-M4核心去执行这个firmware. 而如果需要更新或者替换firmware,只需要更改存储设备上面的firmware镜像即可.
2). 准备
a). 硬件准备
./ Colibri iMX7计算机模块和Colibri Eva Board开发板
./ Ubuntu Linux开发主机
b). 软件准备
./ iMX7模块Cortex-A7核心运行Toradex
Embedded Linux release V2.6 Beta2
./ Ubuntu Linux开发主机
FreeRTOS
source code
交叉编译ToolChain - Linaro ARM Embedded, 4.9 2015-Q3 update - 从
这里下载
3). 配置
a). 下载FreeRTOS for Colibri iMX7
------------------------
$ git clone -b master-1.0.1 git://git.toradex.com/freertos-toradex.git freertos-colibri-imx7/
$ cd freertos-colibri-imx7/
------------------------
b). 解压缩交叉编译工具
------------------------
$ tar xjf gcc-arm-none-eabi-4_9-2015q3-20150921-linux.tar.bz2
//如果开发主机是Ubuntu 64bit 操作系统,则需要安装下面32bit支持包
$ sudo dpkg --add-architecture i386
$ sudo apt-get update
$ sudo apt-get install libc6:i386 libncurses5:i386
//测试gcc运行
$ cd .../gcc-arm-none-eabi-4_9-2015q3/bin/
$./arm-none-eabi-gcc --version
//安装 make 和 Cmake 工具
$ sudo apt-get install make cmake
------------------------
4). 编译FreeRTOS
FreeRTOS 的 examples 目录下提供了诸多例程,在编译前需要先设置叉编译工具路径的环境变量ARMGCC_DIR,然后运行armgcc子目录下准备好的编译脚本即可进行编译.
------------------------
$ export ARMGCC_DIR=.../gcc-arm-none-eabi-4_9-2015q3/
$ cd .../freertos-colibri-imx7/examples/imx7_colibri_m4/demo_apps/hello_world/armgcc
$ ./build_all.sh
------------------------
编译好的可执行文件位于armgcc下的release和debug子目录下, 可以加载到M4核心上面运行了.
5). 在M4核心上面运行Firmware
a). M4的固件程序在Colibri iMX7 A7核心Linux系统U-Boot中进行加载, 将编译好的 hello_world.bin程序放到SD卡根目录 (FAT32格式) ,并连接到开发板上.
------------------------
Colibri iMX7 # fatload mmc 0:1 0x7F8000 hello_world.bin
...
Colibri iMX7 # dcache flush
Colibri iMX7 # bootaux 0x7F8000
## Starting auxiliary core at 0x007F8000 ...
------------------------
b). FreeRTOS 默认使用 UARTB 作为其调试输出串口, 波特率设置115200 8N1。A7 Linux 默认device tree设置也会访问UARTB, 为了防止出现冲突, 推荐在device tree 中禁用 UARTB(设置status参数)。也可以在 U-Boot 中添加下面参数,临时禁用 UARTB。
------------------------
Colibri iMX7 # setenv fdt_fixup 'fdt addr ${fdt_addr_r} && fdt rm /soc/aips-bus@30800000/spba-bus@30800000/serial@30890000'
Colibri iMX7 # saveenv
------------------------
c). Linux会自动关闭不使用设备的时钟,但A7核心Linux无法知道哪些时钟在M4核心上面被使用,因此需要添加下面内核参数来保证M4相关时钟正常。
------------------------
Colibri iMX7 # setenv defargs clk_ignore_unused
------------------------
d). 通过另外一个窗口连接UARTB, 可以收到hello world程序运行后的打印输出
------------------------
$ sudo minicom -D /dev/ttyUSB1 -b 115200
Welcome to minicom 2.7
......
Port /dev/ttyUSB1, 11:52:46
Press CTRL-A Z for help on special keys
Hello World!
------------------------
e). 自动启动加载 M4 上运行的程序
// 运行下面命令将SD卡上面的程序文件复制到系统为M4程序单独提供的ubi分区空间
------------------------
Colibri iMX7 # ubi part ubi
...
Colibri iMX7 # fatload mmc 0:1 ${loadaddr} hello_world.bin
...
Colibri iMX7 # ubi write ${loadaddr} m4firmware ${filesize}
------------------------
// 设置启动变量,之后U-Boot会在开机启动Linux前先启动M4程序
------------------------
Colibri iMX7 # setenv m4boot 'ubi read 0x7F8000 m4firmware && dcache flush && bootaux 0x7F8000'
Colibri iMX7 # saveenv
------------------------
6). M4 程序示例
除了上面测试的hello world, 在examples目录中还有很多示例程序.
a). GPIO示例
// 例程位置: .../examples/imx7_colibri_m4/driver_examples/gpio_imx/
// 同上述方法编译后生成应用: gpio_imx_example.bin
// 例程中使用EXT_IO1作为按键输入, EXT_IO0作为输出控制LED; 在Colibri 评估板上面, 利用X21将对应Pin脚和组件相连:
------------------------
EXT_IO0 => X21-LED1
EXT_IO1 => X21-SW6
------------------------
// 在Uboot运行程序, 由于A7 Linux Device Tree也定义了这几个GPIO, 因此测试只在U-Boot环境下进行.
------------------------
====================== GPIO Example ========================
=================== GPIO Interrupt =====================
The (EXT_IO1) button is configured to trigger GPIO interrupt
Press the (EXT_IO1) button 3 times to continue.
Button pressed 1 time.
Button pressed 2 time.
Button pressed 3 time.
================= GPIO Functionality==================
The button state is now polled.
Press the button to switch LED on or off
Button pressed 1 times
Button pressed 2 times
...
------------------------
b). RPMsg示例 - M4和A7通讯
// 例程位置: .../examples/imx7_colibri_m4/demo_apps/rpmsg/str_echo_freertos/
// 同上述方法编译后生成应用: rpmsg_str_echo_freertos_example.bin
// A7 Linux kernel对应module 源文件: drivers/rpmsg/imx_rpmsg_tty.c
// U-Boot执行如下命令
------------------------
fatload mmc 0:1 0x7F8000 rpmsg_str_echo_freertos_example.bin
reading rpmsg_str_echo_freertos_example.bin
20860 bytes read in 21 ms (969.7 KiB/s)
Colibri iMX7 # dcache flush
Colibri iMX7 # bootaux 0x7F8000
## Starting auxiliary core at 0x007F8000 ...
Colibri iMX7 # run ubiboot
------------------------
// M4 串口输出
------------------------
RPMSG String Echo FreeRTOS RTOS API Demo...
RPMSG Init as Remote
------------------------
// A7 Linux下执行下面命令
------------------------
$ modprobe imx_rpmsg_tty
[ 184.656763] imx_rpmsg_tty rpmsg0: new channel: 0x400 -> 0x0!
[ 184.663331] Install rpmsg tty driver!
$ stty -F /dev/ttyRPMSG -echo
$ exec 3<> /dev/ttyRPMSG
$ echo Test >&3
$ cat <&3
Test
^C
$ exec 3>&-
------------------------
// M4串口对应输出
------------------------
RPMSG String Echo FreeRTOS RTOS API Demo...
RPMSG Init as Remote
Name service handshake is done, M4 has setup a rpmsg channel [0 ---> 1024]
Get Message From Master Side : "Test" [len : 4]
Get New Line From Master Side
------------------------
// 如需将Linux kernel module 设置为开机自动加载
------------------------
$ echo imx_rpmsg_tty > /etc/modules-load.d/rpmsg_tty.conf
------------------------
// 另外关于RPMsg还有其他如pingpong demo, 可以自行测试.
7). 总结
本文对iMX7 异构双核架构进行了说明, 并基于Toradex Colibri iMX7 模块演示了在M4核心上面运行FreeRTOS例程以及A7和M4核心通过RPMsg通信例程, 相信对NXP iMX7架构以及应用有了一个初步的了解, 其非常适合用于同时有人机交互和实时控制的工业应用场景, 同时非常低的功耗也使得整个嵌入式系统的稳定可靠性有了很好的保证.
参考文档
http://developer.toradex.com/knowledge-base/freertos-on-the-cortex-m4-of-a-colibri-imx7