stm32CubeMX で FSMCによるFPGAアクセスでトラブル

stm32f407IGT6を搭載したモーターコントロールボードでSTM32F4xx_StdPeriph_Driverライブラリを使って作っていたプログラムをバージョンアップしてSTM32Cube FW_F4 V1.16.0に対応した時にFPGAへのインターフェースで悩んだ件。

ボードはFSMCのSRAM較正でFPGAにアクセスしています。
以前のライブラリを使ったプログラムではサンプルプログラムを参考にした初期化で簡単に動いたのでSTM32CubeMXを使えばもっと簡単に出来ると思っていました。

しかしFPGAからの読み出しは動作するものの書き込みが出来ない不具合が発生し原因がどうしてもわからず、レジスタの内容をダンプして比較してみたり色々悩んで3日間ほど回り道をしてしまいました。

FSMCの設定のせいだと思い込んでいたのですが、結局判ったのはstm32f407のMCO出力端子からクロックが供給されていないことがトラブルの原因でした。

勿論端子からMCOを出力する設定は出来ていましたがGPIOの設定で出力端子の出力速度がLowになっていたため50MHzのクロックを出力すると殆どHiレベルのままになっていました。

STM32F4xx_StdPeriph_Driverライブラリを使ったプログラムでは初期化コードを自分で書いていくスタイルなのでこのような見落としは少なかったのですが、STM32CubeMXのように初期化コードが自動的に生成されてしまうとこのようなトラブルが時々発生します。

JDEでSTM32CubeMXが生成したプロジェクトを読み込む

STM32CubeMXは組み込み開発で最も面倒で退屈なハードウェアの初期化部分をGUIを使って設定して初期化済みのプログラムテンプレートを生成してくれるツールです。
統合開発環境JDEはSTM32CubeMXが生成したプロジェクトをインポートすることが出来るようになりました。

ここではSTM32CubeMXが生成したプロジェクトをベースにJDEのプロジェクトを作る手順を簡単に説明します。

 

1.STM32CubeMXで作成したプロジェクトを出力するためにProject → Settingsを開きます。

2.Project Settings画面のToolchain/IDE設定でTrueSTUDIOを選び GenerateUnderRootのチェックを外します。
他の項目はそのままでOKです。

3.Project → Generate Codeをクリックしてコードを生成します。

4.Codeが生成されたらそのままメッセージを閉じます。

プロジェクト保存場所に次のようなフォルダとファイルが作成されているはずです。

5.JDEを開き新規プロジェクトを作成します
プロジェクトを作成する場所はSTM32CubeMXでプロジェクトを保存したフォルダにして下さい。

6.JDEのCpudef(CPU定義)はSTM32CubeMXのHALライブラリと同じものを選んでください。

7.CPU定義ファイルだけのプロジェクトが作成されます。

8.TrueStudioプロジェクトインポートメニューを開きます。

9.インポート元としてTrueSTUDIOプロジェクトを指定して、開くをクリックします

10.プロジェクトがインポートされ、ライブラリとソースファイルを含むプロジェクトツリーが表示されます。

プロジェクトのシンボル定義でプロジェクトの構築に必要なのは上の2行です、赤枠で囲んだ部分はコンパイルエラーの原因になるので削除してください。

11.プロジェクトは構築可能になっているはずです、再構築ボタンをクリックしてコンパイルしてみます。

12.下のコンパイルメッセージに「コンパイルとリンクが終わりました」と表示されればテストOKです。

13.STM32CubeMXが生成したプロジェクトは次のような構成になっています。

./Drivers/の下にあるファイルはHALライブラリで通常は変更する必要ありません。
./Src/の下にあるファイルを修正、追加してプログラムを作っていきます。

例えばmain.cは次のような内容です
/*  USER CODE BEGIN … */ と/* USER CODE END …*/で囲まれた部分はSTM32CubeMXで設定を変更してプロジェクトを再生成しても変更されずに残りますのでこの部分にユーザーコードを追加していきます。

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f1xx_hal.h"
// ※ ここに追加したコードはSTM32CubeMXでプロジェクトを再生成すると失われる
/* USER CODE BEGIN Includes */
// ※ ここに書いたコードはSTM32CubeMXの影響を受けない
/* USER CODE END Includes */

/* Private variables ---------------------------------------------------------*/
TIM_HandleTypeDef htim5;

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
void Error_Handler(void);
static void MX_GPIO_Init(void);
static void MX_TIM5_Init(void); 
void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim);


/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/

/* USER CODE END PFP */

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

int main(void)
{

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

/* MCU Configuration----------------------------------------------------------*/

/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
 HAL_Init();

/* Configure the system clock */
 SystemClock_Config();

/* Initialize all configured peripherals */
 MX_GPIO_Init();
 MX_TIM5_Init();

/* USER CODE BEGIN 2 */

/* USER CODE END 2 */

/* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
 /* USER CODE END WHILE */

/* USER CODE BEGIN 3 */

}
 /* USER CODE END 3 */

}

