cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H5 Not Receiving I2S Data from PCM1804 in Slave Mode (Polled)

Bobliang2012
Associate

 

Subject: STM32H563RIT6 I2S1 Not Receiving Data from PCM1804 in Slave Mode (Polled)

Description:

I'm using an STM32H563RIT6 MCU with an 8 MHz external crystal. The I2S1 peripheral is configured in slave mode (receive only) and connected to a PCM1804 ADC chip, which is set as the I2S master (transmit only). The PCM1804 outputs audio in the following format: 32 kHz sampling rate, stereo, 24-bit data packed in a 32-bit frame. Using a logic analyzer, I confirmed that the I2S signals from the PCM1804 (I2S_WS, I2S_BCK, I2S_SDO) are correct and properly aligned. The connections are as follows:

  • I2S_WS → PA4
  • I2S_BCK → PA5
  • I2S_SDO → PA6

I'm testing I2S data reception with the simplest polling-based code, but the STM32H563RIT6 fails to receive data correctly. During debugging in the Start_I2S1_Polling function, the temp_buffer array (used in HAL_I2S_Receive) contains all zeros, which does not match the data captured by the logic analyzer. Below is my code. Could you help identify what I'm doing wrong? Thank you!

Code in main.c:

#include "stm32h5xx_hal.h"
#include "main.h"

I2S_HandleTypeDef hi2s1;

void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2S1_Init(void);

int Start_I2S1_Polling(void)
{
int EC = 0;
uint16_t temp_buffer[128];

if (HAL_I2S_Receive(&hi2s1, temp_buffer, 64, 1000) != HAL_OK)
{
Error_Handler();
}
return EC;
}

int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_I2S1_Init();

Start_I2S1_Polling();

while (1)
{
Start_I2S1_Polling();
HAL_Delay(1000);
}
}

void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);

while (!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLL1_SOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 4;
RCC_OscInitStruct.PLL.PLLN = 250;
RCC_OscInitStruct.PLL.PLLP = 2;
RCC_OscInitStruct.PLL.PLLQ = 3;
RCC_OscInitStruct.PLL.PLLR = 2;
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1_VCIRANGE_3;
RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
RCC_OscInitStruct.PLL.PLLFRACN = 0;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}

RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
| RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2
| RCC_CLOCKTYPE_PCLK3;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB3CLKDivider = RCC_HCLK_DIV1;

if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
Error_Handler();
}

__HAL_FLASH_SET_PROGRAM_DELAY(FLASH_PROGRAMMING_DELAY_2);
}

static void MX_I2S1_Init(void)
{
hi2s1.Instance = SPI1;
hi2s1.Init.Mode = I2S_MODE_SLAVE_RX;
hi2s1.Init.Standard = I2S_STANDARD_PHILIPS;
hi2s1.Init.DataFormat = I2S_DATAFORMAT_24B;
hi2s1.Init.MCLKOutput = I2S_MCLKOUTPUT_DISABLE;
hi2s1.Init.AudioFreq = I2S_AUDIOFREQ_32K;
hi2s1.Init.CPOL = I2S_CPOL_LOW;
hi2s1.Init.FirstBit = I2S_FIRSTBIT_MSB;
hi2s1.Init.WSInversion = I2S_WS_INVERSION_DISABLE;
hi2s1.Init.Data24BitAlignment = I2S_DATA_24BIT_ALIGNMENT_RIGHT;
hi2s1.Init.MasterKeepIOState = I2S_MASTER_KEEP_IO_STATE_DISABLE;
if (HAL_I2S_Init(&hi2s1) != HAL_OK)
{
Error_Handler();
}
}

static void MX_GPIO_Init(void)
{
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
}

void Error_Handler(void)
{
__disable_irq();
while (1)
{
}
}

Relevant code in stm32h5xx_hal_i2s.c (excerpt):

