Skip to main content
Graduate 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).

    This topic has been closed for replies.
    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

    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.

    chriskukuAuthor
    Graduate 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.

    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.