ブログ:
NXP i.MX8 M4コアのFreeRTOS RPMsgアプリケーションの例

2021年11月30日火曜日

はじめに

NXP i.MX8は、Cortex-A72/A53およびCortex-M4によるヘテロジニアスマルチコアのアーキテクチャーが採用されたArmプロセッサーで、NXPが昨年終わりに発売を開始しました。iMX6 SoloXとiMX7からアップグレードされた、NXP i.MXシリーズの最新、最強のArmプロセッサーです。ヘテロジニアスのデュアルコアアーキテクチャー(下記のブロック図参照)により、異なるアーキテクチャーのコアの利用の利便化と安定化が実現しています。この記事では、RPMsgを利用した、iMX8 Cortex-AおよびCortex-Mのコア間の通信の例をデモとして紹介します。

この記事で利用するArmプラットフォームは、NXP i.MX8QM Armプロセッサーを搭載した、ToradexのApalis iMX8QM Arm組み込みプラットフォームです。

準備

Apalis iMX8QMのArmコアバージョンはApalis評価ボードキャリアボードに対応し、デバッグシリアルポートUART1(キャリアボード X29)を開発ホストに接続してデバッグを可能にします。これからiMX8QMのM4コアの一番目はM40と呼ばれて、iMX8QMのM4コアの二番目はM41と呼ばれます。

iMX8 M40およびM41は、それぞれ独自のデバッグUARTを利用します。Apalis評価ボード上のジャンパーを設定して、M4に対応するデバッグUARTを開発ホストに接続する方法については、を参照してください。

Apalis iMX8 Cortex-Aコアには、Toradex Yocto Linux ConsoleイメージV3.04バージョンがインストールされています。詳細については、こちらを参照してください。

M4のデバッグUARTに利用されるピンが、Cortex-AコアLinuxシステムのデバイスツリーにあるピン構成と衝突してしまうため、デバイスツリーを変更してリコンパイルし、再度導入する必要があります。

デバイスツリーの修正パッチファイルについては、以下を参照してください。Linuxカーネルのソースコードのダウンロードとコンパイルおよび導入方法については、ここを参照してください。
https://github.com/simonqin09/Apalis_iMX8_M4_RPMsg/blob/master/apalis_imx8_m4s_uart.patch

M 4のFreeRTOS SDKの導入

ここの指示に従って、NXP MCUXpressoウェブサイトからiMX8QMに対応するSDKをダウンロードします。現在の最新バージョンは2.5.2です。ダウンロードのインターフェースは下の図のとおりです。このページでSDKについてのドキュメンテーションもダウンロードできます。ダウンロードされるSDKファイルは、「SDK_2.5.2_MIMX8QM6xxxFF.tar.gz」です。

Toolchainのダウンロード

SDKのドキュメンテーションによれば、gcc-Arm 7 2018q2バージョンの利用が推奨されています。ダウンロードのアドレスは次のとおりです。

https://developer.Arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads/7-2018-q2-update

ダウンロードしたToolchainファイルをに解凍します。

  • 解凍

$ cd <Toolchain_dir>
$ tar xvf gcc-arm-none-eabi-7-2018-q2-update-linux.tar.bz2

  • テスト

$ gcc-arm-none-eabi-7-2018-q2-update/bin/arm-none-eabi-gcc --version
arm-none-eabi-gcc (GNU Tools for Arm Embedded Processors 7-2018-q2-update) 7.3.1 20180622 (release) [ARM/embedded-7-branch revision 261907]
Copyright (C) 2017 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.

  • その後のコンパイルのために追加でツールをインストールする必要があるかもしれません。例えば、Ubuntuの場合を見てみます。

$ sudo apt-get install make cmake

Helloworldテストアプリケーションをコンパイルします。

ステップaでダウンロードしたSDKファイルをに解凍します。

$ cd <Work_dir>
$ tar xvf SDK_2.5.2_MIMX8QM6xxxFF.tar.gz

Toolchainのパスをエクスポートします。

$ export ARMGCC_DIR=<Toolchain_dir>/gcc-arm-none-eabi-7-2018-q2-update/

M40のHelloworldアプリケーションをコンパイルします。

SDKに含まれるのと同じサンプルコードはすべて/boards/mekmimx8qm/ディレクトリにあります。

  • M40 Helloworldデモのコンパイル

$ cd <Work_dir>/boards/mekmimx8qm/demo_apps/hello_world/cm4_core0
$ armgcc/build_all.sh