HAL_StatusTypeDef HAL_I2S_Init(I2S_HandleTypeDef *hi2s)
{
uint32_t i2sdiv;
uint32_t i2sodd;
uint32_t packetlength;
uint32_t tmp;
uint32_t i2sclk;
uint32_t ispcm;

/* Check the I2S handle allocation */
if (hi2s == NULL)
{
return HAL_ERROR;
}

/* Check the I2S parameters */
assert_param(IS_I2S_ALL_INSTANCE(hi2s->Instance));
assert_param(IS_I2S_MODE(hi2s->Init.Mode));
assert_param(IS_I2S_STANDARD(hi2s->Init.Standard));
assert_param(IS_I2S_DATA_FORMAT(hi2s->Init.DataFormat));
assert_param(IS_I2S_MCLK_OUTPUT(hi2s->Init.MCLKOutput));
assert_param(IS_I2S_AUDIO_FREQ(hi2s->Init.AudioFreq));
assert_param(IS_I2S_CPOL(hi2s->Init.CPOL));
assert_param(IS_I2S_FIRST_BIT(hi2s->Init.FirstBit));
assert_param(IS_I2S_WS_INVERSION(hi2s->Init.WSInversion));
assert_param(IS_I2S_DATA_24BIT_ALIGNMENT(hi2s->Init.Data24BitAlignment));
assert_param(IS_I2S_MASTER_KEEP_IO_STATE(hi2s->Init.MasterKeepIOState));

if (hi2s->State == HAL_I2S_STATE_RESET)
{
/* Allocate lock resource and initialize it */
hi2s->Lock = HAL_UNLOCKED;

#if (USE_HAL_I2S_REGISTER_CALLBACKS == 1UL)
/* Init the I2S Callback settings */
hi2s->TxCpltCallback = HAL_I2S_TxCpltCallback;
hi2s->RxCpltCallback = HAL_I2S_RxCpltCallback;
hi2s->TxRxCpltCallback = HAL_I2SEx_TxRxCpltCallback;
hi2s->TxHalfCpltCallback = HAL_I2S_TxHalfCpltCallback;
hi2s->RxHalfCpltCallback = HAL_I2S_RxHalfCpltCallback;
hi2s->TxRxHalfCpltCallback = HAL_I2SEx_TxRxHalfCpltCallback;
hi2s->ErrorCallback = HAL_I2S_ErrorCallback;

if (hi2s->MspInitCallback == NULL)
{
hi2s->MspInitCallback = HAL_I2S_MspInit;
}

/* Init the low level hardware: GPIO, CLOCK, NVIC... */
hi2s->MspInitCallback(hi2s);
#else
/* Init the low level hardware: GPIO, CLOCK, CORTEX...etc */
HAL_I2S_MspInit(hi2s);
#endif /* USE_HAL_I2S_REGISTER_CALLBACKS */
}

hi2s->State = HAL_I2S_STATE_BUSY;

/* Disable the selected I2S peripheral */
if ((hi2s->Instance->CR1 & SPI_CR1_SPE) == SPI_CR1_SPE)
{
/* Disable I2S peripheral */
__HAL_I2S_DISABLE(hi2s);
}

/* Clear I2S configuration register */
CLEAR_REG(hi2s->Instance->I2SCFGR);

if (IS_I2S_MASTER(hi2s->Init.Mode))
{
/* Prescaler calculation for master mode (not applicable here, included for completeness) */
/* ... */
}

/* Configure I2SMOD, I2SCFG, I2SSTD, PCMSYNC, DATLEN, CHLEN, CKPOL, WSINV, DATAFMT, I2SDIV, ODD and MCKOE bits */
MODIFY_REG(hi2s->Instance->I2SCFGR, (SPI_I2SCFGR_I2SMOD | SPI_I2SCFGR_I2SCFG | \
SPI_I2SCFGR_I2SSTD | SPI_I2SCFGR_PCMSYNC | \
SPI_I2SCFGR_DATLEN | SPI_I2SCFGR_CHLEN | \
SPI_I2SCFGR_CKPOL | SPI_I2SCFGR_WSINV | \
SPI_I2SCFGR_DATFMT | SPI_I2SCFGR_MCKOE),
(SPI_I2SCFGR_I2SMOD | hi2s->Init.Mode | \
hi2s->Init.Standard | hi2s->Init.DataFormat | \
hi2s->Init.CPOL | hi2s->Init.WSInversion | \
hi2s->Init.Data24BitAlignment | hi2s->Init.MCLKOutput));

/* Clear status register */
WRITE_REG(hi2s->Instance->IFCR, 0x0FF8);

/* Configure CFG2 register */
CLEAR_BIT(hi2s->Instance->CR1, SPI_CR1_IOLOCK);
MODIFY_REG(hi2s->Instance->CFG2, SPI_CFG2_LSBFRST, hi2s->Init.FirstBit);

/* Ensure AFCNTR is managed only by Master */
if (IS_I2S_MASTER(hi2s->Init.Mode))
{
MODIFY_REG(hi2s->Instance->CFG2, SPI_CFG2_AFCNTR, (hi2s->Init.MasterKeepIOState));
}

hi2s->ErrorCode = HAL_I2S_ERROR_NONE;
hi2s->State = HAL_I2S_STATE_READY;

return HAL_OK;
}

