The NXP/Freescale VF6xx SoC which is the core of the Colibri VF61 module implements a heterogeneous asymmetric architecture. Besides the main CPU core based on the ARM Cortex-A5 processor, a secondary general purpose ARM Cortex-M4 core is available too. The secondary core typically runs a RTOS optimized for microcontrollers or a bare-metal application. Toradex provides FreeRTOS™, a free professional grade real-time operating system for microcontrollers, along with drivers and several examples which can be used on our Colibri VF61 platform. The FreeRTOS™ port is based on NXP FreeRTOS BSP for i.MX 7.
The source code is available at:
The Cortex-M4 CPU core lives side by side with the Cortex-A5 based primary CPU core. Both CPU complexes have access to the same interconnect and hence have equally access to all peripherals (shared bus topology).
There are several types of memory available. The Cortex-M4 provides local memory (Tightly Coupled Memory, TCM), which is relatively small but can be accessed by the CPU without any latency. There are multiple OCRAM areas (On-Chip RAM, typically SRAM) which are relatively fast as well and slightly larger. The third option is the DDR3 based main memory. From a performance perspective one of the internal areas should be selected whenever possible.
A traditional microcontroller typically has internal NOR flash where the firmware is stored and executed from. This is not the case on Colibri VF61: There is no NOR flash where the firmware can be flashed onto. Instead, the firmware needs to be stored on the mass storage device such as SD-card or the internal NAND flash. The available mass storage devices are not "memory mapped", and hence application can not be executed directly from any of the cores (no eXecuted-In-Place, XIP). Instead, code need to be loaded into one of the available memory sections before the CPU can start executing it.
The Colibri VF61 always boots using the Cortex-A5 core. The core executes the internal boot ROM which typically loads a boot loader such as U-Boot. The boot loader allows loading the firmware from the mass storage device (e.g. NAND flash) into memory, and triggers the Cortex-M4 to start executing the firmware. To upgrade or replace a firmware, one can just replace the firmware binary on the mass storage device.
The two CPU platforms use a different memory layout to access individual sub systems. This table lists some important areas and their memory location for each of the cores side by side. The full list can be found in the Vybrid reference manual.
Region | Size | Cortex-A5 | Cortex-M4 (System Bus) | Cortex-M4 (Code Bus) |
---|---|---|---|---|
Boot ROM | 96KB | 0x00000000-0x00018000 |
0x00000000-0x00018000 |
|
DDR Address | 2048MB (less for M4) | 0x80000000-0xffffffff |
0x80000000-0xdfffffff |
0x00800000-0x0fffffff (maps to 0x80800000-0x8fffffff ) |
OCRAM | 512KB | 0x3f000000-0x3f07ffff |
0x3f000000-0x3f07ffff |
0x1f000000-0x1f07ffff (part of 8MB area 0x1f000000-0x1f7fffff ) |
TCML | 32KB | 0x1f800000-0x1f808000 |
0x1f800000-0x1f808000 |
|
TCMU | 32KB | 0x3f800000-0x3f808000 |
0x3f800000-0x3f808000 |
The FreeRTOS source code is available on our git server. Use git to clone the repository:
# git clone -b colibri-vf61-m4-freertos-v8 https://github.com/toradex/FreeRTOS-Colibri-VF61.git
This table shows how the FreeRTOS BSP source code is structured:
Directory | Content |
---|---|
doc/ | NXP/Freescales FreeRTOS BSP Documentation |
examples/ | Application examples |
examples/vf6xx_colibri_m4/ | Examples ported to Toradex Colibri VF61 |
middleware/multicore/open-amp/ | OpenAMP based RPMsg stack (remote messaging framework) |
platform/ | Driver library, startup code and utilities |
platform/CMSIS/ | Cortex Microcontroller Software Interface Standard (CMSIS) ARM Cortex®-M header files, DSP library source |
platform/devices/VF6XX/linker/ | Linker control files for each supported toolchain |
platform/drivers/ | Peripheral Drivers |
platform/utilities/ | Utilities such as debug console |
rtos/FreeRTOS/ | FreeRTOS Kernel folder |
Using GNU Makefiles and CMake along with the GCC compiler has been tested on Linux based host systems.
We recommend using one of the Linaro provided ARM Embedded toolchains, e.g. 4.9 2015 Q3 update. Unpack the toolchain to an appropriate location, e.g. your home directory:
$ tar xjf ~/Downloads/gcc-arm-none-eabi-4_9-2015q3-20150921-linux.tar.bz2
...
Since the toolchain is compiled as 32-bit binaries, make sure to install 32-bit version of libc and libncurses. On Ubuntu 14.04 the commands to install those libraries are:
sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get install libc6:i386 libncurses5:i386
With that, gcc should run fine
$ ~/gcc-arm-none-eabi-4_9-2015q3/bin/arm-none-eabi-gcc --version
arm-none-eabi-gcc (GNU Tools for ARM Embedded Processors) 4.9.3 20150529 (release) [ARM/embedded-4_9-branch revision 227977]
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Furthermore, the GNU make and cmake need to be available. For example, on Ubuntu:
$ sudo apt-get install make cmake
Each example has a sub-directory called armgcc. Enter this subdirectory and use the provided shell scripts to build the example. The scripts expect the environment variable to point to the Linaro ARM Embedded toolchain:
$ export ARMGCC_DIR=~/gcc-arm-none-eabi-4_9-2015q3/
$ cd examples/vf6xx_colibri_m4/demo_apps/hello_world/armgcc
$ ./build_all.sh
-- TOOLCHAIN_DIR: /home/dvb/gcc-arm-none-eabi-4_9-2015q3/
-- BUILD_TYPE: Debug
-- TOOLCHAIN_DIR: /home/dvb/gcc-arm-none-eabi-4_9-2015q3/
-- BUILD_TYPE: Debug
-- The ASM compiler identification is GNU
-- Found assembler: /home/dvb/gcc-arm-none-eabi-4_9-2015q3//bin/arm-none-eabi-gcc
-- Configuring done
-- Generating done
-- Build files have been written to: /home/dvb/freertos-toradex/examples/vf6xx_colibri_m4/demo_apps/hello_world/armgcc
Scanning dependencies of target hello_world
[ 4%] Building C object CMakeFiles/hello_world.dir/home/dvb/freertos-toradex/rtos/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c.obj
...
[100%] Linking C executable debug/hello_world.elf
[100%] Built target hello_world
With that, the sub directories release/ and debug/ contain the firmware binaries which can be executed on the target (see the instructions of the individual examples below).
There are two possible ways to boot the Cortex-M4 core on Vybrid:
m4boot
/bootaux
Note: In release image 2.7 Beta1, support for m4boot has been dropped from u-boot and remoteproc is the only method to boot and run firmware on Cortex-M4. In release image 2.7 Beta2, support for bootaux has been added including elf boot support.
Note: The FreeRTOS firmware uses Colibri UART_B as its debugging console. Make sure to connect UART_B to your debugging host and start a serial terminal emulator with a baud rate of 115200 on the serial port.
Linux disables unused clocks by default but it is not aware what clocks are used by the Cortex-M4 core. Use the 'clk_ignore_unused' kernel parameter to avoid clocks getting accidentally disabled. The power management suspend code and the Cortex-M4 firmware typically use the same SRAM location leading to a resource conflict. To prevent the suspend code from overwriting the M4 firmware and/or remoteproc from not being able to load, the SRAM driver should be disabled by passing 'initcall_blacklist=sram_init' kernel parameter:
Colibri VFxx # setenv defargs 'clk_ignore_unused initcall_blacklist=sram_init'
By default, our Linux device tree uses UART_B too, which leads to a external abort when the Linux kernel tries to access UART_B. It is recommended to alter the device tree and disable UART_B using the status property (see Device Tree Customization
(901439e4-9c90-11e4-8c91-9e9dd95319f8)). Temporary, the following fdt_fixup command can be use in U-Boot:
Colibri VFxx # setenv fdt_fixup 'fdt addr ${fdt_addr_r} && fdt rm /soc/aips-bus@40000000/serial@40029000'
Colibri VFxx # saveenv
With images 2.7b2 and newer you can boot the Cortex-M4 using bootaux
. This command has been adopted from Colibri iMX7, and allows to boot bin
and elf
files directly.
Colibri VFxx # fatload mmc 0:1 ${loadaddr} hello_world.elf
...
Colibri VFxx # bootaux ${loadaddr}
## Starting auxiliary core at 0x1F0002E1 ...
Colibri VFxx #
Use the following commands to create a UBI volume to store the Cortex-M4 firmware (to free up space for this volume this process will remove the rootfs volume!). The update scripts are required for this steps, make sure you have a SD-card with the image prepared and in your SD-card slot.
Colibri VFxx # run setupdate
...
Colibri VFxx # setenv create_m4firmware 'ubi part ubi && ubi remove rootfs && ubi create m4firmware 0xe0000 static && run prepare_ubi'
...
Colibri VFxx # run create_m4firmware
...
Colibri VFxx # fatload mmc 0:1 ${loadaddr} hello_world.elf
...
Colibri VFxx # ubi write ${loadaddr} m4firmware ${filesize}
...
Colibri VFxx # run update_rootfs
...
Once the UBI volume is in place, a new firmware can be written by just using ubi write
:
Colibri VFxx # ubi part ubi
...
Colibri VFxx # fatload mmc 0:1 ${loadaddr} hello_world.elf
...
Colibri VFxx # ubi write ${loadaddr} m4firmware ${filesize}
...
You need to extend the default ubiboot command to load and execute the firmware before starting Linux:
Colibri VFxx # setenv ubiboot 'run setup; setenv bootargs ${defargs} ${ubiargs} ${setupargs} ${vidargs}; echo Booting from NAND...; ubi part ubi && ubi read ${loadaddr} m4firmware && bootaux ${loadaddr} && ubi read ${kernel_addr_r} kernel && ubi read ${fdt_addr_r} dtb && run fdt_fixup && bootz ${kernel_addr_r} - ${fdt_addr_r}'
Colibri VFxx # saveenv
In images using U-Boot 2015.04 (BSPs before 2.7), one need to use FIT image to boot Cortex-M4 from U-Boot via m4boot
.
Creating FIT image:
readelf
.e.g.:
$ readelf -h release/hello_world.elf | grep Entry
Entry point address: 0x1f000279
Example image source file (vybridm4.its) for hello_world example:
/* * U-Boot FIT image with FreeRTOS blob for Vybrid's Cortex-M4 */ /dts-v1/; / { description = "FreeRTOS for Vybrid's Cortex-M4"; #address-cells = <1>; images { kernel@1 { description = "FreeRTOS for Vybrid"; data = /incbin/("./hello_world.bin"); type = "kernel"; arch = "arm"; os = "baremetal"; compression = "none"; load = <0x3f000000>; entry = <0x1f000279>; hash@1 { algo = "md5"; }; }; }; configurations { default = "config@1"; config@1 { description = "FreeRTOS for Vybrid's Cortex-M4"; kernel = "kernel@1"; }; }; };
Create the image file using the mkimage
command:
$ mkimage -f vybridm4.its vybridm4-freertos.itb
The resulting image file vybridm4-freertos.itb can be now transferred to the target.
m4boot
command:Colibri VFxx # fatload mmc 0:1 ${loadaddr} vybridm4-freertos.itb
...
OR
Colibri VFxx # tftp ${loadaddr} vybridm4-freertos.itb
...
Colibri VFxx # m4boot ${loadaddr}
## Loading kernel from FIT Image at 80008000 ...
Using 'config@1' configuration
Trying 'kernel@1' kernel subimage
Description: FreeRTOS for Vybrid
Type: Kernel Image
Compression: uncompressed
Data Start: 0x800080d4
Data Size: 18628 Bytes = 18.2 KiB
Architecture: ARM
OS: Bare-metal
Load Address: 0x3f000000
Entry Point: 0x1f000279
Hash algo: md5
Hash value: 577a4448ce6171faf7b35e85bd154c10
Loading kernel from 0x800080d4 to 0x3f000000
## Loading ramdisk from FIT Image at 80008000 ...
Using 'config@1' configuration
Could not find subimage node
## Loading fdt from FIT Image at 80008000 ...
Using 'config@1' configuration
Could not find subimage node
Booting Cortex-M4 @0x1f000279
Colibri VFxx #
Use the following commands to create a UBI volume to store the Cortex-M4 firmware (to free up space for this volume this process will remove the rootfs volume!):
Colibri VFxx # run setupdate
...
Colibri VFxx # setenv create_m4firmware 'ubi part ubi && ubi remove rootfs && ubi create m4firmware 0xe0000 static && run prepare_ubi'
...
Colibri VFxx # run create_m4firmware
...
Colibri VFxx # fatload mmc 0:1 ${loadaddr} vybridm4-freertos.itb
...
OR
Colibri VFxx # tftp ${loadaddr} vybridm4-freertos.itb
...
Colibri VFxx # ubi write ${loadaddr} m4firmware ${filesize}
...
Colibri VFxx # run update_rootfs
Once the volume is in place, a new firmware can be written by just using ubi write
:
Colibri VFxx # ubi part ubi
...
Colibri VFxx # ubi write ${loadaddr} m4firmware ${filesize}
...
Use the following command to enable automatic loading and execution of the firmware
Colibri VFxx # setenv m4Boot 'ubi read ${loadaddr} m4firmware && m4boot ${loadaddr}'
Colibri VFxx # saveenv
In our release image (since v2.6.1), by default remoteproc is disabled to allow Cortex-M4 to start from U-Boot. To start Cortex-M4 using remoteproc, deploy the .elf to '/lib/firmware' directory and load the remoteproc kernel modules. To auto load the remoteproc driver during boot, manually add vf610_cm4_rproc.conf file in '/etc/modules-load.d/'
with the remoteproc driver vf610_cm4_rproc
specified in the conf file.
root@colibri-vf:~# cat /etc/modules-load.d/vf610_cm4_rproc.conf
vf610_cm4_rproc
If you build the image using OpenEmbedded, you can have the configuration to be deployed with the image by adding KERNEL_MODULE_AUTOLOAD
in conf/local.conf
:
KERNEL_MODULE_AUTOLOAD += "vf610_cm4_rproc"
Note: remoteproc by default looks for freertos-rpmsg.elf
binary in /lib/firmware. To load a custom .elf one can create a symlink so that freertos-rpmsg.elf
points to the actual .elf.
root@colibri-vf:~# cd /lib/firmware/
root@colibri-vf:~# ln -s hello_world.elf freertos-rpmsg.elf
root@colibri-vf:~# dmesg|grep remoteproc
[ 4.897291] remoteproc0: vf610_m4 is available
[ 4.909798] remoteproc0: Note: remoteproc is still under development and considered experimental.
[ 4.934253] remoteproc0: THE BINARY FORMAT IS NOT YET FINALIZED, and backward compatibility isn't yet guaranteed.
[ 4.983452] remoteproc0: powering up vf610_m4
[ 5.069934] remoteproc0: Booting fw image freertos-rpmsg.elf, size 160544
[ 5.084654] remoteproc0: No resource table found, continuing...
[ 5.098450] remoteproc0: remote processor vf610_m4 is now up
This section provides information about the available examples and how to use them. The source code of the Colibri VF61 examples are located under examples/vf6xx_colibri_m4/. All examples are linked to run in the SRAM area.
Precompiled firmwares can be found at: http://developer.toradex.com/files/toradex-dev/uploads/media/Colibri/FreeRTOS/Binaries/
Simple application starting the FreeRTOS kernel and printing Hello World in a FreeRTOS task.
Hello World!
GPIO example using input and output. Example uses SO-DIMM_PIN: for button/key and SO-DIMM_PIN: for a LED. On a Colibri Evaluation board, you can use header X9 to connect the SO-DIMM signals to a button or LED respectively:
This demo uses a virtual TTY on Linux side to send a RPmsg to FreeRTOS. Each string sent to the FreeRTOS example will be sent back to the Linux host.
Start the example rpmsg_str_echo_example.bin on the Cortex-M4 first, which should already print the following output:
Starting RPMSG String Echo Demo... RPMSG String Echo Demo... RPMSG Init as Remote init M4 as REMOTE
Then, boot into Linux and execute the following commands:
# modprobe imx_rpmsg_tty [ 63.814232] imx_rpmsg_tty rpmsg0: new channel: 0x400 -> 0x1! [ 63.831681] Install rpmsg tty driver!
With that, we have a TTY device located at /dev/ttyRPMSG. The probe method also sends a "hello world" to the other side, which should be visible in the Cortex-M4 console:
... Name service handshake is done, M4 has setup a rpmsg channel [1 ---> 1024] Get Message From A5 : "hello world!" [len : 12] from slot 0
We can use bash to open the file and assign it the file descriptor 3, write into it, read from it and ultimately close it.
# stty -F /dev/ttyRPMSG -echo # exec 3<> /dev/ttyRPMSG # echo Test >&3 # cat <&3 Test ^C # exec 3>&-
On the Cortex-M4 side, this should print the Test message:
... Get Message From A5 : "Test" [len : 4] from slot 1 Get New Line From A5 From Slot 2
To load the module automatically on every boot, a config file in the modules-load.d directory can be used:
# echo imx_rpmsg_tty >> /etc/modules-load.d/vf610_rpmsg.conf
This example uses the messaging mechanism to send an integer value back and forth, while incrementing it on both sites. The demo will stop after 1000 iterations (that is when 2000 incrementations have been executed).
modprobe imx_rpmsg_pingpong [ 60.853586] imx_rpmsg_pingpong rpmsg0: new channel: 0x400 -> 0x1! [ 60.875905] get 1 (src: 0x1) [ 60.886584] get 3 (src: 0x1) [ 60.893515] get 5 (src: 0x1) [ 60.899517] get 7 (src: 0x1) [ 60.905504] get 9 (src: 0x1) [ 60.912600] get 11 (src: 0x1) [ 60.918611] get 13 (src: 0x1) [ 60.924596] get 15 (src: 0x1) ... [ 67.384454] get 1999 (src: 0x1) [ 67.387614] imx_rpmsg_pingpong rpmsg0: goodbye!
Starting RPMSG PingPong Demo... RPMSG PingPong Demo... RPMSG Init as Remote init M4 as REMOTE Name service handshake is done, M4 has setup a rpmsg channel [1 ---> 1024] Get Data From A5 : 0 Get Data From A5 : 2 Get Data From A5 : 4 Get Data From A5 : 6 Get Data From A5 : 8 Get Data From A5 : 10 Get Data From A5 : 12 Get Data From A5 : 14 Get Data From A5 : 16 ...
Use debug level 5 to avoid the messages on the serial console
# echo 5 > /proc/sys/kernel/printk
Toradex CE Library V1
.9 or higher
(d92045c9-c212-11e2-b9c5-9e9dd95319f8) and build Rpmsg_Demo application.git clone -b colibri-vf61-m4-freertos-v8 git://git.toradex.com/freertos-toradex.git
Download and Install MinGW.
Select mingw32-base and msys-base package and update it.
Install cmake
Download the zip package of GNU ARM Embedded Toolchain and extract its content inside C:\MinGW\bin. You should see the folders arm-none-eabi, bin, lib and share below C:\MinGW\bin".
Set the user environment variables(My Computer > Properties > Advanced System settings > Environment variables). ARMGCC_DIR=C:\MinGW\bin and PATH=C:\MinGW\bin"
Run build_all.bat to build FreeRTOS source code, which you can find in FreeRTOS source code directories.
In case you have any query or feedback, please contact our support
(da00418f-27ab-11e1-8146-0021cc5d255c).