cancel
Showing results for 
Search instead for 
Did you mean: 

TIMER

DYann.1
Senior

Hello,

I found an example on the internet of a project but I don't understand the usefulness of using a Timer 7. Could you tell me why ? Thanks in advance.

 

__IO uint32_t usTick;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  /* Prevent unused argument(s) compilation warning */
  if(htim==&htim7){
	usTick++;	
	}
  /* NOTE : This function Should not be modified, when the callback is needed,
            the __HAL_TIM_PeriodElapsedCallback could be implemented in the user file
   */
}

void delay_us(__IO uint32_t Delay){
uint32_t t=usTick;
uint32_t wait = Delay;
while( usTick - t < wait);

}
int main(void)
{

  /* 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_TIM7_Init();
	/*if (HAL_TIM_Base_Start(&htim7) != HAL_OK) {
		      _Error_Handler(__FILE__, __LINE__);
    }*/
	if (HAL_TIM_Base_Start_IT(&htim7) != HAL_OK) {
		      _Error_Handler(__FILE__, __LINE__);
    }

  MX_I2C1_Init();
	  MX_I2S2_Init();

	HAL_Delay(100);

	audio.init();


	bool ptt=HAL_GPIO_ReadPin(GPIOE,PTT_SWITCH);
	bool pttstate=ptt;
	uint16_t index = 0;
	uint16_t buf = 0;
	audio.set_volume(0);
  /* Infinite loop */
  	while (1)//	read power switch
	{
		ptt=HAL_GPIO_ReadPin(GPIO_PINS,PTT_SWITCH);
		if(ptt!=pttstate){
			if(ptt==0){

				audio.start_receive();
				for(buf=0;buf<32;buf++){
					for(index=0;index < AUDIO_BUF_SIZE;index++){
						HAL_I2SEx_TransmitReceive(&hi2s2, &i2s_zero,&i2s_buf[buf][index], 1,0xFF);
					}
				}

				audio.start_play();
				for(buf=0;buf<32;buf++){
					for(index=0;index < AUDIO_BUF_SIZE;index++){
						HAL_I2SEx_TransmitReceive(&hi2s2, &i2s_buf[buf][index],&i2s_zero, 1,0xFF);
					}
				}
			}
			
			pttstate=ptt;
		}
  	}

}

 

 

40 REPLIES 40

Hi,

It's a good idea but after my configuration :

DYann1_0-1698928962986.png

Right for SAI data output to data input but what should I do for the other 3 connections ? Which are :

SAI1_MCLK_B (Master CLK)

SAI1_FS_B (Frame Synchro)

SAI1_SCK_B (Bit Clock).

I still let them connect to the CODEC, it seems to me, right ? In my case I just connect

SAI1_SD_B with SAI1_SD_A. Right ?  

DYann.1
Senior

After connecting SAI1_SD_B with SAI1_SD_A and do the for loop.

DYann1_0-1698934602077.png

But now How to check if I have theses values via SAI1_SD_B ?

DYann1_1-1698936733022.png

I wonder what is the meaning of 'Memory To Peripheral'. After me the DMA stores data in a device but what is this device? A user-defined memory area ?

LCE
Principal

The SAI blocks can be synchronized internally.

Connection: I mean a hardware connection from pin to pin, don't know if that is feasible on your board, there might be some soldering involved.

Memory: internal SRAM buffer, those you assign by calling the DMA start function

Peripheral: all that stuff not CPU or memory, like interfaces (in your case the SAI), ADC, DAC, Timers, ...

Data go this way:

  • ext. ADC -> SAI RX -> DMA -> SRAM AD buffers
  • SRAM DA buffers (your "playbuf") -> DMA -> SAI TX -> ext. DAC

Thank you for your helps, this information is very clear (for me) compared to the numerous videos or code examples that I have seen. No problem for the connection, I've the evaluation board STM32L5 and the CODEC so I use this jump between 2 connections  :

  DYann1_0-1698939704259.png

