FPGA受託設計開発お受けします。

トップページ > プロフィール > Arm Cortex-M3 IP on Artix-7

Cortex-M3 on Xilinx Artix-7

2018年末にXilinxのFPGA用にArmがCortex-M3とCortex-M1のIPの提供を開始しました。
このうち、Cortex-M3をDigilent社のBasys3ボードにインプリメントしてみた結果を紹介します。

Digilent社のBasys3にインプリメント

Basys3基板

図1a

Armより提供されているサンプルプロジェクトをそのままArty7ボードにダウンロードして評価しても良かったのですが、新たにArty7ボードを購入する気にはなれなかったのと、お仕着せのサンプルではなくて、自分的に実用的な装置をでっち上げたいと思い、手持ちのBasys3ボードを使ってSDカード (SPIモード) 読み出しでS/PDIF出力のオーディオ・トランスポート基板を組んでみました。

Basys3ボードはxc7a35tcpg236-1が載っており、基板上に5個のタクト・スイッチが実装されていて十字キーが実現できること、Pmodコネクタが4個付いていることが特徴です。あと、システム的にはどうでも良いことですが、オーディオ・マニアの自分としては、DRAMのような多ビットのIOバスが存在しないので、動作に伴ってパワープレーンをノイズで汚す危険性の少ない基板ではないかと密かに期待しています。

製作物仕様 - 外付けデバイス

オーディオ・ファイルのストレージ用として、Digilent社のmicroSDカード基板(Pmod)を、ディスプレーにはAmazonで調達したHiLetgoの1.3インチOLEDディスプレーモジュール基板(SPI 128x64)を採用しました。OLED基板はユニバーサル基板を使ってPmodに仕立てました。この中華OLEDはなかなか奇麗で、一度使うといわゆるLCDモジュールは使う気がしなくなります。

普及している0.96インチの製品はサイズがいまいち小さいので老眼には更に厳しいものがありますが、この1.3インチのSPI接続用モジュールは他に無いようなので大変貴重です。

microSDソケットとOLED

図1b


回路構成

回路構成は図2のようなブロック図となります。2つのSPIコントローラは標準のAXI Quad SPIでも問題ないと思いますが、都合で自前のIPを使いました (SDカードから4bytes連続で読み出し、armマイコンにぶら下げたRAMへはワード単位でストアしたいので、SPIアクセスが32bitでもできるものならOKです )。そのほか、Timer、GPIO、そしてUartLiteは必須でしょう。唯一特徴的なことは、オーディオ・データ専用のFIFOを設定していることで、ファームがSDカードから読んだデータを何らかのレジスタ経由で直接FIFOへストアしたら、あとはフリーランのオーディオクロックのタイミングでオーディオ・データが勝手にFIFOから抜き出され、S/PDIFフォーマットに変換されて出力されるようにしていることです。ファームの仕事はSDカードからオーディオ・データをFIFOへ移動するまで、ということになります。

回路ブロック図

図2

そのために、ファームからアクセス可能なメモリ領域としてAXI BRAM Controller経由でブロックメモリ(BRAM)を繋げています。ブロックメモリはデュアルポート構成にしてあり、ポートAにはAXI BRAM Controller経由でSDカードのオーディオ・データがPIO転送されてきます。一方、ポートBからはフリーランのオーディオクロック・タイミングで制御されたアドレスとイネーブル信号に従ってオーディオ・データが出てきます。spdif_master コントローラというのが、そのタイミングを作ってブロックメモリのポートBを制御し、受け取ったオーディオデータをS/PDIFに成形して出力するIPです。

このように、Cortex-M3にはITCM、DTCMと、FIFOを実メモリとしてぶら下げた構成としています。すべてのメモリはArtix-7のブロックメモリ(BRAM)から成っており、BRAM使用率は結果的に100%になりました。内訳は、ITCMが128kB、DTCMが64kB、そしてFIFOが8kBです。このうち、オーディオ・バッファとしてファームではFIFOから2kBを確保しています。
FPGAのコンフィグレーションが済んだ時点で、内部のBRAMたるITCMとDTCMにはプログラムコードとデータ等の初期値が既に入っているようにしており、外部の不揮発性メモリ等からプログラムをロードするというような構成にはしていません(そういう意味ではFPGA自体は外部SPIメモリからコンフィグデータを読み込んで立ち上がっているわけではありますが・・・)。