コンパイルされたバイナリファイルは、Armgccディレクトリの下のdebug/release、ddr_debug/ddr_release、flash_debug/flash_releaseディレクトリにあります。デフォルトでは、TCMからM4のアプリケーションが読み込まれます。ddrおよびflashは、それぞれddrとflash読み込みモードに対応します。これについては、本記事では言及しません。また、Apalis iMX8のメモリー領域の割り当てについては、こちらを参照してください。

M40 Helloworldサンプルアプリケーションの導入とテスト

最新のApalis iMX8 ubootバージョン(U-Boot 2018.03-toradex_imx_v2018.03_4.14.78_1.0.0_ga-bringup+g92d0497781)は、現時点でELF形式のミラーリングに対応していません。このため、生成されたバイナリファイルm4_image.binをSDカードのルートディレクトリのFAT32パーティションにコピーして、SDカードをApalis評価ボードX19 4bit SDカードスロットに接続します。

Apalis iMX8に電源を入れます。Cortex-AコアデバッグシリアルポートUART1シリアルターミナルで、スペースバーを押してubootに入ります。

U-Boot 2018.03-toradex_imx_v2018.03_4.14.98_2.3.0_bringup+gd626574ba1 (Apr 17 2020 - 19:28:04 +0000)

CPU:   Freescale i.MX8QM revB A53 at 1200 MHz at 25C
DRAM:  4 GiB
MMC:   FSL_SDHC: 0, FSL_SDHC: 1, FSL_SDHC: 2
Loading Environment from MMC... OK
In:    serial
Out:   serial
Err:   serial
Model: Toradex Apalis iMX8 QuadMax 4GB Wi-Fi / BT IT V1.0B, Serial# 06548514

BuildInfo: 
- SCFW b929edfe, SECO-FW 27167ff2, IMX-MKIMAGE d7f9440d, ATF bb209a0
- U-Boot 2018.03-toradex_imx_v2018.03_4.14.98_2.3.0_bringup+gd626574ba1 

switch to partitions #0, OK
mmc0(part 0) is current device
flash target is MMC:0
Net:   eth0: ethernet@5b040000
Fastboot: Normal
Normal Boot
Hit any key to stop autoboot:  0 
Apalis iMX8 #

SD カードのイメージを表示します。

Apalis iMX8 # ls mmc 2

Helloworldプログラムを読み込んで実行します。

Apalis iMX8 # fatload mmc 2 ${loadaddr} m4_image.bin && dcache flush && bootaux ${loadaddr} 0
9032 bytes read in 20 ms (440.4 KiB/s)
## Starting auxiliary core at 0x80280000 ...
Power on M4 and MU
Copy M4 image from 0x80280000 to TCML 0x34fe0000
Start M4 0
bootaux complete

実行すると、M40デバッグUARTに対応するシリアルターミナルに「hello world」という出力がプリントされ、その後はアプリケーションがキーボード入力を受け取ってプリントすることができるようになります。例えば、この例では「this is input before linux boot up」という文字列が入力されました。

hello world.
this is input before linux boot up

この時点で、UART1デバッグシリアルポートターミナルに切り替え、次のコマンドを実行するとLinuxの起動を継続できます。

Apalis iMX8 # run bootcmd

次にM40デバッグシリアルターミナルに切り替え、キーボード入力をテストします。

hello world.
this is input before linux boot up this is input after linux boot up

M41でも操作は同様です。ただし、読み込み時のコマンドの最後の0を1に置き換えます。

Apalis iMX8 # fatload mmc 2 ${loadaddr} m4_1_image.bin && dcache flush && bootaux ${loadaddr} 1

M4 FreeRTOS RPMsgサンプルプログラムのテスト

  • RPMsg_lite_str_echo_rtos

<Work_dir>/boards/mekmimx8qm/multicore_examples/rpmsg_lite_str_echo_rtos

  • RPMsg_lite_pingpong_rtos

<Work_dir>/boards/mekmimx8qm/multicore_examples/rpmsg_lite_pingpong_rtos/linux_remote

関連するデモの手順については、対応するプロジェクトのreadme.txtを参照してください。M40とM41のテスト結果は同じになるため、本記事のデモの例としてはM40のみを扱います。

str_echoサンプルプログラムのテスト

チャプター3で行ったのと同じように、str_echoサンプルプログラム、「m4_image.bin」をSDカードから読み込み、実行します。

UART1デバッグシリアルポートターミナル

Apalis iMX8 # fatload mmc 2 ${loadaddr} m4_image.bin && dcache flush && bootaux ${loadaddr} 0
20112 bytes read in 21 ms (934.6 KiB/s)
## Starting auxiliary core at 0x80280000 ...
Power on M4 and MU
Copy M4 image from 0x80280000 to TCML 0x34fe0000
Start M4 0
bootaux complete

M40デバッグシリアルポートターミナルの出力

