Skip to main content
eeyurdakul
Associate II
December 22, 2019
Solved

STM32H7 I2S DMA using HAL Firmware 1.5 Troubleshoot

  • December 22, 2019
  • 2 replies
  • 2711 views

I try to operate very basic I2S DMA function in STM32H750 chip. This is a very simple function which successfully works on STM32F4 and F7 chips.

I have read the previous comments about I2S problems on H7 chip, and know

there are some problems with I2S in previous releases of HAL library, but with the release of v.1.50. this library was rewritten. 

Right know, polling mode and interrupt mode are successfully working.

For DMA problems on H7, the linker script is re-edited. I2C and SPI DMA functions are working successfully, but I2S function starts without any errors, finishes 1 cycle successfully, then halts. It does not work in neither normal nor circular mode. 

In debug mode, HAL_I2S_TxHalfCpltCallback is called after one cycle, then it halts. No error callbacks are called. Below tryouts were not successful either;

  • placing dma buffer on RAM_D2
  • using cache maintenance functions (SCB_CleanDCache)
  • using I2S2 or I2S3

Solving this problem is very crucial for my project. Project files are attached.Any help or suggestion would be apreciated.

main.c ---->

#include "main.h"
#include "dma.h"
#include "i2c.h"
#include "i2s.h"
#include "tim.h"
#include "gpio.h"
 
#include "audio.h"
#include "CS43L22.h"
 
uint16_t counter = 0;
int16_t dataI2S[2];
 
void SystemClock_Config(void);
 
int main(void) {
 
 HAL_Init();
 SystemClock_Config();
 
 MX_GPIO_Init();
 MX_I2C3_Init();
 MX_I2S1_Init();
 MX_DMA_Init();
 
 HAL_GPIO_WritePin(I2S1_RESET_GPIO_Port, I2S1_RESET_Pin, GPIO_PIN_SET);
 CS43_Init(hi2c3, MODE_I2S);
 CS43_SetVolume(30);
 CS43_Enable_RightLeft(CS43_RIGHT_LEFT);
 CS43_Start();
 
 HAL_I2S_Transmit_DMA(&hi2s1, (uint16_t *)dataI2S, 2);
 
 while (1) {}
}
 
void SystemClock_Config(void) {}
 
void HAL_I2S_TxHalfCpltCallback(I2S_HandleTypeDef *hi2s) {
}
 
void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s) {
	 if (hi2s == &hi2s1) {
		 if (counter < 2205) {
			 dataI2S[0] = kAudioSample[counter] - 32767;
			 dataI2S[1] = kAudioSample[counter] - 32767;
			 counter += 1;
		 } else if (counter < 44100){
			 counter += 1;
		 } else {
			 counter = 0;
		 }
	 }
}
 
void HAL_I2S_ErrorCallback(I2S_HandleTypeDef *hi2s) {
 
}
 
void Error_Handler(void) {}

i2s.c---->

void MX_I2S1_Init(void)
{
 
 hi2s1.Instance = SPI1;
 hi2s1.Init.Mode = I2S_MODE_MASTER_TX;
 hi2s1.Init.Standard = I2S_STANDARD_PHILIPS;
 hi2s1.Init.DataFormat = I2S_DATAFORMAT_16B;
 hi2s1.Init.MCLKOutput = I2S_MCLKOUTPUT_ENABLE;
 hi2s1.Init.AudioFreq = I2S_AUDIOFREQ_44K;
 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();
 }
 
}
 
void HAL_I2S_MspInit(I2S_HandleTypeDef* i2sHandle)
{
 
 GPIO_InitTypeDef GPIO_InitStruct = {0};
 if(i2sHandle->Instance==SPI1)
 {
 /* USER CODE BEGIN SPI1_MspInit 0 */
 
 /* USER CODE END SPI1_MspInit 0 */
 /* I2S1 clock enable */
 __HAL_RCC_SPI1_CLK_ENABLE();
 
 __HAL_RCC_GPIOA_CLK_ENABLE();
 __HAL_RCC_GPIOC_CLK_ENABLE();
 /**I2S1 GPIO Configuration 
 PA4 ------> I2S1_WS
 PA5 ------> I2S1_CK
 PA7 ------> I2S1_SDO
 PC4 ------> I2S1_MCK 
 */
 GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_7;
 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
 GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
 GPIO_InitStruct.Pin = GPIO_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_AF5_SPI1;
 HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
 
 /* I2S1 DMA Init */
 /* SPI1_TX Init */
 hdma_spi1_tx.Instance = DMA1_Stream0;
 hdma_spi1_tx.Init.Request = DMA_REQUEST_SPI1_TX;
 hdma_spi1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
 hdma_spi1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
 hdma_spi1_tx.Init.MemInc = DMA_MINC_ENABLE;
 hdma_spi1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
 hdma_spi1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
 hdma_spi1_tx.Init.Mode = DMA_CIRCULAR;
 hdma_spi1_tx.Init.Priority = DMA_PRIORITY_LOW;
 hdma_spi1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
 if (HAL_DMA_Init(&hdma_spi1_tx) != HAL_OK)
 {
 Error_Handler();
 }
 
 __HAL_LINKDMA(i2sHandle,hdmatx,hdma_spi1_tx);
 
 /* I2S1 interrupt Init */
 HAL_NVIC_SetPriority(SPI1_IRQn, 0, 0);
 HAL_NVIC_EnableIRQ(SPI1_IRQn);
 }
}

linker script---->

.data :
 {
 . = ALIGN(4);
 _sdata = .; /* create a global symbol at data start */
 *(.data) /* .data sections */
 *(.data*) /* .data* sections */
 
 . = ALIGN(4);
 _edata = .; /* define a global symbol at data end */
 } >RAM_D1 AT> FLASH
 
 
 /* Uninitialized data section */
 . = ALIGN(4);
 .bss :
 {
 /* This is used by the startup in order to initialize the .bss secion */
 _sbss = .; /* define a global symbol at bss start */
 __bss_start__ = _sbss;
 *(.bss)
 *(.bss*)
 *(COMMON)
 
 . = ALIGN(4);
 _ebss = .; /* define a global symbol at bss end */
 __bss_end__ = _ebss;
 } >RAM_D1
 
 /* User_heap_stack section, used to check that there is enough RAM left */
 ._user_heap_stack :
 {
 . = ALIGN(8);
 PROVIDE ( end = . );
 PROVIDE ( _end = . );
 . = . + _Min_Heap_Size;
 . = . + _Min_Stack_Size;
 . = ALIGN(8);
 } >RAM_D1

0690X00000ButtRQAR.png0690X00000ButtWQAR.png 

This topic has been closed for replies.
Best answer by eeyurdakul
MX_GPIO_Init();
MX_I2C3_Init();
MX_I2S1_Init();
MX_DMA_Init();

STM32Cube automatically generates init functions, but the order is false, MX_DMA_Init() should be the first.

MX_DMA_Init();
MX_GPIO_Init();
MX_I2C3_Init();
MX_I2S1_Init();

This solves the problem, right now it works both in normal and circular mode.

2 replies

eeyurdakul
eeyurdakulAuthorBest answer
Associate II
December 23, 2019
MX_GPIO_Init();
MX_I2C3_Init();
MX_I2S1_Init();
MX_DMA_Init();

STM32Cube automatically generates init functions, but the order is false, MX_DMA_Init() should be the first.

MX_DMA_Init();
MX_GPIO_Init();
MX_I2C3_Init();
MX_I2S1_Init();

This solves the problem, right now it works both in normal and circular mode.