2019年3月25日月曜日

STM32: HALライブラリを使ってI2C送受信

SW4STM32(System Workbench for STM32)とSTM32CubeMX(初期化コード生成ツール)でI2Cをいじっています。STM32標準のHALライブラリを使えば、コマンド1行でI2Cを簡単に扱えますが、サンプルコードから少し外れた使い方をしようとするといきなり行き詰まってしまいました。とても初歩的ながら、ポインタやら構造体を勉強しないと動かせないようです。そこで、試行錯誤して動作確認できたコードをメモとして残しておきます。

やりたいこととしては、SiliconLabsのAM/FMラジオ Si4730の制御です。Si4730は、STM32のI2C1に接続されていてアドレスは0x11です。STM32CubeMXでI2C1を適切に設定し、初期化コードが生成されていることを前提とします。

I2Cで送信

まずは送信です。0x12 SET_PROPERTYコマンドでProperty 0x0104 DIGITAL_OUTPUT_SAMPLE_RATEに0xBB80を設定します。I2C送信データとしては、レジスタ0x12にレジスタ値0x000104BB80を送信することになります。ロジアナ波形は次の通りです。


HAL_I2C_Master_Transmit()関数の場合

  uint8_t txBuffer4730[6];
  uint16_t Si4730_Pri_address =  0x11<<1;

  txBuffer4730[0] = 0x12;
  txBuffer4730[1] = 0x00;
  txBuffer4730[2] = 0x01;
  txBuffer4730[3] = 0x04;
  txBuffer4730[4] = 0xBB;
  txBuffer4730[5] = 0x80;
  HAL_I2C_Master_Transmit(&hi2c1, Si4730_Pri_address, txBuffer4730, 6, 100);

  • 第2引数は7ビットのデバイスアドレスを1ビット左シフトさせます
  • 第4引数は送信データのByte数

HAL_I2C_Mem_Write()関数の場合

 この関数を使って同じ波形を作れます。メモリアクセス用の関数なのでレジスタとデータを分けて指定します。

  uint8_t txBuffer4730[5];
  uint16_t Si4730_Pri_address =  0x11<<1;

  txBuffer4730[0] = 0x00;
  txBuffer4730[1] = 0x01;
  txBuffer4730[2] = 0x04;
  txBuffer4730[3] = 0xBB;
  txBuffer4730[4] = 0x80;
  HAL_I2C_Mem_Write(&hi2c1, Si4730_Pri_address, 0x12, 1, txBuffer4730, 5, 100);

  • 第2引数は7ビットのデバイスアドレスを1ビット左シフトさせます
  • 第3引数はメモリ(レジスタ)アドレスを指定
  • 第4引数はメモリ(レジスタ)アドレスサイズのByte数
  • 第6引数は送信データのByte数


I2Cで受信

次に受信です。先ほど設定したプロパティを 0x13 GET_PROPERTYコマンドで読み出します。I2Cでの通信手順としては、まず最初に4バイトのレジスタ指定(書き込み)を送信し、直後に受信する2ステップの流れとなります。

HAL_I2C_Master_Receive()関数の場合

  uint8_t txBuffer4730[4];
  uint8_t rxBuffer4730[4];
  uint16_t Si4730_Pri_address =  0x11<<1;

  txBuffer4730[0] = 0x13;
  txBuffer4730[1] = 0x00;
  txBuffer4730[2] = 0x01;
  txBuffer4730[3] = 0x04;
  HAL_I2C_Master_Transmit(&hi2c1, Si4730_Pri_address, txBuffer4730, 4, 100);
  HAL_I2C_Master_Receive(&hi2c1, Si4730_Pri_address, rxBuffer4730, 4, 100);
  • 第2引数は7ビットのデバイスアドレスを1ビット左シフトさせます
  • 第3引数は受信バッファのポインタ
  • 第4引数は受信データのByte数




HAL_I2C_Mem_Read()関数の場合

この関数では、送信と受信を一括して行える反面、2バイトまでしかレジスタ指定できません。参考としてレジスタ0x12ABから3バイトを受信する場合を例示します。

  uint16_t txBuffer4730;
  uint8_t rxBuffer4730[3];
  uint16_t Si4730_Pri_address =  0x11<<1;

  txBuffer4730 = 0x12AB
  HAL_I2C_Mem_Read(&hi2c1, Si4730_Pri_address, txBuffer4730, 2, rxBuffer4730, 3 , 1000);

  • 第2引数は7ビットのデバイスアドレスを1ビット左シフトさせます
  • 第3引数はレジスタアドレス
  • 第4引数はレジスタアドレスのByte数
  • 第5引数は受信バッファのポインタ
  • 第6引数は受信データのByte数