cancel
Showing results for 
Search instead for 
Did you mean: 

Unable to activate SAI on stm32h7s78-dk

esxu
Associate II

Hello,

I am writing this because I am unable to enable the SAI on this development board. The strange thing is that I actually managed to enable it before and it was working correctly. However, while implementing another feature, I switched branches and worked on a different GitHub branch for some time. When I came back, I noticed that the SAI was no longer starting.

At first, I thought I had made a mistake in a commit, so I created a completely new project where the only goal was to start the SAI. Even though I believe all the steps are configured correctly, the MCK clock never starts, and the MCKEN register bit never becomes enabled. I am attaching screenshots of the SAI registers below.

esxu_0-1778498835653.png

 

As shown in the screenshot, the SAI is enabled, but I cannot see any clock output on the oscilloscope. As I mentioned before, what confuses me the most is that two weeks ago, using the exact same development board, I was able to make it work correctly.

I tried adding the following line inside the MX_SAI2_Init function 

  hsai_BlockB2.Init.MckOutput              = SAI_MCK_OUTPUT_ENABLE;

After doing this, the MCKEN bit appeared as 0x01, but the SAI still did not start.

I also created a small test program to verify that all the pins used by the SAI are working correctly. In this test, I toggle the pins at a very high speed, and all of them behave as expected on the oscilloscope. Because of this, I would rule out a hardware issue as the cause of the problem.

I am using the CN14 and CN15 headers of the development board.

When probing the pins with the oscilloscope, I observe the following:

  • D13 remains at 0V
  • D12 remains at 3.3V
  • D11 remains at 0V

Additionally, I have completely disabled the cache in order to rule it out as a possible source of the issue.

The first time I configured the SAI, I used the following post as a reference:

STM32H7RS GPDMA Circular w/ Linked List issue

I am also including the code from the main, sai, linked_list, and gpdma files in case someone can spot where my mistake is. I will also upload a ZIP file containing the complete project.

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2026 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 "main.h"
#include "gpdma.h"
#include "sai.h"
#include "usb_otg.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
#include <stdint.h>
#include <string.h>
#include "linked_list.h"
extern DMA_QListTypeDef SAI_DMA_queue;
int32_t buf[100]  __attribute__ ((aligned(32)));

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Update SystemCoreClock variable according to RCC registers values. */
  SystemCoreClockUpdate();

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_GPDMA1_Init();
  MX_USB_OTG_HS_PCD_Init();
  MX_SAI2_Init();
  /* USER CODE BEGIN 2 */
  memset(&SAI_DMA_queue, 0, sizeof(SAI_DMA_queue));

  MX_SAI_DMA_queue_Config();

   // D: check for correct linkage, it was fine
   if (HAL_DMAEx_List_LinkQ(&handle_GPDMA1_Channel0, &SAI_DMA_queue) != HAL_OK)
   {
	   Error_Handler();
   }

   // D: attempt to link the DMA handle, and be seen as linked list
   // D: now below the linkq, to associate SAI with handle that has gotten parameters
   __HAL_LINKDMA(&hsai_BlockB2, hdmarx, handle_GPDMA1_Channel0);

  // D: does all necessary calls, 256 is half-word samples
  if (HAL_SAI_Receive_DMA(&hsai_BlockB2, (uint8_t*) buf, 100) != HAL_OK)
  {
	  Error_Handler();
  }

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * File Name          : SAI.c
  * Description        : This file provides code for the configuration
  *                      of the SAI instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2026 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_BlockB2;