Sorry In my program I did not call the DMA Start function as you say. I configured the DMA in circular mode only :

DYann1_0-1698940013222.png

I don't know if this is the right method but I have no errors when my program runs.

DYann.1
Senior

Here is my Main for this moment :

int main(void)
{
  /* USER CODE BEGIN 1 */
	HAL_StatusTypeDef fresult;
	int32_t playbuf[4096*2] __attribute__ ((aligned (32)));
  /* USER CODE END 1 */

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

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

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

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

/* Configure the peripherals common clocks */
  PeriphCommonClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_SAI1_Init();
  MX_I2C1_Init();
  /* USER CODE BEGIN 2 */
  HAL_SAI_RegisterCallback(&hsai_BlockB1, HAL_SAI_TX_HALFCOMPLETE_CB_ID, HAL_SAI_TxHalfCpltCallback);
  HAL_SAI_RegisterCallback(&hsai_BlockB1, HAL_SAI_TX_COMPLETE_CB_ID, HAL_SAI_TxCpltCallback);
  fresult= HAL_SAI_Init(&hsai_BlockB1);
  if (fresult != HAL_OK)
	{
  	return HAL_ERROR;
	}
  fresult = HAL_SAI_Transmit_DMA(&hsai_BlockB1, (uint8_t *)playbuf , (sizeof(playbuf))/4);
  HAL_Delay(100);
  SGTL5000_init();
  set_volume(0);
  /* USER CODE END 2 */

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

	  for (i=0;i<100;i++)
	  {playbuf[i]=i;}
	  start_receive();
	  HAL_Delay(100);
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
LCE
Principal

I'd rather fill the buffer once, before the while loop, and fill it completely.

Yes of course, you're right about this buffer. But I would like to have a little precision please. After your explanation

DYann1_0-1698962001575.png

So when I fill the array (playbuf) with the values, I only check the way

SRAM DA buffer -> DMA -> SAI TX -> ext. DAC (not for me). In this case why to connect SAI1_SD_B with SAI1_SD_A ? Is this really necessary ?

I can't verify for the moment the way : ext.ADC -> SAI RX -> DMA -> SRAM AD buffers. Right ? 

LCE
Principal

What kind of of hardware do you actually have?

Is a Codec connected, and if yes, how?

How are the SAI blocks set up? Which is transmitter, which is receiver?

 

"What kind of of hardware do you actually have ?" 

I have a STM32L552E-EV evaluation board with audio board (CODEC SGTL5000, Audio Adaptor Rev D for Teensy 4.0).  

https://www.pjrc.com/store/teensy3_audio.html

DYann1_0-1699019209727.png

"Is a Codec connected, and if yes, how?"

Yes the CODEC is connect to the STM32 and my configuration with the CODEC is :

DYann1_1-1699020940384.png

According to my knowledge via the documentation

FSx - Frame Synchronisation

SCKx - bit Clock

SDx - Serial data line

MCLK - Master Clock

And for I2S LRCLK is equivalent FS for SAI.

"How are the SAI blocks set up?"

I have this configuration but I don't know if I answer your question ?

DYann1_2-1699021664950.png

DYann1_3-1699021699986.png

DYann1_4-1699022034025.png

Which is transmitter, which is receiver?

The transmitter is SAI B and the receiver is SAI A (so CODEC is the slave after me). I hope I answered your questions.

LCE
Principal

That is some helpful info for helping. 😉

LRCK is the good old "Left Right Clock" for stereo decoders, which is equal to the sampling rate.

So you have an extra audio board, that makes some things easier.

So, again, I would start:

- without the audio board

- then connect the SAI data IOs

- fill playbuf completely 

- start DMAs (first start the slave, then the master)

- check all the SAI clocks and data IOs with a scope, LRCK should equal your sampling rate 

If all is working correctly, you should see DA data in the AD buffers.
To check AD data, you could simply compare the buffers.

PS: set the SAI DMA priorities higher (probably not necessary at low sampling rates)