STM32H7でSPI

ちょっと嵌ったので備忘録的に。
以前公開したこちらの記事ですが、その後STM32H7でも同じようなことを行おうとしました。
okb-lysenko.hatenablog.com

○事象
F7のときとほぼ同じ設定であるのにも関わらず、SPIのDevice IDに誤った値が
帰ってくる。(何らかの原因で通信に失敗している)

○対処
今回はオシロすら使うまでもなく、気まぐれで設定を弄ったら治ってしまいました。
H7ではF7には存在しなかったオプションがあると思います。
色々調べて、特に怪しいなと考えたのは以下の項目でした。(デフォルト値を併記します)

・NSSP mode->Enable

・Nss Polarity->Low

・Master Keep Io Status->Master Keep Io Status->Disable

これらのうち、上2個はどうも間違っていなさそう。しかし3番目がよくわからん。そこで
次のような投稿を見つけました。

https://community.st.com/s/question/0D53W00000A2xuESAR/why-is-spi-not-working-on-nucleoh743zi2-nss-is-wrong-direction-and-no-clockno-output-solved-but-why

投稿主はNSS HW制御なので状況は違うのですが、試しに以下のように設定変更すると、
無事0x38が戻ってきました。

・Master Keep Io Status->Master Keep Io Status->Enable

HW制御でなくても影響を受けるものなのですね・・・。

STM32H7 NucleoでError: No STM32 target found!になる

※当記事の内容を実践して生じたいかなる損害に対しても補償はできません。かならず御自身で設計検討を行なってください。

タイトルのとおりです。
半導体不足の最中、昨年入手したSTM32H7A3 Nucleo-144で遊んでおりました。

○症状
これまで普通にProgramming、Debugができていたのに、突然タイトルのようなエラーが
出てSt-linkにつながらなくなった。Core Voltage等は読めており3.3V付近を指しているが、
MCUがロックアップしているのかEraseもできない状態。

○原因(推定)
不明だが、電源周りの設定が誤っていた可能性がある。
main.cの中のSystemClock_Configという関数に以下の記述がある。

HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY)


ただ、ボードのUsers Manual(UM2408)を読むと、デフォルトはSMPSからの供給となっており、
おそらく下記が正しい。

HAL_PWREx_ConfigSupply(PWR_DIRECT_SMPS_SUPPLY)

ちなみに、上記Manualには「設定を誤るとDeadlockする」とハッキリ書いてありました。
CubeMXの生成コードのままなので、どこかに設定項目があるのかもしれません。

○対処
とりあえずはロックアップを解消し、Eraseを実行しないといけません。
今回はCube MX Progをダウンロードし、Connect Under Resetの要領でなんとかMCUを認識
させることができました。
Connectさえできれば、あとはEraseして回復を確認するのみです。

根本原因に対する対策としては、上記原因箇所を変更すれば良いものと思われます。

○参考
2点紹介します。復旧の方は根本原因が違っても参考になると思います。

復旧方法:
community.st.com

原因推定:
ST Community

IMU383を使う

こんなブログにでもコンスタントにアクセスを頂いています。主にElecrow発注記事が参照されているようで、何を隠そう私自身も活用しています。毎週発注するわけでもないですから、忘れてしまうのは仕方がないことですね。

 

最近は半導体不足もあって、あまり工作が進んでいません。

最近のトピックとして、Aceinnaという会社のIMUであるIMU383を入手しました。

www.aceinna.com

Homebrew界?で有名なIMUといえばIMU6000やその後継機種になるかと思いますが、こちらはもう少しハイエンドよりです。ジャイロや加速度計の詳細なスペックの読み方は優れた記事が国内外にありますので割愛します(語るだけの知識がありません…)が、mouserで個人が1個から購入できる製品は他に見当たらないので、導入してみました。このセンサについて書かれた日本語記事(英語記事すらも)はほぼ存在しないようでしたので、せっかくだから備忘録を残そうと思ったのが今回のモチベーションです。

※本ブログの内容を実践して損害が生じても補償はできません。必ずご自身の手で設計検証を行ってください。

 

■本記事のスコープ

SPI通信のポーリングでセンサからデータを取得する。初めて使うセンサなので、Who am I(0x57)の取得を目指す。IMU383と書いてますが、データシートを読む限り381についても同じ方法で行けると思います。

 

■HW編

今回はセンサの評価という側面が大きいので、まずは手持ちのマイコンボード(STM32F7 Nucleo)にドッキングできるよう治具を起こしました。将来的にはマイコンボードとセットでHWを起こす予定です。(要望があれば治具も共有します)

