cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L1 SPI always busy after DMA TX/RX

SWill.3
Associate II

I am using an STM32L151VET7 as a full-duplex SPI slave, and after using HAL_SPI_TransmitReceive_DMA and receiving/transmitting any number of bytes, the SPI remains busy, and further calls to HAL_SPI_TransmitReceive_DMA return HAL_BUSY. Upon transmission, the DMA TX and RX interrupts fire as expected.

The goal is to interpret the data and restart a DMA transfer with HAL_SPI_TransmitReceive_DMA inside an interrupt on the rising edge of NSS (I'm using software NSS), but that obviously is not possible with this bug. The most important parts of my code are below. All of this code obviously follows clock initialisation, HAL_Init() and NSS initialization (which I have tested, and works fine).

What is causing the SPI peripheral to remain busy, even after the DMA has clearly finished the transfer?

Thanks everyone

SPI INITIALIZATION:

__HAL_RCC_SPI1_CLK_ENABLE();

__HAL_RCC_GPIOE_CLK_ENABLE();

static GPIO_InitTypeDef gpio_init;

gpio_init.Pin = GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;

gpio_init.Mode = GPIO_MODE_AF_PP;

gpio_init.Pull = GPIO_NOPULL;

gpio_init.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

gpio_init.Alternate = GPIO_AF5_SPI1;

HAL_GPIO_Init(GPIOE, &gpio_init);

spi_handle.Instance = SPI1;

spi_handle.Init.Mode = SPI_MODE_SLAVE;

spi_handle.Init.Direction = SPI_DIRECTION_2LINES;

spi_handle.Init.DataSize = SPI_DATASIZE_8BIT;

spi_handle.Init.CLKPolarity = SPI_POLARITY_LOW;

spi_handle.Init.CLKPhase = SPI_PHASE_1EDGE;

spi_handle.Init.NSS = SPI_NSS_SOFT;

spi_handle.Init.FirstBit = SPI_FIRSTBIT_MSB;

spi_handle.Init.TIMode = SPI_TIMODE_DISABLE;

spi_handle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;

spi_handle.Init.CRCPolynomial = 0;

if (HAL_SPI_Init(&pch_spi) != HAL_OK) {

assert(false);

}

DMA INITIALIZATION:

__HAL_RCC_DMA1_CLK_ENABLE();

rx_dma.Instance = DMA1_Channel2;

rx_dma.Init.Direction = DMA_PERIPH_TO_MEMORY;

rx_dma.Init.PeriphInc = DMA_PINC_DISABLE;

rx_dma.Init.MemInc = DMA_MINC_ENABLE;

rx_dma.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;

rx_dma.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;

rx_dma.Init.Mode = DMA_NORMAL;

rx_dma.Init.Priority = DMA_PRIORITY_HIGH;

if (HAL_DMA_Init(&rx_dma) != HAL_OK) {

assert(false);

}

__HAL_LINKDMA(&spi_handle, hdmarx, rx_dma);

tx_dma.Instance = DMA1_Channel3;

tx_dma.Init.Direction = DMA_MEMORY_TO_PERIPH;

tx_dma.Init.PeriphInc = DMA_PINC_DISABLE;

tx_dma.Init.MemInc = DMA_MINC_ENABLE;

tx_dma.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;

tx_dma.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;

tx_dma.Init.Mode = DMA_NORMAL;

tx_dma.Init.Priority = DMA_PRIORITY_HIGH;

if (HAL_DMA_Init(&tx_dma) != HAL_OK) {

assert(false);

}

__HAL_LINKDMA(&spi_handle, hdmatx, tx_dma);

HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 0, 0);

HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);

HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 0, 0);

HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);

INTERRUPTS:

void DMA1_Channel2_IRQHandler(void) {

HAL_DMA_IRQHandler(&rx_dma);

}

void DMA1_Channel3_IRQHandler(void) {

HAL_DMA_IRQHandler(&tx_dma);

}

void EXTI2_IRQHandler(void) {

HAL_SPI_TransmitReceive_DMA(&spi_handle, tx_dma_buf, rx_dma_buf, BUF_SIZE);

}

0 REPLIES 0