Skip to main content
chriskuku
Senior II
June 8, 2025
Solved

HAL_I2S_TransmitDMA in circular mode (STM32H503) doesn't run continuously

  • June 8, 2025
  • 1 reply
  • 776 views

I have set up a DMA on an I2S device with an STM32H503CBU6. The idea is, that the DMA runs continuously on a single bufferaddress (one word, containing the left and right channels for the external I2S-DAC). When the DMA transfer of that 1 word is complete it should start over again by itself.

At present the goal is not achieved with the following setup:

uint16_t ram_loc[2] = {0,0};
int main(void)
{

 

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

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



 /* Configure the system clock */
 SystemClock_Config();

 

 /* Initialize all configured peripherals */
 MX_GPIO_Init();
 MX_GPDMA1_Init();
 MX_ICACHE_Init();
 MX_I2C1_Init();
 MX_I2S2_Init();
 MX_TIM1_Init();
 
 HAL_I2S_Transmit_DMA(&hi2s2, ram_loc,1); // since circular is configured,
 // am I right that the DMA keeps alive itself?
 /* USER CODE END 2 */

 /* Infinite loop */
 
 while (1)
 {

 	// for testing, increment ram_loc (L+R) by one every 10ms
 	// which should produce a (sawtooth) ramp.
 	//
 	 HAL_Delay(10);
 	 ram_loc[0]++,ram_loc[1]++;
 	 if(ram_loc[0] == 65535)
 		 ram_loc[0]=ram_loc[1]=0;
	
 }
 
}

 

Some things I'm not sure about: how is the DMA data organized. Since it is an I2S audio stream with L+R signals, I assume they are two words of 16bits, sent in one 32bit DMA chunk. Or is it 32bit data in a 32bit frame? BTW, what does "frame" actually stand for?
What is the "Port 0" that appears, when I choose "circular" mode in the DMA channel 4 setup?

I2S2_WS - PA3
I2S2_CK - PA5
I2S2_SDO - PB1

 I don't see any data on PB1. Timing is there (48KHz on PA5, WS on PA3).

Best answer by chriskuku

I got it running. I hadn't finished the necessary setup of the GPDMA.
Had to define a linked list with two nodes. And get some other parameters in the I2S interface (word length etc.) right. See attached IOC.

 

1 reply

TDK
Super User
June 8, 2025

You should initialize ram_loc with nonzero data, and make it volatile.

volatile uint16_t ram_loc[2] = {0xAAAA, 0xAAAA};

 

Clock is there. Data is probably there as well. It's not being updated because the compiler is free to optimize it away.

"If you feel a post has answered your question, please click ""Accept as Solution""."
chriskuku
chriskukuAuthor
Senior II
June 8, 2025

Would have been too nice, but:

volatile uint16_t ram_loc[2] = {0xAAAA, 0xAAAA};
../Core/Src/main.c: In function 'main':
../Core/Src/main.c:179:36: warning: passing argument 2 of 'HAL_I2S_Transmit_DMA' discards 'volatile' qualifier from pointer target type [-Wdiscarded-qualifiers]
 179 | HAL_I2S_Transmit_DMA(&hi2s2, ram_loc,1); // since circular is configured,
 | ^~~~~~~

And, thinking about it, the compiler shouldn't optimize a variable away, that is being passed to a function

and is being assigned (incremented) further down in the while loop in the code. Or am I wrong? And non-zero data? No, this can't be it. 

Data is data, whether zero or non-zero, it's an initialization.

TDK
Super User
June 8, 2025
 HAL_I2S_Transmit_DMA(&hi2s2, (uint16_t*)ram_loc,1)

Cast it to the proper type to avoid the warning.

"If you feel a post has answered your question, please click ""Accept as Solution""."