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);
しておけば、必要な構造体メンバの初期化がされるので、必ず行うべきなのだった…。
コメント