RPMSG String Echo FreeRTOS RTOS API Demo...

Linuxを起動します

UART1デバッグシリアルポートターミナル

Apalis iMX8 # run bootcmd

M40デバッグシリアルポートターミナルの出力

RPMSG String Echo FreeRTOS RTOS API Demo...

Nameservice sent, ready for incoming messages...

LinuxにRPMsg ttyドライバーを読み込み、RPMsgリンクを確立します。

UART1デバッグシリアルポートターミナル

root@apalis-imx8:~# modprobe imx_rpmsg_tty
[  539.316502] imx_rpmsg_tty virtio1.rpmsg-virtual-tty-channel.-1.30: new channel: 0x400 -> 0x1e!
[  539.325355] Install rpmsg tty driver!

M40デバッグシリアルポートターミナルの出力

RPMSG String Echo FreeRTOS RTOS API Demo...

Nameservice sent, ready for incoming messages...
Get Message From Master Side : "hello world!" [len : 12]

テストデータを送信します。M41の場合、対応する仮想シリアルポートは、/dev/ttyRPMsg31になります。

root@apalis-imx8:~# echo "this is a test from toradex" > /dev/ttyRPMSG30

M40デバッグシリアルポートターミナルの出力

RPMSG String Echo FreeRTOS RTOS API Demo...

Nameservice sent, ready for incoming messages...
Get Message From Master Side : "hello world!" [len : 12]
Get Message From Master Side : "this is a test from toradex" [len : 27]
Get New Line From Master Side

pingpongサンプルプログラムのテストでは、テスト実施のプロセスは基本的にstr_echoのものと同じです。関連するシリアルポートのプリント出力の一覧を以下に示します。

UART1デバッグシリアルポートターミナル

M41でRPMsg pingpongサンプルプログラムを実行します。

Apalis iMX8 # fatload mmc 2 ${loadaddr} m4_image_pingpong.bin && dcache flush && bootaux ${loadaddr} 0
20696 bytes read in 21 ms (961.9 KiB/s)
## Starting auxiliary core at 0x80280000 ...
Power on M4 and MU
Copy M4 image from 0x80280000 to TCML 0x34fe0000
Start M4 0
bootaux complete

Linuxを起動します。

Apalis iMX8 # run bootcmd

Pingpongドライバーを読み込みます。

root@apalis-imx8:~# modprobe imx_rpmsg_pingpong
[   34.508241] imx_rpmsg_pingpong virtio1.rpmsg-openamp-demo-channel.-1.30: new channel: 0x400 -> 0x1e!
root@apalis-imx8:~# [   34.520657] get 1 (src: 0x1e)
[   34.525069] get 3 (src: 0x1e)
[   34.529515] get 5 (src: 0x1e)
……
[   34.738211] get 99 (src: 0x1e)
[   34.742665] get 101 (src: 0x1e)
[   34.745865] imx_rpmsg_pingpong virtio1.rpmsg-openamp-demo-channel.-1.30: goodbye!

デバッグシリアルポートターミナルの出力

pingpongプログラム開始後の出力

RPMSG Ping-Pong FreeRTOS RTOS API Demo...
RPMSG Share Base Addr is 0x90010000

Linux起動後の出力

Link is up!
Nameservice announce sent.

Pingpongドライバー読み込み後の出力

Waiting for ping...
Sending pong...
……
Waiting for ping...
Sending pong...
Ping pong done, deinitializing...
Looping forever...

M4のファームウェアは起動時にテストを自動的に読み込んで実行するよう設定されています。

上記のテストは、UbootコマンドによりSDカードからM4ファームウェアを読み込んで実行されていました。以下では、M40とM41ファームウェアがApalis iMX8 eMMCフラッシュ空間に格納されており、起動後にファームウェアが自動的に読み込まれて実行されることをstr_echoサンプルプログラムを利用してデモンストレートします。

まず、Linuxシステムに入り、SDカードに格納されている、コンパイル済みのM40およびM41のstr_echoプログラムファームウェアをフラッシュのvfatパーティションにコピーします。これは、Linuxカーネルやデバイスツリーなどのファイルが格納されているパーティションです。

UART1デバッグシリアルポートターミナル

root@apalis-imx8:~# cd /media/mmcblk0p1/
root@apalis-imx8:/media/mmcblk0p1# ls
Image    dpfw.bin     fsl-imx8qm-apalis-eval.dtb.bak    fsl-imx8qm-apalis-v1.1-eval.dtb
boot.scr    fsl-imx8qm-apalis-eval.dtb     fsl-imx8qm-apalis-ixora-v1.1.dtb  hdmitxfw.bin

