cancel
Showing results for 
Search instead for 
Did you mean: 

Problem with enabling onboard MEMS microphone using SAI interface on STM32H735IG discovery board

PZare.1
Associate II
/* SAI configured in Mode: Pulse Width Modulation using MicroPhones pairs (1-2) and CK2 as clock */
static void MX_SAI4_Init(void)
{
  hsai_BlockA4.Instance = SAI4_Block_A;
  hsai_BlockA4.Init.Protocol = SAI_FREE_PROTOCOL;
  hsai_BlockA4.Init.AudioMode = SAI_MODEMASTER_RX;
  hsai_BlockA4.Init.DataSize = SAI_DATASIZE_8;
  hsai_BlockA4.Init.FirstBit = SAI_FIRSTBIT_MSB;
  hsai_BlockA4.Init.ClockStrobing = SAI_CLOCKSTROBING_FALLINGEDGE;
  hsai_BlockA4.Init.Synchro = SAI_ASYNCHRONOUS;
  hsai_BlockA4.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE;
  hsai_BlockA4.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE;
  hsai_BlockA4.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_EMPTY;
  hsai_BlockA4.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_16K;
  hsai_BlockA4.Init.MonoStereoMode = SAI_STEREOMODE;
  hsai_BlockA4.Init.CompandingMode = SAI_NOCOMPANDING;
  hsai_BlockA4.Init.PdmInit.Activation = ENABLE;
  hsai_BlockA4.Init.PdmInit.MicPairsNbr = 1;
  hsai_BlockA4.Init.PdmInit.ClockEnable = SAI_PDM_CLOCK2_ENABLE;
  hsai_BlockA4.FrameInit.FrameLength = 8;
  hsai_BlockA4.FrameInit.ActiveFrameLength = 1;
  hsai_BlockA4.FrameInit.FSDefinition = SAI_FS_STARTFRAME;
  hsai_BlockA4.FrameInit.FSPolarity = SAI_FS_ACTIVE_HIGH;
  hsai_BlockA4.FrameInit.FSOffset = SAI_FS_FIRSTBIT;
  hsai_BlockA4.SlotInit.FirstBitOffset = 0;
  hsai_BlockA4.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE;
  hsai_BlockA4.SlotInit.SlotNumber = 1;
  hsai_BlockA4.SlotInit.SlotActive = 0x00000001;
  if (HAL_SAI_Init(&hsai_BlockA4) != HAL_OK)
  {
    Error_Handler();
  }
}
void HAL_SAI_MspInit(SAI_HandleTypeDef* hsai)
{
  GPIO_InitTypeDef GPIO_InitStruct;
  RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
/* SAI4 */
    if(hsai->Instance==SAI4_Block_A)
    {
    /* Peripheral clock enable */
  /** Initializes the peripherals clock
  */
    PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SAI4A;
    PeriphClkInitStruct.PLL2.PLL2M = 4;
    PeriphClkInitStruct.PLL2.PLL2N = 12;
    PeriphClkInitStruct.PLL2.PLL2P = 3;
    PeriphClkInitStruct.PLL2.PLL2Q = 2;
    PeriphClkInitStruct.PLL2.PLL2R = 2;
    PeriphClkInitStruct.PLL2.PLL2RGE = RCC_PLL2VCIRANGE_3;
    PeriphClkInitStruct.PLL2.PLL2VCOSEL = RCC_PLL2VCOWIDE;
    PeriphClkInitStruct.PLL2.PLL2FRACN = 0.0;
    PeriphClkInitStruct.Sai4AClockSelection = RCC_SAI4ACLKSOURCE_PLL2;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
    {
      Error_Handler();
    }
    if (SAI4_client == 0)
    {
       __HAL_RCC_SAI4_CLK_ENABLE();
    /* Peripheral interrupt init*/
    HAL_NVIC_SetPriority(SAI4_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(SAI4_IRQn);
    }
    SAI4_client ++;
    /**SAI4_A_Block_A GPIO Configuration
    PE5     ------> SAI4_CK2
    PD6     ------> SAI4_D1
    */
    GPIO_InitStruct.Pin = GPIO_PIN_5;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF10_SAI4;
    HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
    GPIO_InitStruct.Pin = GPIO_PIN_6;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF1_SAI4;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
    }
}

With that configuration I am receiving interrupts that are handled in ISR:

void SAI4_IRQHandler(void)
{
  HAL_SAI_IRQHandler(&hsai_BlockA4);
}

That I am confirming in main loop:

#define BUFF_SIZE 4092
uint8_t buffer[BUFF_SIZE];
 
volatile int i = 0;
volatile int it_error = 0;  // not used in this example
volatile int it_read = 0;
volatile int old_it_read = 0;
 
void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai_BlockA4)
{
  it_read++;
}
 
void HAL_SAI_ErrorCallback(SAI_HandleTypeDef *hsai_BlockA4)
{
  it_error = 1;
}
 