Code in stm32h5xx_hal_msp.c:

void HAL_I2S_MspInit(I2S_HandleTypeDef* hi2s)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
if (hi2s->Instance == SPI1)
{
/* Initialize the peripheral clock */
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SPI1;
PeriphClkInitStruct.PLL3.PLL3Source = RCC_PLL3_SOURCE_HSE;
PeriphClkInitStruct.PLL3.PLL3M = 8;
PeriphClkInitStruct.PLL3.PLL3N = 512;
PeriphClkInitStruct.PLL3.PLL3P = 18;
PeriphClkInitStruct.PLL3.PLL3Q = 2;
PeriphClkInitStruct.PLL3.PLL3R = 2;
PeriphClkInitStruct.PLL3.PLL3RGE = RCC_PLL3_VCIRANGE_3;
PeriphClkInitStruct.PLL3.PLL3VCOSEL = RCC_PLL3VCOWIDE;
PeriphClkInitStruct.PLL3.PLL3FRACN = 0;
PeriphClkInitStruct.PLL3.PLL3ClockOut = RCC_PLL3_DIVP;
PeriphClkInitStruct.Spi1ClockSelection = RCC_SPI1CLKSOURCE_PLL3P;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}

/* Peripheral clock enable */
__HAL_RCC_SPI1_CLK_ENABLE();

__HAL_RCC_GPIOA_CLK_ENABLE();
/**I2S1 GPIO Configuration
PA4 ------> I2S1_WS
PA5 ------> I2S1_CK
PA6 ------> I2S1_SDI
*/
GPIO_InitStruct.Pin = GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
}

void HAL_I2S_MspDeInit(I2S_HandleTypeDef* hi2s)
{
if (hi2s->Instance == SPI1)
{
/* Peripheral clock disable */
__HAL_RCC_SPI1_CLK_DISABLE();

/**I2S1 GPIO Configuration
PA4 ------> I2S1_WS
PA5 ------> I2S1_CK
PA6 ------> I2S1_SDI
*/
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6);
}
}

Additional Notes:

  • The logic analyzer confirms that the PCM1804's I2S signals are correct.
  • The STM32H563 is in slave mode, so it should not require precise clock configuration for I2S1 since the PCM1804 provides the clock signals.
  • The HAL_I2S_Receive function does not return an error (it returns HAL_OK), but the received data in temp_buffer is all zeros.
  • I'm using J-Link with the latest software (V8.78) for debugging, and the MCU is correctly recognized.

Can someone point out what might be causing the STM32H563 to fail to receive the I2S data? Are there issues with my I2S configuration, GPIO setup, or something else? Any help is greatly appreciated!

Bobliang2012_0-1761061708991.png

 

0 REPLIES 0