インプリメント結果

この規模の回路構成で、xc7a35tcpg236-1へのインプリメンテーション結果は図3a、図3bのようになり、Cortex-M3は面積的にかなりインパクトがあります。速度的には50MHzでの動作はぎりぎり厳しいといったところです。これだけの面積が必要となるとコスト面では少々使い難い様に思います。ある程度高度なデータ処理が必要であれば、7a100あたりへスライドするよりもハードマクロのZYNQに移行するか、(FPGAとのデータ交換手段が悩ましくなりますが)基板に外付けで安いCortex-M3チップを載せる選択肢もありそうです。

Cortex-M3インプリメンテーション結果

図3a: xc7a35tcpg236-1へのCortex-M3+αインプリメンテーション結果


BRAMは別としてLUTの使用率が非常に高くなっています。

Cortex-M3インプリメンテーション結果

図3b: xc7a35tcpg236-1へのCortex-M3+αインプリメンテーション結果

 

全く同じ回路でCortex-M3からCortex-M1に変更した構成で合成・配置配線した結果が図4a、図4bです。この程度の面積なら非常に魅力的です。個人的には、高度なデータ処理が必要なければCortex-M1と格闘したいところです。ちなみに、GNUのToolChainでもCortex-M0だけではなく、Cortex-M1もきちんとサポートされていました。このIPがサポートされている他社のFPGAもあるということですね。この構成の場合、CMSISのスタートアップルーチンを少し書き換えるだけで、他のCコードには手を加えなくとも、Cortex-M3からCortex-M1へ移植ができました。

Coetex-M1インプリメンテーション結果

図4a: xc7a35tcpg236-1へのCortex-M1+αインプリメンテーション結果


LUTの使用率は劇的に小さくなっています。

Cortex-M1インプリメンテーション結果

図4b: xc7a35tcpg236-1へのCortex-M1+αインプリメンテーション結果


 

ちなみに、やはり同じ構成でMicroBlazeプロセッサをxc7a35tcpg236-1へ組み込んだ場合のインプリメンテーション結果は図5のようになり ( ※ブロックメモリの容量は同じになっていません )、さすがにXilinxFPGA専用のIPといったところでしょうか。速度的にもCortex-M3の倍近いクロックスピードで動作可能になっています。


MBインプリメンテーション結果

図5  xc7a35tcpg236-1へのMicroBlaze+αインプリメンテーション結果


ファームウェア(ソフト)開発環境

開発環境として、KeilのMDKが3か月間無償で使用可能です。それを過ぎると生成可能コードサイズ限定版に振り替える必要があります。Armとしては、IPは無償で提供するのでツールにお金を支払って欲しいというのがビジネスモデルなのでしょう。それでも親切にGNUのコンパイラも提供されており、開発環境を低コストで構築することができるようになっています(https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads)。ただし、いろいろ四苦八苦することになりました。現状のコードサイズはKeilツールの制限をまだ超えていませんが、フリーのGCCが使えるので気が楽です。しかし、開発初期段階ではMakefileやリンカ・スクリプトと格闘しました。

ファームをビルドするために、リンカ・スクリプトにITCM、DTCM、そしてFIFOの3つのメモリ領域をきちんと定義することが必要でした。図6のメモリ・マップにある通り、0x6000_0000から始まるFIFO領域も第3のメモリとして定義し、Cのコード中ではオーディオ・バッファの領域をこのFIFO領域に属するものとして__attribute__指定で定義すれば良いようです(u8 AuBuff[2048] __attribute__((section(".fifo"))); のように・・・)。


メモリマップ

図6  メモリマップ

開発途上での注意(BRAM編)

ITCMとDTCMのイニシャライズデータは.mifファイルと同等のフォーマットでCortex-M3のIP内で指定するようになっています。ただし、IP群をつないで真っ新な状態から論理合成→配置配線するのではなく、ファームウェアを修正してITCMやDTCMのイニシャライズデータのみを変更した状態で合成・配置配線を実行しても両者の内容が更新されないようです。