SAI_HandleTypeDef hsai_BlockA4;
 
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SAI4_Init(void);
 
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_SAI4_Init();
 
  HAL_StatusTypeDef ret;
  ret = HAL_SAI_Receive_IT(&hsai_BlockA4, (uint8_t *)buffer, (uint16_t)BUFF_SIZE);
 
  while (1)
  {
    i++;
    /* check if `it_read` changed - if yes, buffer is complete */
    if (old_it_read != it_read)
    {
      old_it_read = it_read;
      /* start again */
      HAL_SAI_Receive_IT(&hsai_BlockA4, (uint8_t *)buffer, (uint16_t)BUFF_SIZE);
    }
  }
}

But every buffer is filled with "255" values.

I was assuming that I will receive buffer of PDM values. Can you show me where I can find solution for my problem or how I can solve it?

I tried to follow multiple examples (from BSP, SAI and others) as well tried to use Interfacing PDM microphones application note (AN5027) but with no success.

Any help would be appreciated,

Pawel

6 REPLIES 6
Eleon BORLINI
ST Employee

Hi @PZare.1​ Pawel,

I checked internally with our experts, and they suggest to check the settings of the pins: the mic is connected to PE4/PE5, while you are configuring the PD6/PE5.

0693W00000AMGE3QAP.pngBefore checking in more details your configuration, please see what happens changing the two pins, and let me know.

-Eleon

PZare.1
Associate II

Hi Eleon,

thanks for checking! I did the changes as you suggest:

[...]
    GPIO_InitStruct.Pin = GPIO_PIN_5;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF10_SAI4;
    HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
 
    GPIO_InitStruct.Pin = GPIO_PIN_4;  // changed for pin 4
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF1_SAI4;  // not changed AF1 alternate pin
    HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);  // changed for port E
[...]

Only change that I noticed is that right now my buffer is filled with "0x00" values instead of "0xFF" values.

Pawel

Edit:

Changed alternate pin to GPIO_AF10_SAI4 as well, same results.

Hi @PZare.1​ ,

do you have the possibility to check the PDM data (and then the PCM stream) with a scope?

-Eleon

Hello Eleon,

I checked signal on PE5 pin (SB40 on your board schematic) - clock is clocking with 133kHz frequency, on pin PE4 (SB39) there is always 0 V.

Pawel

Hi @PZare.1​ ,

did you already check this presentation on the SAI interface for the STM32H7?

At least to check if there is a macro issue in the interface settings and configurations.

-Eleon

RBamf.1
Associate III

Hi, the Size argument of "HAL_SAI_Receive_IT(&hsai_BlockA4, (uint8_t *)buffer, (uint16_t)BUFF_SIZE);" is not the number of bytes. It represents the number of transfers. It's very difficult, you must configure the FrameInit and SlotInit specifically for your microphone. Here is my configuration:

	saiHandle.Instance = SAI1_Block_A; // audio block A.
	saiHandle.Init.Protocol = SAI_FREE_PROTOCOL;
	saiHandle.Init.FirstBit = SAI_FIRSTBIT_MSB;
	saiHandle.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_16K;
	saiHandle.Init.AudioMode = SAI_MODEMASTER_RX; // block a must provide clock signals and receive from the data line.
	saiHandle.Init.Synchro = SAI_ASYNCHRONOUS;	// we only want to use this one audio block.
	saiHandle.Init.SynchroExt = SAI_SYNCEXT_DISABLE; // disable sychronizing the 2 audio blocks.
	saiHandle.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE; // assume to power the data?
	saiHandle.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE; // any frame length allowed.
	saiHandle.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_EMPTY;	// used for interrupts.
	saiHandle.Init.MonoStereoMode = SAI_STEREOMODE; // mono mode only available in transmission mode.
	saiHandle.Init.CompandingMode = SAI_NOCOMPANDING; // telecommunications specification (not needed)
	saiHandle.Init.TriState = SAI_OUTPUT_NOTRELEASED; // assume the SAI is ma
	saiHandle.FrameInit.FrameLength = 64; // 64 bit frame. (2 slots)
	saiHandle.FrameInit.ActiveFrameLength = 32; // Frame synchronization active level length. (half the frame length)
	saiHandle.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION;
	saiHandle.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW;
	saiHandle.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT;
	saiHandle.SlotInit.FirstBitOffset = 0; // no offset in receive mode -> FBOFF <= (SLOTSZ - DS)
	saiHandle.SlotInit.SlotSize = SAI_SLOTSIZE_32B; // 32 bits per slot to contain the 32 data bits (24 data, 8 zeroed)
	saiHandle.SlotInit.SlotNumber = 2;
	saiHandle.SlotInit.SlotActive = SAI_SLOTACTIVE_ALL;

Then to read a 24 bit value from a 32 bit frame.etc:

HAL_SAI_Receive_IT(saiHandle, m_SAIDataBuffer, 2U);

You will need to research this section of the reference manual.

Chapter 41, pages 1339-1389 of the "RM0394 Reference manual STM32L41xxx/42xxx/43xxx/44xxx/45xxx/46xxx advanced Arm®-based 32-bit MCUs" document.