Skip to main content
Explorer II
July 11, 2025
Question

STM32U595-SAI/DMA with INMP441 Microphone Not Working - No Data Received

  • July 11, 2025
  • 1 reply
  • 397 views

Hello ST Community,

I'm working on a project using STM32U595 with INMP441 MEMS microphone and NS4168 audio DAC. The system is configured to capture audio data from the microphone using SAI1_Block_A in DMA mode and then output it to the speaker using SAI1_Block_B.

Issue:
I've implemented the SAI RX half-complete and complete callbacks, but they are never triggered. I've added printf statements to display the received data, but nothing is being printed. The DAC seems to be initialized correctly (NS4168_INIT() returns without error), but no audio data is being processed. Code:

/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * File Name : SAI.c
 * Description : This file provides code for the configuration
 * of the SAI instances.
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2025 STMicroelectronics.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "sai.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

SAI_HandleTypeDef hsai_BlockA1;
SAI_HandleTypeDef hsai_BlockB1;
DMA_NodeTypeDef Node_GPDMA1_Channel1;
DMA_QListTypeDef List_GPDMA1_Channel1;
DMA_HandleTypeDef handle_GPDMA1_Channel1;
DMA_NodeTypeDef Node_GPDMA1_Channel0;
DMA_QListTypeDef List_GPDMA1_Channel0;
DMA_HandleTypeDef handle_GPDMA1_Channel0;

/* SAI1 init function */
void MX_SAI1_Init(void)
{

 /* USER CODE BEGIN SAI1_Init 0 */

 /* USER CODE END SAI1_Init 0 */

 /* USER CODE BEGIN SAI1_Init 1 */
 /* USER CODE END SAI1_Init 1 */
 hsai_BlockA1.Instance = SAI1_Block_A;
 hsai_BlockA1.Init.AudioMode = SAI_MODEMASTER_RX;
 hsai_BlockA1.Init.Synchro = SAI_ASYNCHRONOUS;
 hsai_BlockA1.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE;
 hsai_BlockA1.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE;
 hsai_BlockA1.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF;
 hsai_BlockA1.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_44K;
 hsai_BlockA1.Init.SynchroExt = SAI_SYNCEXT_DISABLE;
 hsai_BlockA1.Init.MonoStereoMode = SAI_MONOMODE;
 hsai_BlockA1.Init.CompandingMode = SAI_NOCOMPANDING;
 hsai_BlockA1.Init.TriState = SAI_OUTPUT_NOTRELEASED;
 if (HAL_SAI_InitProtocol(&hsai_BlockA1, SAI_I2S_MSBJUSTIFIED, SAI_PROTOCOL_DATASIZE_32BIT, 2) != HAL_OK)
 {
 Error_Handler();
 }
 hsai_BlockB1.Instance = SAI1_Block_B;
 hsai_BlockB1.Init.AudioMode = SAI_MODEMASTER_TX;
 hsai_BlockB1.Init.Synchro = SAI_ASYNCHRONOUS;
 hsai_BlockB1.Init.OutputDrive = SAI_OUTPUTDRIVE_ENABLE;
 hsai_BlockB1.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE;
 hsai_BlockB1.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF;
 hsai_BlockB1.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_44K;
 hsai_BlockB1.Init.SynchroExt = SAI_SYNCEXT_DISABLE;
 hsai_BlockB1.Init.MckOutput = SAI_MCK_OUTPUT_DISABLE;
 hsai_BlockB1.Init.MonoStereoMode = SAI_MONOMODE;
 hsai_BlockB1.Init.CompandingMode = SAI_NOCOMPANDING;
 if (HAL_SAI_InitProtocol(&hsai_BlockB1, SAI_I2S_MSBJUSTIFIED, SAI_PROTOCOL_DATASIZE_32BIT, 2) != HAL_OK)
 {
 Error_Handler();
 }
 /* USER CODE BEGIN SAI1_Init 2 */

 /* USER CODE END SAI1_Init 2 */
}
static uint32_t SAI1_client = 0;

