cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F411 SPI with DMA not firing IRQs

MGawr.2
Associate II

Hello.

I have a custom board with STM32F411RET6. I need to use SPI1 to communicate with an RF chip. I'm using HAL and FreeRTOS. I need to use DMA, since it's a high-throughput application. I'm not using CubeMX.

The problem is I can't get any IRQ to fire after the SPI transfer is done. Below is all the relevant code. I use a configuration struct so I can use the same code with multiple RF chips.

My config struct:

SPI_HandleTypeDef rf1_spi_h;
DMA_HandleTypeDef rf1_dma_tx_h;
DMA_HandleTypeDef rf1_dma_rx_h;
 
rf_config_t rf1 = {
        /* Other fields */
 
	.cs = {
		.port = RF1_CS_PORT,
		.pin = RF1_CS_PIN,
	},
 
	.miso = {
		.port = RF1_MISO_PORT,
		.pin = RF1_MISO_PIN,
		.af = GPIO_AF5_SPI1,
	},
 
	.mosi = {
		.port = RF1_MOSI_PORT,
		.pin = RF1_MOSI_PIN,
		.af = GPIO_AF5_SPI1,
	},
 
	.sck = {
		.port = RF1_SCK_PORT,
		.pin = RF1_SCK_PIN,
		.af = GPIO_AF5_SPI1,
	},
 
	.spi = SPI1,
	.spi_handle = &rf1_spi_h,
	.spi_irq = SPI1_IRQn,
 
	.dma_tx_irq = DMA2_Stream3_IRQn,
	.dma_rx_irq = DMA2_Stream2_IRQn,
 
	.dma_tx_stream = DMA2_Stream3,
	.dma_rx_stream = DMA2_Stream2,
 
	.dma_tx_chan = 3,
	.dma_rx_chan = 3,
 
	.dma_tx_handle = &rf1_dma_tx_h,
	.dma_rx_handle = &rf1_dma_rx_h,
 
        /* Other fields */
};

First, I enable DMA clock and IRQs:

__HAL_RCC_DMA1_CLK_ENABLE();
__HAL_RCC_DMA2_CLK_ENABLE();
 
//TX stream
HAL_NVIC_SetPriority(cfg->dma_tx_irq, 5, 0);
HAL_NVIC_EnableIRQ(cfg->dma_tx_irq);
 
//RX Stream
HAL_NVIC_SetPriority(cfg->dma_rx_irq, 5, 0);
HAL_NVIC_EnableIRQ(cfg->dma_rx_irq);

Then I configure the SPI peripheral:

__HAL_RCC_SPI1_CLK_ENABLE(); // It's only here for now
HAL_SPI_DeInit((cfg->spi_handle));
cfg->spi_handle->Instance = cfg->spi;
cfg->spi_handle->Init.Mode = SPI_MODE_MASTER;
cfg->spi_handle->Init.Direction = SPI_DIRECTION_2LINES;
cfg->spi_handle->Init.DataSize = SPI_DATASIZE_8BIT;
cfg->spi_handle->Init.CLKPolarity = SPI_POLARITY_LOW;
cfg->spi_handle->Init.CLKPhase = SPI_PHASE_1EDGE;
cfg->spi_handle->Init.NSS = SPI_NSS_SOFT;
cfg->spi_handle->Init.TIMode = SPI_TIMODE_DISABLE;
cfg->spi_handle->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
cfg->spi_handle->Init.CRCPolynomial = 10;
cfg->spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
cfg->spi_handle->Init.FirstBit = SPI_FIRSTBIT_MSB;
 
configASSERT(HAL_SPI_Init((cfg->spi_handle)) == HAL_OK);

Then I initialize the DMA streams:

cfg->dma_tx_handle->Instance = cfg->dma_tx_stream;
cfg->dma_tx_handle->Init.Channel = cfg->dma_tx_chan;
cfg->dma_tx_handle->Init.Direction = DMA_MEMORY_TO_PERIPH;
cfg->dma_tx_handle->Init.PeriphInc = DMA_PINC_DISABLE;
cfg->dma_tx_handle->Init.MemInc = DMA_MINC_ENABLE;
cfg->dma_tx_handle->Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
cfg->dma_tx_handle->Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
cfg->dma_tx_handle->Init.Mode = DMA_NORMAL;
cfg->dma_tx_handle->Init.Priority = DMA_PRIORITY_MEDIUM;
cfg->dma_tx_handle->Init.FIFOMode = DMA_FIFOMODE_DISABLE;
configASSERT(HAL_DMA_Init((cfg->dma_tx_handle)) == HAL_OK);
__HAL_LINKDMA((cfg->spi_handle),hdmatx,*(cfg->dma_tx_handle));
 