センサ側のコネクタが少し特殊で、メス側のコネクタを用意するのに少し苦労しました。SAMTECのCLM-110-02-L-D-P-TRという型番のものですが、Mouserで1個600円以上します。代替品を探してみたものの、ちょうどよい製品は存在しないようです。

接続は次のようにしました。初期化をしっかり行う必要があるので、8pinは必ずGPIOにつなぎます。7pinについてはGNDに落とすとUSART接続になりますが、今回はSPIで使用するためPB12につないでマイコン側でpull-upしています。

f:id:Mami_pero_pero:20211008235247p:plain

 

■SW編(初期設定編)

SW開発にはCubeIDEを使っています。mbedのクラウド環境なども使えそうですが、Cubeにもボード別のテンプレートが用意されているので活用しましょう。以下ポイントだけ列挙します。

 

<System Clockの設定>

割とどうでもいいと思いますが、SPI1に供給されるクロックを覚えておきます。

 

<SPIの設定>

今回はSPI1を使いました。Full-duplex Masterで、NSSはSoftware制御にします。

Data Sizeは8bit、MSB Firstです。

Prescalerはデータシート指示の通り1000kB/sとなるよう設定します。これはSystem Clockで設定したSPIクロックをスケーラで除算した値になります。

極性はデータシートによればクロックのアイドル時はHigh、立ち上がりエッジでのサンプリングです。CPOL=High、CPHA=2 Edgeを選択します。

 

<GPIOの設定>

PA4: NSSとして割当。GPIO Outputに設定。Output LevelはHigh。

PB12: DRとして割当。SPIを使用するのでGPIO Inputに設定。pull-upを指定。

PB13: nRSTとして割当。GPIO Outputに設定。Output LevelはHigh。

 

なお、GPIOの項目からAlternative機能を割り当てたピンの挙動を設定することができます。

今回はSPIですが、これらのピンのMax output speedをLowに指定しました。

理由は以下の記事を発見したためです。

blog.boochow.com

実は今回は結構ハマってしまって、オシロ/ロジアナで通信を眺めていて同じような事象に遭遇したためです。このエラッタを踏んでいるのかはきちんと検証できていないのですが、おまじない程度のつもりで設定しています。

 

■SW編(通信編)

実際に通信してゆきます。

 

<初期化>

意外と?初期化ロジックは繊細なようです。大体データシートに書かれている通りで、Delayなどは若干コンサバに書きました。

HAL_Delay(100);

HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);

HAL_Delay(100);

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_RESET); // RESET

HAL_Delay(900);

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_SET); // 

HAL_Delay(500);

 

__HAL_SPI_ENABLE(&hspi1) 

最後の一行はおまじないで、なくても動くと思います。何をしているかの説明は不要ですね。概ねデータシート通りリセットをしています。注意点として、MX_SPI1_Init()を実行したあとに書くようにしてください。私はUSER CODE BEGIN 2という位置に書いています。

 

<byte読み込み>

実際にデータを読んでいきましょう。

void read_single(uint8_t reg, uint8_t* buf){

    uint8_t send[2] = {reg, 0x00};

    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); // select device

    HAL_Delay(1);

    while(!(SPI1->SR & SPI_SR_TXE));

    HAL_SPI_TransmitReceive(&hspi1, send, buf, 2, HAL_MAX_DELAY);

    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);  // 

    HAL_Delay(1);

}

NSSを自分で制御しているので、頭とお尻にそのための処理があります。

Whileループはなぜかベアメタル風ですが、以前書いたものを引っ張ってきただけで深い意味はありません。送信バッファに何も残っていないことを確認しています。

データシートを読むと、データは16bit単位?でやり取りし、一度送受信するたびにNSSを上げ下げする必要があります。つまり、0x57から値を読み出そうとすると、

(1)読み出しアドレス{0x57, 0x00}を送信

(2)ダミーデータ{0x00, 0x00}を送信&データを受信

という2回の送受信が発生し、この間はいちいちNSSを操作します。SPIは全二重通信ですから、なにか送ればなにか返ってきます。一回目の送信でもゴミデータが返ってくる可能性はありますが、これは捨ててしまっていいでしょう。(2)が本命です。

というわけで次のように書きます。main関数の無限ループの中に書きました。

uint8_t buf[2];

read_single(0x57, buf);

read_single(0x00, buf);

buf[1]の値を見てみて、0x38が返ってくれば成功です!

お疲れさまでした。

 

 

 

 

 

 

 

 

STM32CubeでC++を使う(遭遇編)