SDカードのマウントパスからM4のstr_echoプログラムファームウェアをコピーします。

root@apalis-imx8:/media/mmcblk0p1# cp /media/mmcblk2p1/m4_image.bin .
root@apalis-imx8:/media/mmcblk0p1# cp /media/mmcblk2p1/m4_1_image.bin .
root@apalis-imx8:/media/mmcblk0p1# ls
Image    fsl-imx8qm-apalis-eval.dtb   fsl-imx8qm-apalis-v1.1-eval.dtb    m4_image.bin    boot.scr    fsl-imx8qm-apalis-eval.dtb.bak    hdmitxfw.bin dpfw.bin    fsl-imx8qm-apalis-ixora-v1.1.dtb  m4_1_image.bin

ubootへと再起動して、環境変数を設定します。

UART1デバッグシリアルポートターミナル

M4のファームウェア名を別個に指定します。

Apalis iMX8 # setenv m4_0_image 'm4_image.bin'
Apalis iMX8 # setenv m4_1_image 'm4_1_image.bin'

起動順序を設定し、M40、M41とLinuxをそれぞれ起動します。

Apalis iMX8 # setenv bootcmd 'run m4boot_0 && run m4boot_1 && run distro_bootcmd'
Apalis iMX8 # saveenv && reset

再起動を設定したら、Linuxの起動プロセス中にM40とM41のデバッグシリアルポートがそれぞれ関連するプログラムの出力をプリントすることが確認できます。

UART1デバッグシリアルポートターミナル

U-Boot 2018.03-toradex_imx_v2018.03_4.14.98_2.3.0_bringup+gd626574ba1 (Apr 17 2020 - 19:28:04 +0000)
……
Normal Boot
Hit any key to stop autoboot:  0 
20112 bytes read in 13 ms (1.5 MiB/s)
## Starting auxiliary core at 0x80280000 ...
Power on M4 and MU
Copy M4 image from 0x80280000 to TCML 0x34fe0000
Start M4 0
bootaux complete
61488 bytes read in 13 ms (4.5 MiB/s)
## Starting auxiliary core at 0x80280000 ...
Power on M4 and MU
Copy M4 image from 0x80280000 to TCML 0x38fe0000
Start M4 1
bootaux complete
……
Scanning mmc 0:1...
Found U-Boot script /boot.scr
……
Starting kernel ...
……

M40デバッグシリアルターミナル

RPMSG String Echo FreeRTOS RTOS API Demo...

Nameservice sent, ready for incoming messages...

M41デバッグシリアルターミナル

RPMSG String Echo FreeRTOS RTOS API Demo...

Nameservice sent, ready for incoming messages...
app_srtm: AUTO and I2C service registered

LinuxにRPMsg ttyドライバーを読み込み、送信テストを実施します。

UART1デバッグシリアルポートターミナル

ドライバーを読み込みます。

root@apalis-imx8:~# modprobe imx_rpmsg_tty
[   34.795096] imx_rpmsg_tty virtio1.rpmsg-virtual-tty-channel.-1.30: new channel: 0x400 -> 0x1e!
[   34.803985] Install rpmsg tty driver!
[   34.807934] imx_rpmsg_tty virtio3.rpmsg-virtual-tty-channel-1.-1.31: new channel: 0x400 -> 0x1f!
[   34.817031] Install rpmsg tty driver!

メッセージを送信します。

root@apalis-imx8:~# echo "this is a message from apalis imx8 linux to m4 0" > /dev/ttyRPMSG30
root@apalis-imx8:~# echo "this is a message from apalis imx8 linux to m4 1" > /dev/ttyRPMSG31

デバッグシリアルターミナル

RPMSG String Echo FreeRTOS RTOS API Demo...

Nameservice sent, ready for incoming messages...
Get Message From Master Side : "hello world!" [len : 12]
Get Message From Master Side : "this is a message from apalis imx8 linux to m4 0" [len : 48]
Get New Line From Master Side

M41デバッグシリアルターミナル

RPMSG String Echo FreeRTOS RTOS API Demo...

Namapp_srtm: AUTO and I2C service registered
eservice sent, ready for incoming messages...
Get Message From Master Side : "hello world!" [len : 12]
Get Message From Master Side : "this is a message from apalis imx8 linux to m4 1" [len : 48]
Get New Line From Master Side

まとめ

本記事では、NXP i.MX8を利用し、マルチコアヘテロジニアスアーキテクチャーにおいてRPMsgドライバーを介してCortex-AコアがCortex-M4コアとLinux通信を行う例を紹介しました。

記者: Shanfeng Hu, FAE, Toradex

コメントを投稿

Please login to leave a comment!
Have a Question?