void HAL_SAI_MspInit(SAI_HandleTypeDef *saiHandle)
{

 GPIO_InitTypeDef GPIO_InitStruct;
 DMA_NodeConfTypeDef NodeConfig;
 RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
 /* SAI1 */
 if (saiHandle->Instance == SAI1_Block_A)
 {
 /* SAI1 clock enable */
 /** Initializes the peripherals clock
 */
 PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SAI1;
 PeriphClkInit.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLL1;

 if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
 {
 Error_Handler();
 }

 if (SAI1_client == 0)
 {
 __HAL_RCC_SAI1_CLK_ENABLE();

 /* Peripheral interrupt init*/
 HAL_NVIC_SetPriority(SAI1_IRQn, 5, 0);
 HAL_NVIC_EnableIRQ(SAI1_IRQn);
 }
 SAI1_client++;

 /**SAI1_A_Block_A GPIO Configuration
 PC3 ------> SAI1_SD_A
 PA8 ------> SAI1_SCK_A
 PB9 ------> SAI1_FS_A
 */
 GPIO_InitStruct.Pin = GPIO_PIN_3;
 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
 GPIO_InitStruct.Alternate = GPIO_AF13_SAI1;
 HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

 GPIO_InitStruct.Pin = GPIO_PIN_8;
 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
 GPIO_InitStruct.Alternate = GPIO_AF13_SAI1;
 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

 GPIO_InitStruct.Pin = GPIO_PIN_9;
 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
 GPIO_InitStruct.Alternate = GPIO_AF13_SAI1;
 HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

 /* Peripheral DMA init*/

 NodeConfig.NodeType = DMA_GPDMA_LINEAR_NODE;
 NodeConfig.Init.Request = GPDMA1_REQUEST_SAI1_A;
 NodeConfig.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
 NodeConfig.Init.Direction = DMA_PERIPH_TO_MEMORY;
 NodeConfig.Init.SrcInc = DMA_SINC_FIXED;
 NodeConfig.Init.DestInc = DMA_DINC_INCREMENTED;
 NodeConfig.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD;
 NodeConfig.Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD;
 NodeConfig.Init.SrcBurstLength = 1;
 NodeConfig.Init.DestBurstLength = 1;
 NodeConfig.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0 | DMA_DEST_ALLOCATED_PORT0;
 NodeConfig.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
 NodeConfig.Init.Mode = DMA_NORMAL;
 NodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;
 NodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;
 NodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;
 if (HAL_DMAEx_List_BuildNode(&NodeConfig, &Node_GPDMA1_Channel0) != HAL_OK)
 {
 Error_Handler();
 }

 if (HAL_DMAEx_List_InsertNode(&List_GPDMA1_Channel0, NULL, &Node_GPDMA1_Channel0) != HAL_OK)
 {
 Error_Handler();
 }

 if (HAL_DMAEx_List_SetCircularMode(&List_GPDMA1_Channel0) != HAL_OK)
 {
 Error_Handler();
 }

 handle_GPDMA1_Channel0.Instance = GPDMA1_Channel0;
 handle_GPDMA1_Channel0.InitLinkedList.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
 handle_GPDMA1_Channel0.InitLinkedList.LinkStepMode = DMA_LSM_FULL_EXECUTION;
 handle_GPDMA1_Channel0.InitLinkedList.LinkAllocatedPort = DMA_LINK_ALLOCATED_PORT0;
 handle_GPDMA1_Channel0.InitLinkedList.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
 handle_GPDMA1_Channel0.InitLinkedList.LinkedListMode = DMA_LINKEDLIST_CIRCULAR;
 if (HAL_DMAEx_List_Init(&handle_GPDMA1_Channel0) != HAL_OK)
 {
 Error_Handler();
 }

 if (HAL_DMAEx_List_LinkQ(&handle_GPDMA1_Channel0, &List_GPDMA1_Channel0) != HAL_OK)
 {
 Error_Handler();
 }

 __HAL_LINKDMA(saiHandle, hdmarx, handle_GPDMA1_Channel0);

 if (HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel0, DMA_CHANNEL_NPRIV) != HAL_OK)
 {
 Error_Handler();
 }
 }
 if (saiHandle->Instance == SAI1_Block_B)
 {
 /* SAI1 clock enable */
 /** Initializes the peripherals clock
 */
 PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SAI1;
 PeriphClkInit.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLL1;

 if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
 {
 Error_Handler();
 }
 if (SAI1_client == 0)
 {
 __HAL_RCC_SAI1_CLK_ENABLE();

 /* Peripheral interrupt init*/
 HAL_NVIC_SetPriority(SAI1_IRQn, 5, 0);
 HAL_NVIC_EnableIRQ(SAI1_IRQn);
 }
 SAI1_client++;

 /**SAI1_B_Block_B GPIO Configuration
 PB3 (JTDO/TRACESWO) ------> SAI1_SCK_B
 PB5 ------> SAI1_SD_B
 PB6 ------> SAI1_FS_B
 */
 GPIO_InitStruct.Pin = GPIO_PIN_3 | GPIO_PIN_5 | 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_AF13_SAI1;
 HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

 /* Peripheral DMA init*/

 NodeConfig.NodeType = DMA_GPDMA_LINEAR_NODE;
 NodeConfig.Init.Request = GPDMA1_REQUEST_SAI1_B;
 NodeConfig.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
 NodeConfig.Init.Direction = DMA_MEMORY_TO_PERIPH;
 NodeConfig.Init.SrcInc = DMA_SINC_INCREMENTED;
 NodeConfig.Init.DestInc = DMA_DINC_FIXED;
 NodeConfig.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD;
 NodeConfig.Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD;
 NodeConfig.Init.SrcBurstLength = 1;
 NodeConfig.Init.DestBurstLength = 1;
 NodeConfig.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0 | DMA_DEST_ALLOCATED_PORT0;
 NodeConfig.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
 NodeConfig.Init.Mode = DMA_NORMAL;
 NodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;
 NodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;
 NodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;
 if (HAL_DMAEx_List_BuildNode(&NodeConfig, &Node_GPDMA1_Channel1) != HAL_OK)
 {
 Error_Handler();
 }

 if (HAL_DMAEx_List_InsertNode(&List_GPDMA1_Channel1, NULL, &Node_GPDMA1_Channel1) != HAL_OK)
 {
 Error_Handler();
 }

 if (HAL_DMAEx_List_SetCircularMode(&List_GPDMA1_Channel1) != HAL_OK)
 {
 Error_Handler();
 }

 handle_GPDMA1_Channel1.Instance = GPDMA1_Channel1;
 handle_GPDMA1_Channel1.InitLinkedList.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
 handle_GPDMA1_Channel1.InitLinkedList.LinkStepMode = DMA_LSM_FULL_EXECUTION;
 handle_GPDMA1_Channel1.InitLinkedList.LinkAllocatedPort = DMA_LINK_ALLOCATED_PORT0;
 handle_GPDMA1_Channel1.InitLinkedList.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
 handle_GPDMA1_Channel1.InitLinkedList.LinkedListMode = DMA_LINKEDLIST_CIRCULAR;
 if (HAL_DMAEx_List_Init(&handle_GPDMA1_Channel1) != HAL_OK)
 {
 Error_Handler();
 }

 if (HAL_DMAEx_List_LinkQ(&handle_GPDMA1_Channel1, &List_GPDMA1_Channel1) != HAL_OK)
 {
 Error_Handler();
 }

 __HAL_LINKDMA(saiHandle, hdmatx, handle_GPDMA1_Channel1);

 if (HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel1, DMA_CHANNEL_NPRIV) != HAL_OK)
 {
 Error_Handler();
 }
 }
}