遭遇編とか書いてますが、多分続かないです。備忘録的要素が強い。

訳あってSTM32F7向けのファームウエアを書いているのですが、その過程でC++の資産を使う場面がありました。少しハマったのでメモとして残します。

ココに記載した手順を実行した結果何が起ころうと責任は取れません。

 

■何が起こったか

CubeMXでC++プロジェクトを指定して自動生成したにも関わらず、template, classなどの記述が弾かれる。

 

今回の主題は上記の通りですが、同時に発生した以下の問題についても対処法を記載します。

#error "Compiler generators FPU Instructions for a device without an FPU..."

というエラーが出てビルドが止まる。

 

■解決方法

身も蓋もないですが

main.cおよびmain.hをmain.cppおよびmain.hppにリネームする

自分の場合これで解決しました。

 

こういう場合うっかりミス(この場合Cを指定して自動生成しているetc.)の可能性を排除しに行くのが先決です。プロジェクトを右クリックして、”C++へ変換”なるオプションが表示されていた場合、Cを指定して自動生成している可能性が高い(みたい)です。その場合C++へ変換を選択することでうっかりを解消できる。

自分の場合は”Cへ変換”なるオプションが表示されているため、おそらく生成時の設定は正しい。ということで、似たようなケースの場合上記の方法で解決するかもしれません。

 

■解決方法(副題)

こちらはこうです

ビルド設定のPath and Symbolsに#__FPU_PRESENTを追記する

こちらはエラーメッセージの通りに対処をしています。ただし、適当な場所に#defineマクロとして書き込むとRedefineだぞ!と怒られます。理不尽だ。

 

■まとめ

これらの問題は正しい手順を踏めば生成時に潰せる問題なのかもしれません。

ただ、正しい生成手順を学ぶ気もない以上、再び同じ問題に遭遇することはほぼ確実ですので、潰し方を書き残しておきます。

 

以上

 

PSoC Creator3.0で%fが使えない

 PSoC Creator3.0にアップデートしてからというもの,sprintfのフォーマット指定子として"%f"が使えないという問題がありました.

sprintf愛好家の自分としては,これは非常に由々しき事態ですので,webの海を渉猟して解決策を探ってみました.

 

こ↑こ↓にありました:http://japan.cypress.com/?app=forum&id=2492&rID=86619

 

どうも3.0ではnewlib-nanoをデフォルトで使うことになってて,そいつが%fをサポートしていないらしい.なんかゴニョゴニョすれば動くぜ!みたいなことが書いてある気がするけど,面倒なのでnewlib-nanoをdisableします.

プロジェクトのBuild Setting->Linker-> Use newlib-nanoをFalseに.

 

これでsprintfで%fが使えるはず.

 

 

 

 

Elecrowへの発注手順

 基板製作にはElecrowというサービスをよく利用しています.

しかしながら,年がら年中発注しているわけでもないので,「いざ注文!」という時にはすっかり手順を忘れている…というわけで,なかば備忘録代わりに手順を記しておくことにします.なお,ガーバを出力する前に必ずデザインルールチェックでエラーが出ないことを確認しておくべきです(まずい箇所があれば作れない旨の連絡が来ますが、二度手間です).

 

1. ガーバデータを出力

 とりあえずCAMファイルが必要なので,Elecrowのページに飛んで,各製造メニュー最下部にあるリンクからDLします.

 

 DLしたCAMファイルをどこでもいいので放り込み,ガーバを出したいEagleプロジェクトを起動して

CAM processor -> File -> Open -> Job を選択,先ほどDLしたCAMファイルを指定します.指定したら,Process Jobをクリック.すると,必要なファイルがプロジェクトのディレクトリに保存されます.

f:id:Mami_pero_pero:20140103003957p:plain

f:id:Mami_pero_pero:20140103003958p:plain

2. Elecrowに投げる

 生成されたファイルのうち,

xxx.GTL

xxx.GBL

xxx.GTS

xxx.GBS

xxx.GTO

xxx.GBO

xxx.TXT

xxx.GML

をzipかrarで固め,注文画面からアップロードします.

生成されたガーバーはビューワを使ってチェックしたほうが良いと思います.GC Prevueやgerbvあたりが使いやすいと思います.

f:id:Mami_pero_pero:20140103005153p:plain

E-Testはどうせ無料なので,100%にしておきましょう.

 

あとは普通の通販と同じように支払いをして完了です.お疲れ様でした.

 

追記(2017-01-08)

こちらの情報は2014年時点でのものですので、発注方法・デザインルールが変わっている可能性があります。基板を発注する機会があったら更新したいと思います。