2021年3月21日日曜日

STM32CubeIDE: I2Sを32bit長で使う

STM32のI2Sで32bitデータを扱う場合は、32bit変数の上位16bitと下位16bitを入れ替える必要があります。

参考
「可燃ごみ箱」さん 「STM32 I2S DMA利用時の32ビット対応
「平坂久門ただいま失業中」さん 「STM32でDCCを作る方向で (8) I2Sの具合はどうかな?

uint32_t型の変数をそのまま使った場合のI2S信号をAnalog Discovery 2のLogic機能で見てみました。

STM32CubeIDE: Version 1.5.1
Target board: Nucleo-F446RE

MXの設定


Multimedia
  I2S2
    Mode
      Mode: Half-Duplex Master
  Configuration
    Parameter Settings
      Generic Parameters
        Data and Frame Format: 32Bits Data 32Bits Frame
        Selected Audio Frequency: 48KHz

Data and Frame Formatで32bitデータを指定します。

main.cに追加


  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  uint32_t data[2] = { 0xffeeddcc, 0x77665544 };
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	if (HAL_I2S_Transmit(&hi2s2, (uint16_t *)data, 2, 100) != HAL_OK) {
		Error_Handler();
	}
  }
  /* USER CODE END 3 */

簡単にメインループ内でPollingしました。送信するデータはわかりやすいようにバイトごとに区切って数字を変えています。

HAL_I2S_Transmit()の3番めの引数は、STM32F4のHALのドキュメント「UM1725 User Manual Description of STM32F4 HAL and low-layer drivers」に
HAL_StatusTypeDef HAL_I2S_Transmit (I2S_HandleTypeDef * hi2s, uint16_t * pData, uint16_t Size, uint32_t Timeout)

Size: number of data sample to be sent
とありややこしいですが、32bitデータの場合、32bitデータとしての個数を指定すれば良いようです。

「32 Bits Data on 32 Bits Frame」で「32bitデータが2個」なのでSize=2となります。

pDataがuint16_t型へのポインタなので何となく「16bitデータがが4個」としてSize=4としたくなりますw

I2S信号を観測



LchがDDCC:FFEE、Rchが5544:7766と16bit単位で逆順になっています。

Analog Discovery 2のLogicのI2Sの設定

Analog Discovery 2の「-I2S」のカラムをダブルクリックするとI2Sの解釈方法を設定できます。FormatをHexadecimalとして16進数表示させています。

16bit毎の入れ替え処理を追加

Byte(8bit)単位の入れ替えは、ARMのアセンブラにREVという命令があり、GCCでも__builtin_bswapXX()という関数が使えますが、16bitごとの入れ替えを一発でというものは無いようなので、プログラムで行うことにします。

/* USER CODE BEGIN PFP */
static int32_t swap16(int32_t x);
/* USER CODE END PFP */

<中略>

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  int32_t data[2] = { 123456, -234567 };
  data[0] = swap16(data[0]);
  data[1] = swap16(data[1]);
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	if (HAL_I2S_Transmit(&hi2s2, (uint16_t *)data, 2, 100) != HAL_OK) {
		Error_Handler();
	}
  }
  /* USER CODE END 3 */

<中略>

/* USER CODE BEGIN 4 */
static int32_t swap16(int32_t x)
{
	return (uint32_t)x << 16 | (uint32_t)x >> 16;
}
/* USER CODE END 4 */

I2Sは符号付き整数の場合が多いのでint32_t型のデータに変更しています。

ビットシフトにより16bit単位の入れ替えを行っていますが、シフトする場合は論理シフトを使うようにuint32_tにキャストします。int32_tのままだと算術シフトになり負数の場合空いた上位ビットが1で埋まってしまいます。

I2S信号を観測



期待通りの信号が出力されています。

Analog Discovery 2のLogicのI2Sの設定

FormatをTwo's complementとして2の補数で表示させています。
 

0 件のコメント:

コメントを投稿