STM32 ライブラリ xxx_StructInit() は必ず行う

STM32のライブラリでSPIを使ったが、どうも動作が不安定なので悩んでいた。

初期化は

SPI_InitTypeDef SPI_InitStructure;

// 2線・全二重モード
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;

// スレーブモード
SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;
// 8bitモード
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
// クロック極性: 通常時L
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
// クロックフェーズ: 1エッジ
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
// SPI_NSS_Hard: NSSピンはマスターからのCSとして使用しそれにより自動イネーブル
// SPI_NSS_Soft: 手動(SPI_CR1->SSIビットをNSSとして使用)
SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;
// MSBから送受信
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
// CRCは使用しないがデフォルトの多項式 7 を設定
SPI_InitStructure.SPI_CRCPolynomial = 7;

SPI_Init(SPI1, &SPI_InitStructure);

こんなコード。SPI_InitTypeDef 構造体メンバ中、 SPI_BaudRatePrescaler のみ、なにも設定していないが、スレーブモードなので、設定しなくていいと思っていた。

でも、SPI_Init() のソースを見ると、構造体メンバの値を単純にorしたものを、SPI_CR1レジスタに設定していた。

tmpreg |= (uint16_t)((uint32_t)SPI_InitStruct->SPI_Direction | SPI_InitStruct->SPI_Mode |
SPI_InitStruct->SPI_DataSize | SPI_InitStruct->SPI_CPOL |
SPI_InitStruct->SPI_CPHA | SPI_InitStruct->SPI_NSS |
SPI_InitStruct->SPI_BaudRatePrescaler | SPI_InitStruct->SPI_FirstBit);
/* Write to SPIx CR1 */
SPIx->CR1 = tmpreg;

構造体メンバに1つでも未初期化のものがあると、めちゃくちゃな値がCR1レジスタ全体に設定されてしまうのだった…それで不安定だったのかorz。

debug時はassert_param()でパラメータチェックが入るからいいのだが、ズボラにズボラを重ねていきなりreleaseで作っていると当然ノーチェック。

構造体メンバはまず

SPI_StructInit(&SPI_InitStructure);

しておけば、必要な構造体メンバの初期化がされるので、必ず行うべきなのだった…。

コメント

タイトルとURLをコピーしました