STM32 HALを使ってI2Cで通信する

  • 2020.05.05
  • HAL
STM32 HALを使ってI2Cで通信する

今回はI2Cによる通信について書いてみます。

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

PC:Windows10 OS
IDE: STM32CubeIDE Version1.3.0
Configurator: STM32CubeMX Version5.5.0
Board: STM32Nucleo-F401RE

I2C通信の概要

・フィリップス(現NXP)セミコンダクターズが開発した通信方式
・SCLとSDAの2本の通信ラインを使って双方向で通信が可能
・通信速度は100k, 1Mbits/secなどいくつか選択肢がある
・マスタとスレーブが存在し、マルチマスタでの構築も可能

I2Cの詳しい仕様については こちら を見て頂ければと思います。

スレーブとなるターゲット

STM32(をマスタ)で制御し、スレーブのデバイスは以下のものを使ってみました。

気圧センサーモジュール

価格は600円でネットを使って購入しました。

メーカーはSTマイクロです。デバイスのデータシートは こちら です。

SCL, SDAラインにプルアップ抵抗をつけるための半田づけジャンパー2箇所を半田づけしておきます。

接続

下表のとおりに接続します。

このモジュールは I2C か SPI のどちらで接続するのか5番ピンでインターフェースを選択することができます。
今回はI2Cで接続するので5番ピンを H (3.3V) につなぎます。
4番ピンはデバイスアドレスの最下位ビットです。これで同じデバイスを2つつなぐことができるわけですが、今回は1つなので L (GND) につないでおきます。
割り込みは使わないのでINT端子は接続していません。

プロジェクトを作成する

IDEを起動し、File- New – STM32 Project を選択し、Target Selection ウィンドウが出たら Board Selector タブを選択し Boards List から NUCLEO-F401RE を選択し Next ボタンを押します。

Project 名に F401I2cHAL と入力し、Finishボタンを押します。
Initialize all peripherals with their default Mode ? と聞いてくるので Yesを押します。
This kind of project is associated with the STM32CubeMx perspective. Do you want to open this perspective now ? と聞いてくるので Yesを押します。

コードジェネレーターでI2Cインターフェースを追加する

今回使うI2Cの端子はPB8とPB9です。(画像の左上付近の赤枠で囲った部分)

PB8を右クリックして選択し、I2C1_SCL を選択します。
PB9を右クリックして選択し、I2C1_SDA を選択します。

端子の色がグレーから黄色にかわることを確認します。

そして Pinout & Configuration – Categories – Connectivity – I2C1 を選択し、
I2C1 Mode and Configuration – Mode の I2C のリストから I2C を選択します。

Project Explorer で F401I2cHAL を選択し、Project – Build Project でビルドします。

端子の色が黄色から緑色にかわります。

また、main.cに MX_I2C1_Init()が生成されていることを確認します。

コードを追加する

MX_I2C1_Init()関数内で完結するコードを書いてみました。

static void MX_I2C1_Init(void)
{

  /* USER CODE BEGIN I2C1_Init 0 */

#define WHO_AM_I 0x0f
#define CTRL_REG1 0x20
#define WAKE_UP 0x90
#define P_ADRS 0x28

  HAL_StatusTypeDef s;
  uint8_t err;
  uint8_t buf[16];
  uint32_t press;

  /* USER CODE END I2C1_Init 0 */

  /* USER CODE BEGIN I2C1_Init 1 */

  /* USER CODE END I2C1_Init 1 */
  hi2c1.Instance = I2C1;
  hi2c1.Init.ClockSpeed = 100000;
  hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
  hi2c1.Init.OwnAddress1 = 0;
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c1.Init.OwnAddress2 = 0;
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  if (HAL_I2C_Init(&hi2c1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN I2C1_Init 2 */

  buf[0] = WHO_AM_I;	// Who am I ?

  s = HAL_I2C_Master_Transmit(&hi2c1, 0xb8, buf, 2, 3000);
  s = HAL_I2C_Master_Receive(&hi2c1, 0xb9, buf, 1, 3000);

  if (HAL_OK == s)
  {
	  if (0xbd == buf[0])
	  {
		  err = 0;
	  }
	  else
	  {
		  err = 1;
	  }

  }
  else
  {
	  err = 1;
  }

  buf[0] = CTRL_REG1;	// Control Register1
  buf[1] = WAKE_UP;

  s = HAL_I2C_Master_Transmit(&hi2c1, 0xb8, buf, 2, 3000);

  HAL_Delay(1000);

  buf[0] = P_ADRS | 0x80;

  s = HAL_I2C_Master_Transmit(&hi2c1, 0xb8, buf, 1, 3000);
  s = HAL_I2C_Master_Receive(&hi2c1, 0xb9, buf, 3, 3000);

  press = buf[2] << 16 | buf[1] << 8 | buf[0];
  press /= 4096;

  /* USER CODE END I2C1_Init 2 */

}

コードの解説

WHO_AM_I というレジスタの値を読んで、 0xbdであればデバイスを認識できているとのことです。
コントロールレジスタ1に WAKE_UP(0x90) を書いてパワーダウンモードを解除します。

気圧の計測値は 0x28 (P_ADRS), 0x29, 0x2a のレジスタから読み込みます。

P_ADRS | 0x80 とすることでアドレスをオートインクリメントして次々と読むことができます。

読んだ値を 4096 で割ることで単位 [hPa]の気圧を得ることができます。

読んで計算した気圧は 1009 とか 1010 [hPa] でした。

よろしければI2Cに関する記事の HALを使ってI2Cでメモリーにアクセスする もご覧ください。

HALカテゴリの最新記事