void HAL_SAI_MspDeInit(SAI_HandleTypeDef *saiHandle)
{
 /* SAI1 */
 if (saiHandle->Instance == SAI1_Block_A)
 {
 SAI1_client--;
 if (SAI1_client == 0)
 {
 /* Peripheral clock disable */
 __HAL_RCC_SAI1_CLK_DISABLE();
 HAL_NVIC_DisableIRQ(SAI1_IRQn);
 }

 /**SAI1_A_Block_A GPIO Configuration
 PC3 ------> SAI1_SD_A
 PA8 ------> SAI1_SCK_A
 PB9 ------> SAI1_FS_A
 */
 HAL_GPIO_DeInit(GPIOC, GPIO_PIN_3);

 HAL_GPIO_DeInit(GPIOA, GPIO_PIN_8);

 HAL_GPIO_DeInit(GPIOB, GPIO_PIN_9);

 HAL_DMA_DeInit(saiHandle->hdmarx);
 }
 if (saiHandle->Instance == SAI1_Block_B)
 {
 SAI1_client--;
 if (SAI1_client == 0)
 {
 /* Peripheral clock disable */
 __HAL_RCC_SAI1_CLK_DISABLE();
 HAL_NVIC_DisableIRQ(SAI1_IRQn);
 }

 /**SAI1_B_Block_B GPIO Configuration
 PB3 (JTDO/TRACESWO) ------> SAI1_SCK_B
 PB5 ------> SAI1_SD_B
 PB6 ------> SAI1_FS_B
 */
 HAL_GPIO_DeInit(GPIOB, GPIO_PIN_3 | GPIO_PIN_5 | GPIO_PIN_6);

 HAL_DMA_DeInit(saiHandle->hdmatx);
 }
}