/* SAI2 init function */
void MX_SAI2_Init(void)
{

  /* USER CODE BEGIN SAI2_Init 0 */

  /* USER CODE END SAI2_Init 0 */

  /* USER CODE BEGIN SAI2_Init 1 */

  /* USER CODE END SAI2_Init 1 */

  hsai_BlockB2.Instance = SAI2_Block_B;
  hsai_BlockB2.Init.AudioMode = SAI_MODEMASTER_RX;
  hsai_BlockB2.Init.Synchro = SAI_ASYNCHRONOUS;
  hsai_BlockB2.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE;
  hsai_BlockB2.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE;
  hsai_BlockB2.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_EMPTY;
  hsai_BlockB2.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_48K;
  hsai_BlockB2.Init.SynchroExt = SAI_SYNCEXT_DISABLE;
  hsai_BlockB2.Init.MonoStereoMode = SAI_STEREOMODE;
  hsai_BlockB2.Init.CompandingMode = SAI_NOCOMPANDING;
  if (HAL_SAI_InitProtocol(&hsai_BlockB2, SAI_I2S_STANDARD, SAI_PROTOCOL_DATASIZE_24BIT, 2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SAI2_Init 2 */

  /* USER CODE END SAI2_Init 2 */

}
static uint32_t SAI2_client =0;

void HAL_SAI_MspInit(SAI_HandleTypeDef* saiHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct;
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/* SAI2 */
    if(saiHandle->Instance==SAI2_Block_B)
    {
      /* SAI2 clock enable */

  /** Initializes the peripherals clock
  */
    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SAI2;
    PeriphClkInit.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLL3P;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
    {
      Error_Handler();
    }

      if (SAI2_client == 0)
      {
       __HAL_RCC_SAI2_CLK_ENABLE();

      /* Peripheral interrupt init*/
      HAL_NVIC_SetPriority(SAI2_B_IRQn, 0, 0);
      HAL_NVIC_EnableIRQ(SAI2_B_IRQn);
      }
    SAI2_client ++;

    /**SAI2_B_Block_B GPIO Configuration
    PE14     ------> SAI2_MCLK_B
    PE13     ------> SAI2_FS_B
    PE11     ------> SAI2_SD_B
    PE12     ------> SAI2_SCK_B
    */
    GPIO_InitStruct.Pin = GPIO_PIN_14|GPIO_PIN_13|GPIO_PIN_11|GPIO_PIN_12;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF10_SAI2;
    HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);

    }
}

void HAL_SAI_MspDeInit(SAI_HandleTypeDef* saiHandle)
{

/* SAI2 */
    if(saiHandle->Instance==SAI2_Block_B)
    {
    SAI2_client --;
      if (SAI2_client == 0)
      {
      /* Peripheral clock disable */
      __HAL_RCC_SAI2_CLK_DISABLE();
      HAL_NVIC_DisableIRQ(SAI2_B_IRQn);
      }

    /**SAI2_B_Block_B GPIO Configuration
    PE14     ------> SAI2_MCLK_B
    PE13     ------> SAI2_FS_B
    PE11     ------> SAI2_SD_B
    PE12     ------> SAI2_SCK_B
    */
    HAL_GPIO_DeInit(GPIOE, GPIO_PIN_14|GPIO_PIN_13|GPIO_PIN_11|GPIO_PIN_12);

    }
}

/**
  * @}
  */

/**
  * @}
  */
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * File Name          : linked_list.c
  * Description        : This file provides code for the configuration
  *                      of the LinkedList.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2026 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 "linked_list.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

DMA_NodeTypeDef SAI_DMA_Node __attribute__((section("noncacheable_buffer")));
DMA_QListTypeDef SAI_DMA_queue;

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/**
  * @brief  DMA Linked-list SAI_DMA_queue configuration
  * @PAram  None
  * @retval None
  */
HAL_StatusTypeDef MX_SAI_DMA_queue_Config(void)
{
  HAL_StatusTypeDef ret = HAL_OK;
  /* DMA node configuration declaration */
  DMA_NodeConfTypeDef pNodeConfig;

  /* Set node configuration ################################################*/
  pNodeConfig.NodeType = DMA_GPDMA_LINEAR_NODE;
  pNodeConfig.Init.Request = GPDMA1_REQUEST_SAI2_B;
  pNodeConfig.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
  pNodeConfig.Init.Direction = DMA_PERIPH_TO_MEMORY;
  pNodeConfig.Init.SrcInc = DMA_SINC_FIXED;
  pNodeConfig.Init.DestInc = DMA_DINC_INCREMENTED;
  pNodeConfig.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD;
  pNodeConfig.Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD;
  pNodeConfig.Init.SrcBurstLength = 1;
  pNodeConfig.Init.DestBurstLength = 1;
  pNodeConfig.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0;
  pNodeConfig.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
  pNodeConfig.Init.Mode = DMA_NORMAL;
  pNodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;
  pNodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;
  pNodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;
  pNodeConfig.SrcAddress = 0;
  pNodeConfig.DstAddress = 0;
  pNodeConfig.DataSize = 0;

  /* Build SAI_DMA_Node Node */
  ret |= HAL_DMAEx_List_BuildNode(&pNodeConfig, &SAI_DMA_Node);

  /* Insert SAI_DMA_Node to Queue */
  ret |= HAL_DMAEx_List_InsertNode_Tail(&SAI_DMA_queue, &SAI_DMA_Node);

  ret |= HAL_DMAEx_List_SetCircularMode(&SAI_DMA_queue);

   return ret;
}
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    gpdma.c
  * @brief   This file provides code for the configuration
  *          of the GPDMA instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2026 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 "gpdma.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

DMA_HandleTypeDef handle_GPDMA1_Channel0;

/* GPDMA1 init function */
void MX_GPDMA1_Init(void)
{

  /* USER CODE BEGIN GPDMA1_Init 0 */

  /* USER CODE END GPDMA1_Init 0 */

  /* Peripheral clock enable */
  __HAL_RCC_GPDMA1_CLK_ENABLE();

  /* GPDMA1 interrupt Init */
    HAL_NVIC_SetPriority(GPDMA1_Channel0_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(GPDMA1_Channel0_IRQn);

  /* USER CODE BEGIN GPDMA1_Init 1 */

  /* USER CODE END GPDMA1_Init 1 */
  handle_GPDMA1_Channel0.Instance = GPDMA1_Channel0;
  handle_GPDMA1_Channel0.InitLinkedList.Priority = DMA_HIGH_PRIORITY;
  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_LAST_LL_ITEM_TRANSFER;
  handle_GPDMA1_Channel0.InitLinkedList.LinkedListMode = DMA_LINKEDLIST_CIRCULAR;
  if (HAL_DMAEx_List_Init(&handle_GPDMA1_Channel0) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel0, DMA_CHANNEL_NPRIV) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN GPDMA1_Init 2 */

  /* USER CODE END GPDMA1_Init 2 */

}

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

 

3 REPLIES 3
esxu
Associate II

I forgot to upload the project ZIP file.

Also, I wanted to ask a question. Is it possible to damage the SAI peripheral while the pins still continue working as GPIOs? Because the last time I worked with SAI, when I wrote __HAL_SAI_ENABLE();, the peripheral started despite having a bad configuration.

 

 
esxu
Associate II

One last comment I would like to add: if someone could try to run my code and let me know whether it works or not, it would help me a lot, since it would tell me whether the issue is related to software or hardware.

Saket_Om
ST Employee

Hello @esxu 


@esxu wrote:

I am using the CN14 and CN15 headers of the development board.

When probing the pins with the oscilloscope, I observe the following:

  • D13 remains at 0V
  • D12 remains at 3.3V
  • D11 remains at 0V

Pin name D13, D12 and D11 are not related to SAI2. 

Saket_Om_1-1778511344055.png

I tested your code, and the DMA TC and HTC interrupts are triggered correctly. However, the buffer remains empty and contains only zeros.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
Saket_Om