Skip to main content
FLewz.1
Associate III
November 30, 2020
Solved

STM32F446 I2S stuck on Busy

  • November 30, 2020
  • 17 replies
  • 3611 views

Hi,

I've been trying to get I2S to work without using the HAL to get to know the MCU a bit more. I configured the Peripheral as mentioned in the reference manual, but whenever I write to the SPI->DR the status is stuck on busy.

This is my init function

	RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;	// enable GPIOA Port CLK; PA4 I2S1-WS; PA5 I2S1-CK; PA7 I2S1-SD
	GPIOA->MODER |= GPIO_MODER_MODE4_1
					| GPIO_MODER_MODE5_1
					| GPIO_MODER_MODE7_1;
	GPIOA->MODER &= ~(GPIO_MODER_MODE4_0 | GPIO_MODER_MODE5_0 | GPIO_MODER_MODE7_0);
	GPIOA->AFR[0] |= (GPIO_AF5_SPI1 << GPIO_AFRL_AFSEL4_Pos);
	GPIOA->AFR[0] |= (GPIO_AF5_SPI1 << GPIO_AFRL_AFSEL5_Pos);
	GPIOA->AFR[0] |= (GPIO_AF5_SPI1 << GPIO_AFRL_AFSEL7_Pos);
 
	RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;		// enable I2S Peripheral CLK
	SPI1->I2SPR |= SPI_I2SPR_I2SDIV & 47u; // set I2S Prescaler to 47
	SPI1->I2SPR &= ~SPI_I2SPR_ODD;			// set I2S ODD to 0
	SPI1->I2SCFGR &= ~SPI_I2SCFGR_CKPOL;	// set Clock Polarity to LOW when IDLE
	SPI1->I2SCFGR |= SPI_I2SCFGR_I2SMOD;	// set Mode to I2S
	SPI1->I2SCFGR |= SPI_I2SCFGR_I2SCFG_1; // set Mode to I2S Master Transmit
	SPI1->I2SCFGR &= ~SPI_I2SCFGR_DATLEN;	// set Data Length to 16 Bit
	SPI1->I2SCFGR |= SPI_I2SCFGR_CHLEN;	// set Channel Length to 32 Bit
	SPI1->I2SCFGR &= ~SPI_I2SCFGR_I2SSTD;	// set Channel to Philips Standard
//	SPI1->CR2 |= SPI_CR2_TXEIE;
//	NVIC_EnableIRQ(SPI1_IRQn);
	SPI1->I2SCFGR |= SPI_I2SCFGR_I2SE;		// enable I2S

In my main i simply check if TXE is set and then write a new value to the DR but since it never clears there is nothing happening there either.

What am I doing wrong?

This topic has been closed for replies.
Best answer by waclawek.jan

And can you see the sample frequency on LRCK?

Try to measure directly on the pin (suspecting bad solder joints) and check for shorts - unless this is a "known good" board such as Nucleo or Disco. Try to set the pin to GPIO output and wiggle it, measuring level on the output.

Coincidentally I'm working on I2S1 on a 'F446 and do have PA4/PA5 as LRCK/BICK, and can confirm that yes they do work when AFR=5.

If you're stuck, read out and check/post all the relevant registers content.

JW

17 replies

FLewz.1
FLewz.1Author
Associate III
December 5, 2020

There's one more thing I can't figure out for the life of me.

My LRCK is running perfectly at 48kHz. The I2S Clock is set at 76.8Mhz so as to get an exact 48kHz with DIV = 25. However my interrupt is called around every 1750 cycles with core frequency at 180MHz which would be a sample rate of 96kHz.

This is only when I have getNextSample() in the interrupt handler however.

I know I shouldn't call a function in an interrupt handler, I still have to set up a DMA.

It shouldn't be the second channel because I check for that in my interrupt service:

if(SPI2->SR == 0x02)
	{
		SPI2->DR = last_val;
	}else
	{
 last_val = getNextSample()
		SPI2->DR = last_val;
	}

Havin getNextSample in the while loop, and double buffering, makes the behaviour even more unpredictable. Now the CHSEL always stays at 1 and the interrupt gets called after about 150 cycles again, then after about 1600 cycles and then again after about 1750 cycles. So all in all its the correct sample period of 3500 cycles, but too many interrupts.