/** System Clock Configuration
*/
void SystemClock_Config(void)
{
  .. 
 この後に初期化関数が続きます。

STM32CubeMXをGCC(JDE)で使う(1)

STM32CubeMXについて

Stm32CubeMXはベースとなるライブラリHALも動作が安定してきて既にSTM32CubeMX抜きの開発など考えられないほど便利な開発環境です。
ただ、便利になったぶん構造が複雑になって、以前のライブラリのようにフリーの開発環境で簡単にHALを使うのは難しくなりました。

統合開発環境JDEの生い立ち

私は組込開発に専ら自作の開発環境であるJDEを使っています。
現在、組込用メインCPUとしているtm32Fシリーズを使い始める前は、H8、SHシリーズを使っていて、その前はV25を組込み開発用のCPUとして使っていました。

V25はPCと同じ86系のCPUなので、PC用のコンパイラであるBCC(Borland C Builder)とBCCが生成したPC用のオブジェクトを組込ボードで動作させるために作ったV25モニタを使ってコンパイル、転送、実行が素早くできる工夫をして自社製品にも活用しましたしV25ボードも様々な方に愛用していただきました。
そのV25がディスコンなどで使えなくなりH8,SHシリーズを使い始めた時に作ったのがGCCをベースにしたJDEです。

GCC

H8、SHシリーズを使い始めた時に開発用のコンパイラとして何を選ぶかという問題がありました。
当時はまだオープンソースのソフトをキワモノ扱いする人も多くメーカー純正コンパイラの評価が圧倒的に高い時代でしたが将来的にはGCCが優位に立つという見通しでGCCを選択しました。
他の理由としてはCPUボードや製品を愛用していただいている方に学校関係者や研究職の方が多いため「出来るだけフリーソフトで開発できるようにしたい。」ということもありました。
今ではLinuxが普及したこともあり汎用コンパイラとしてのGCCの評価は完全に固まり、組み込み用としても最適化性能を除いてはGCCが優位になりました。

最適化性能をどれだけ問題にするかは立場によって異なります。
民生機器のように数円のコストが問題になる場合はギリギリの性能と最小限のROM/RAMを持つCPUを使うためにコストや汎用性等他の点を犠牲にしても最適化性能に優れたコンパイラを使う必要があります。
一方私たちのようにFA分野の仕事を手掛ける場合や研究職、教育関係者の方々にとっては最適化性能より汎用性、コストパーフォーマンスに優れたコンパイラを使う方が有利です。
何故なら、組込分野では使えるCPUの性能は様々であり多少のコストアップで最適化性能の差を埋めるCPUを使うことが出来るからです。

具体的な例をみると、マイコンカーラリーのレギュレーションで決まっているR8Cボードに搭載されているR8C/38Aという16ビットCPUは秋月価格450円でROM128KB,RAM20KB、クロック20MHzですが、マイコンカーラリー用のデータロガーボードの試作に使ったDigiKeyで入手できる価格1517円のSTM765VGT6は32ビットでクロック216MHz、ROM1MB、RAM512KBと一桁以上の性能を有しています。
このくらいのROM/RAMがあればリアルタイムOSも楽に動くので制御ループと同時にモニタプログラムを走らせておくことも出来ますし浮動小数形式が使える普通のprintfを使っても全く問題がありません。

つまり最新の高性能組込用CPUを使えば最適化性能を気にする必要は無く、オープンソースのGCCを問題なく使えるということになります。

JDEの履歴

JDEを作った当初の目的はGCCを使うこと以外にV25モニタの思想を引き継いだH8用モニタを使ってコンパイラから転送、実行までの流れを自動化するということにありました。
私が開発を効率化するために最も重視するのはボード上の情報可視化とターンアラウンドタイムの短縮です。
H8はボード上のCPUにシリアルケーブルだけでプログラムを書き込み出来るオンボードプログラミング方式の先駆けとなったCPUでしたがCPUに書き込むために「電源を切る → ブートモードSW ON → 書き込み → 電源を切る → ブートモードSW OFF → 電源投入」という手順を踏む必要がありました。(今のR38C/38Aボードも同じです)
H8モニタを使えば書き込むために一度ボードのリセットボタンを押す必要はありますがボード上のスイッチを操作しなくても転送から実行が出来ますし、モニタモードでボードのメモリ情報を見ることが出来るようになっています。
僅かな差ですが、スイッチ操作の削減とモニタモードでの情報があることで、開発が効率的になるものです。

H8、SHシリーズに見切りをつけたのはルネサスの大手メーカーだけを向いた営業姿勢により突然デバイスの供給が数か月中断するといった事態が起こり始めたのがきっかけでした。(具体的には自動車メーカーの都合で一般へのデバイス供給が中断した件)

JDEはGCCがサポートしているCPUなら何でも使えますから、GCCが組サポートしているアーキテクチャの中で最も前途有望と思われるARM系のCPUにターゲットを絞って検討を開始し、最初はATMEL社のCPUを暫く使ってみてその後、周辺機能が充実したstm32シリーズを使い始めて今に至っています。

JDEにSTM32CubeMXが生成したプロジェクトのインポート機能追加

STM32CubeMXが出てくるまではJDEをプロジェクト管理ツール+OopenOCD仕様の書き込みアダプタを使った書き込みツールとして便利に使ってきました。
それだけならば特にJDEにこだわる必要もありませんでしたが、STM32CubeMXが生成したプロジェクトをインポートする機能を追加出来たことで自分が好きなように改造できるツールJDEを使っていて良かったと、改めて思っているところです。