2025年6月23日月曜日

【STM32】 I2C EEPROM動かすのに案外てこずった

秋月でも売ってるI2C EEPROM.こんなの動かすの簡単じゃーん.実際動かしたことあるし.

なのですが、Arduinoでなら簡単ポンで出来たことがSTM32だと難儀したりして、忘備録だか備忘録だか忘れたが書き留めておこうそうしよう.

かつてのこちらの投稿でも少し書いたのですが、STM32のライブラリでI2C EEPROMを動かすとき、
 HAL_I2C_Master_Transmit()
 HAL_I2C_Master_Receive()
だと実装できんと思います.
代わりにこれを使う必要がある.
 HAL_I2C_Mem_Write()

なぜか?
EEPROMのBYTE readシーケンスを見ていただきたい.
total 4bytesのI2C動作になるのだが、前半はwrite動作、後半はread動作になっている.
すなわち、
 1BYTE目 device address  CPU→EEPROM
 2BYTE目 memory address CPU→EEPROM
 3BYTE目 device address  CPU→EEPROM
 4BYTE目 read data     EEPROM→CPU
この複雑な動作をHAL_I2C_Master_Receive()では出来ない.
ならば前半をHAL_I2C_Master_Transmit()でやって後半をHAL_I2C_Master_Receive()でやればいいと思っても、中央部でSTOPを発行するの禁止なので無理.これが1つ目の地雷.

地雷回避は、HAL_I2C_Mem_Read()を使ったこのような関数でやることになる.
uint8_t EEP_read1(int adrs){
 uint8_t rd;
 HAL_I2C_Mem_Read(
  &hi2c2,
  0b10100000 + ((adrs&0x700)>>7), // adrs[10:8]
  (uint16_t)(adrs & 0xff),
  I2C_MEMADD_SIZE_8BIT,
  &rd,
  1,
  500);
 return rd;
}

writeは HAL_I2C_Mem_Write()を使ったこのような関数でやることになる.
void EEP_write1(int adrs, uint8_t wdata){
 HAL_I2C_Mem_Write(
  &hi2c2,
  0b10100000 + ((adrs&0x700)>>7), // adrs[10:8]
  adrs & 0xff, // adrs[7:0]
  I2C_MEMADD_SIZE_8BIT,
  &wdata,
  1,
  500);
 HAL_Delay(5);   ←地雷その2
}

writeにおける地雷その2は5mSec waitしないとうまく書けない.
これはdatasheetにも書かれていて、正統にはACKをpollingしたら良いのかもしれないが、面倒なので一律5mSec入れてる.


ArduinoのI2C libraryだと裏で勝手に地雷回避してくれてた記憶があるので、STM32だと悩んでしまいました.

ご注意のほど.

かしこ

0 件のコメント:

コメントを投稿