そもそも、ファームの修正を行うたびにFPGAの合成・配置配線を繰り返していたのでは効率が悪すぎます。そのために.mmiファイルが用意されています。.mmiファイルにはITCMやDTCMとしてアサインされたFPGA内のブロックメモリの位置情報とビット割り当て情報が記載されていて、ファームウェア修正後に新しい.elfファイル中のITCMやDTCMの内容で、.bitファイル中のブロックメモリの内容だけを更新し、新しい.bitファイルを生成するためのtclスクリプト(make_prog_files.tcl)と共に使用するようになっています。

.mmiファイルはITCMやDTCMがFPGA内のどこのブロックメモリ(BRAM)に物理的にマッピングされているかを上記のtclスクリプトがわかるようにするためのものです。回路を変更してから合成・配置配線するとBRAMのマッピングは結構頻繁に変りますので、そのたびに.mmiファイルも作り直す必要があります。そのためのtclスクリプトとしてmake_mmi_file.tclが添付されています。

ただし、添付されているサンプルプロジェクト用の.mmiファイルにはITCMのマップ情報しか記述されていませんし、make_mmi_file.tcl自体も、ITCMのマッピング情報しか書き出せない仕様になっていますので、DTCMやFIFOがどのBRAMにマップされているかは別途.mmiファイルに追加しなければなりませんでした。
そこで、DTCMの場合はスクリプト中に出てくる"itcm"という単語を"dtcm"と書き換え、スクリプトが"AddressSpace Name"としてDTCMのマッピング情報を引いてくるようにすることでDTCMの情報だけを取得し、その後にITCMの情報に追加することで対処しました。本来はスクリプトを書き換えてITCM/DTCM両対応にするべきでしょう。

FIFOに関しても.mmiで指定する必要がありましたが、ITCM/DTCMとは構成が大きく異なりますので、名前を書き換えただけでは正しいマッピング情報を引いてくれません。とりあえず対処療法として、Vivado上で"Implemented Design"を開いた状態で"ctrl"+"F"を押すと出現する"Find"というダイアログBoxの"OK"ボタンを押します(図7)。そして"Find Results"タブに出てくるBRAMのマッピング情報と(図8)、"Cell Properties"からBRAMのSite情報を得て(図9)、DTCMの下に追加しました。
参考までに、そうして書き出したITCM/DTCM/FIFO三つ巴の.mmiファイルを置いておきます


BMEM情報の捜索

図7  Findダイアログ

見つかったBMEM情報

図8  BMEMの情報

BMEM情報の捜索

図9  BMEMのSite情報

デバッグ

デバッグをどうするかですが、回路設計者としてはVivadoでシミュレータを走らせるのが一番簡単で楽でした。CPUが無事にブートするようになり、各AXIペリフェラルが想定通り動作しているかを確認するにはHDLシミュレータを使うのが楽です。Xil_Out32関数で任意のアドレスにアクセスすることができますので、ペリフェラルそのものの動作確認は容易です。

ファームが大きくなってきたときにソフト屋さんが使う通常のデバッグ手法が現状の構成では使えないのが難点かもしれません。必要に応じて、BSCANE2をインスタンスしてCortex-M3のJTAG線をFPGAの外へ出し、ボード上のFTDIチップを"USB to JTAGコントローラ"としてDigilentのadept2と連携させることを考えてみるとか・・・?

結び

以上のように、Basys3ボード上のxc7a35tcpg236-1にCortex-M3のIPを組込み、GCCでファームをコンパイルしてSDカードをソースとしたオーディオ・トランスポートを作ってみました。現状の仕様ではサンプリング周波数44.1kHz、量子化ビット数16bitのwaveファイルのみしか扱えません。GAPレス再生に非対応です。一応8+3文字以上のロングファイル・ネーム対応で、日本語は扱えませんが、CDリッピングの際には文字コードのエンコード種別としてUTF-16を指定します。今後日本語のフォントファイルをDTCMに置くなどして対応することになると思います。その際には大きなELFファイルになるでしょう。まだまだFATのハンドリングが完全ではないようで、細かい不具合は散見されますが、ひとまず私的には実用品として活躍してくれています。Arm、GNU Toolchainの他、FatFsには大変お世話になりました。

なお、ボード上の水晶発振器を45.1584MHzに交換してありますので、残念ながら一般的なBasys3ボードではすぐに利用できる設計リソースではありません。

以上、開発体験記(備忘録)でした。