cfg->dma_rx_handle->Instance = cfg->dma_rx_stream;
cfg->dma_rx_handle->Init.Channel = cfg->dma_rx_chan;
cfg->dma_rx_handle->Init.Direction = DMA_PERIPH_TO_MEMORY;
cfg->dma_rx_handle->Init.PeriphInc = DMA_PINC_DISABLE;
cfg->dma_rx_handle->Init.MemInc = DMA_MINC_ENABLE;
cfg->dma_rx_handle->Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
cfg->dma_rx_handle->Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
cfg->dma_rx_handle->Init.Mode = DMA_NORMAL;
cfg->dma_rx_handle->Init.Priority = DMA_PRIORITY_MEDIUM;
cfg->dma_rx_handle->Init.FIFOMode = DMA_FIFOMODE_DISABLE;
configASSERT(HAL_DMA_Init((cfg->dma_rx_handle)) == HAL_OK);
__HAL_LINKDMA((cfg->spi_handle),hdmarx,*(cfg->dma_rx_handle));

And finally I initialize the SPI pins:

__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
 
GPIO_InitTypeDef GPIO_InitStruct = {0};
 
GPIO_InitStruct.Pin = cfg->mosi.pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = cfg->mosi.af;
HAL_GPIO_Init(cfg->mosi.port, &GPIO_InitStruct);
 
GPIO_InitStruct.Pin = cfg->miso.pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = cfg->miso.af;
HAL_GPIO_Init(cfg->miso.port, &GPIO_InitStruct);
 
GPIO_InitStruct.Pin = cfg->sck.pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = cfg->sck.af;
HAL_GPIO_Init((cfg->sck.port), &GPIO_InitStruct);
 
cfg->reset = gpio_init_output(cfg->reset.port, cfg->reset.pin);
gpio_write(&(cfg->reset), true);
 
cfg->cs = gpio_init_output(cfg->cs.port, cfg->cs.pin);
gpio_write(&(cfg->cs), true);
 
/* Enable the SPI IRQ */
HAL_NVIC_SetPriority(cfg->spi_irq, 5, 0);
HAL_NVIC_EnableIRQ(cfg->spi_irq);

The gpio_init_output() and gpio_write() are my own functions and they are well-tested.

My IRQs are as follows:

void SPI1_IRQHandler(void)
{
	HAL_SPI_IRQHandler(rf1.spi_handle);
}
 
/*	RX stream IRQ handler */
void DMA2_Stream2_IRQHandler(void)
{
	HAL_DMA_IRQHandler(rf1.dma_rx_handle);
}
 
/*	TX stream IRQ handler */
void DMA2_Stream3_IRQHandler(void)
{
	HAL_DMA_IRQHandler(rf1.dma_tx_handle);
}

I initialize my transfers with:

HAL_SPI_TransmitReceive_DMA((cfg->spi_handle), buf_send, buf_rcv, size);	

I can see that IRQs never fire using a Ozone debugger with a J-Link. Please advice.

6 REPLIES 6
KDJEM.1
ST Employee

Hello @MGawr.2​ and welcome to the Community :),

The IRQs DMA_stream positions are missing in the STM32F411.svd.

 Thank you for bringing the issue to our attention.

I reported this issue internally. 

Internal ticket number: 137390 (This is an internal tracking number and is not accessible or usable by customers).

Kaouthar

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

Hello @KDJEM.1​ , thank you for your fast response.

I'm happy you found the issue. Could you suggest me some workaround for this?

Thank you.

gbm
Lead III

If you use Rx DMA interupt, usually no other interrupt is needed for handling SPI transfers.. Are you sure you have enabled the interrupt in the DMA peripheral?

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice

Hello @MGawr.2​,

Sorry for this inconvenience.

To solve your problem, a correct STM32F411.svd file is shared for you in the below.

Thank you for your contribution in the ST community.

When your question is answered, please close this topic by choosing Select as Best. This will help other users find that answer faster.

Kaouthar

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

Hello @KDJEM.1​ , thank you for your help.

I'll try it next week and select this as the answer if everything works.

Hello @KDJEM.1​.

I'm sorry, but I'm going to need some guidance as to how to actually use the file you provided. I found a converter (https://www.keil.com/pack/doc/CMSIS/SVD/html/svd_SVDConv_pg.html), but its header output is widely different than my current stm32f411xe.h. I assume it's not a simple matter of switching the two headers, therefore I'm asking for your help.