STM32 HAL_SPI_TransmitReceive()が失敗する

  • 2021.01.16
  • HAL
STM32 HAL_SPI_TransmitReceive()が失敗する

皆さま こんにちは。

今回は HALを使ったSPI通信が失敗するパターンのお話です。

STM32 HALを使ってSPIで通信する の記事をベースにしたお話ですので、まずはそちらをご覧になってください。

投稿時の開発環境を記しておきます。

PC:Windows10 OS
IDE: STM32CubeIDE Version1.5.0
Configurator: STM32CubeMX Version6.1.0
Board: STM32Nucleo-F401RE

SPI通信が失敗する

SPIは以下のようにして通信します。

(1)CS=Lにしてデバイスを選択する
(2)送受信する
(3)CS=Hにして選択解除する

私は起動後に、

HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); // CS=L
HAL_SPI_TransmitReceive(&hspi1, sbuf, rbuf, 2, 1000); // Transmit & Receive
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); // CS=H

というコードを書きました。
内容はデバイスコードを問い合わせるコマンドで、受信した値により正常/異常の判断をしています。
何故か失敗し、2回繰り返すと2回目は成功するので、それで良しとしていました。

最近やっと簡易ロジアナが動くようになったので、波形観測をしてみました。

上から
CS
CLK
MOSI
MISO
です。

起動時の設定直後は、制御レジスタ1の SPEビット(ビット6)が0になっています。
そしてHAL_SPI_TransmitReceive()関数の中には以下のコードが書かれています。

/* Check if the SPI is already enabled */
if ((hspi->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE)
{
  /* Enable SPI peripheral */
  __HAL_SPI_ENABLE(hspi);
}

従って起動後最初の関数実行時には、このif()の中を通ります。
SPIをイネーブルにしたところが、図の緑色の部分になります。

意図せぬところで CLK が動いてしまったので、デバイスコードが返ってこないという結果になっています。
2回目がうまくいく理由は、すでにSPIがイネーブルになっているために、if()の中を通らないからです。

HALの関数の中をいじるわけにもいかないので、以下のコードで回避しました。

(個人的には、送受信関数の中でペリフェラルをイネーブルにするコードがあるのはどうか?と思っています)

HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); // CS=Hにしておく
__HAL_SPI_ENABLE(&hspi1); // あらかじめEnableにしておく
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
s = HAL_SPI_TransmitReceive(&hspi1, sbuf, rbuf, 2, 1000);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);

これで2度読みする必要はなくなりました。
波形は以下の通りです。

詳しく調べていませんけれど起動時だけの問題のようです。。

いかがでしたか?
HAL の SPI が動かなかったら思い出してみてください。

組み込み屋さんにとって、時にロジアナは強力な味方になってくれます。

いやぁ、ロジアナってほんっとにいいモノですね。。

HALカテゴリの最新記事