/**
 * @}
 */

/**
 * @}
 */
#include "sai.h"
#include "INMP441.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#include "../BSP/NS4168/NS4168.h"

#define AUDIO_BUFFER_FRAME 128
#define AUDIO_BUFFER_CHANEL 2
#define AUDIO_BUFFER_SIZE (AUDIO_BUFFER_FRAME * AUDIO_BUFFER_CHANEL)

int32_t AUDIO_BUFFER[AUDIO_BUFFER_SIZE];

/**
 * @brief 初始化INMP441麦克风
 * @retval HAL状态
 */
HAL_StatusTypeDef INMP441_Init(void)
{
 NS4168_INIT();
 // 清空缓冲区
 memset(AUDIO_BUFFER, 0, sizeof(AUDIO_BUFFER));

 return HAL_OK;
}

/**
 * @brief 开始音频采集
 * @retval HAL状态
 */
HAL_StatusTypeDef INMP441_Start(void)
{
 HAL_StatusTypeDef status;

 memset(AUDIO_BUFFER, 0, sizeof(AUDIO_BUFFER));
 // 启动DMA接收
 status = HAL_SAI_Receive_DMA(&hsai_BlockA1, (uint32_t *)&AUDIO_BUFFER, sizeof(AUDIO_BUFFER));
 // 启动DMA发送
 status = HAL_SAI_Transmit_DMA(&hsai_BlockB1, (uint32_t *)&AUDIO_BUFFER, sizeof(AUDIO_BUFFER));
 return status;
}

/**
 * @brief 停止音频采集
 * @retval HAL状态
 */
HAL_StatusTypeDef INMP441_Stop(void)
{
 // printf("INMP441: Stopping SAI DMA\r\n");
 return HAL_SAI_DMAStop(&hsai_BlockA1);
}

/**
 * @brief SAI半传输完成回调
 * @PAram hsai SAI句柄
 * @retval 无
 */
void HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef *hsai)
{
 if (hsai->Instance == SAI1_Block_A)
 {
 printf("INMP441 RxHalf Data: ");
 for (int i = 0; i < 5; i++)
 {
 printf("%d ", AUDIO_BUFFER[i]);
 }
 }
}

/**
 * @brief SAI传输完成回调
 * @PAram hsai SAI句柄
 * @retval 无
 */
void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai)
{
 if (hsai->Instance == SAI1_Block_A)
 {
 }
}

/**
 * @brief SAI错误回调
 * @PAram hsai SAI句柄
 * @retval 无
 */
void HAL_SAI_ErrorCallback(SAI_HandleTypeDef *hsai)
{
 if (hsai->Instance == SAI1_Block_A)
 {
 uint32_t error_code = hsai->ErrorCode;
 printf("INMP441 SAI Error: 0x%lX\r\n", error_code);
 }
}

 

    This topic has been closed for replies.

    1 reply

    Technical Moderator
    July 11, 2025

    Plese refer to the BSP example below which use SAI with DMA for audio recording and audio playback.

    STM32CubeU5/Projects/STM32U575I-EV/Examples/BSP at main · STMicroelectronics/STM32CubeU5 · GitHub