cancel
Showing results for 
Search instead for 
Did you mean: 

Why is my DMA-controller not working with my SPI bus?

arnold_w
Senior
Posted on February 23, 2016 at 16:32

I'm working with the Discovery Development Board and I am trying to use the DMA-controller with my SPI-bus in order to support longer continuous transfers than 16 bits. I have assigned SPI1 as my master and SPI2 as my slave and connected wires in between and I have verified using a logic analyzer that my master is working properly. My slave, on the other hand, is not working properly. I get SPI2_IRQHandler-interrupts which containthe first 2 bytes (out of 4) in each transmission, but there are no signs of life at all from my DMA-controller. Any type of interrupt from the DMA-controller would be a step forward for me. One more thing, the line

__IO uint32_t DMA_S0CR;/*!< Some kind of DMA interrupt enable, Address offset: 0x10 */ was missing in the typedef struct of the DMA_TypeDef inmy stm32f407xx.h-file so I added that myself.Can anybody please help me make the DMA-controller work?

void initializeSpi2controlPins(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/***************************************************
***************** SPI MISO ***********************
***************************************************/
GPIO_InitStructure.Pin = GPIO_PIN_2;
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
/***************************************************
***************** SPI MOSI ***********************
***************************************************/
GPIO_InitStructure.Pin = GPIO_PIN_3;
GPIO_InitStructure.Mode = GPIO_MODE_AF_OD;
GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
/***************************************************
***************** SPI CLK ************************
***************************************************/
GPIO_InitStructure.Pin = GPIO_PIN_10;
GPIO_InitStructure.Mode = GPIO_MODE_AF_OD;
GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
/***************************************************
***************** SPI NSS ************************
***************************************************/
GPIO_InitStructure.Pin = GPIO_PIN_9;
GPIO_InitStructure.Mode = GPIO_MODE_AF_OD;
GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
}
void enableSpi2module(void)
{
SPI_HandleTypeDef hspi;
hspi.Instance = SPI2;
hspi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
hspi.Init.Direction = SPI_DIRECTION_2LINES;
hspi.Init.Mode = SPI_MODE_SLAVE;
hspi.Init.DataSize = SPI_DATASIZE_16BIT;
hspi.Init.NSS = SPI_NSS_HARD_INPUT;
hspi.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi.Init.CLKPhase = SPI_PHASE_2EDGE;
hspi.Init.CLKPolarity = SPI_POLARITY_HIGH;
hspi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi.Init.TIMode = SPI_TIMODE_DISABLE;
RCC->APB1ENR |= RCC_APB1ENR_SPI2EN; // Enable clock for SPI 2
SPI2->DR = 0x9876; // Load some data for the master to receive
if (HAL_SPI_Init(&hspi) != HAL_OK)
{
UART4_TransmitNullTerminatedString((uint8_t*)''\r\nSPI2. Initialization Error'');
UART4_WaitForTransmitToFinish();
}
__HAL_SPI_ENABLE(&hspi);
RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN; // Enable clock for DMA1
__HAL_RCC_DMA1_CLK_ENABLE();
static DMA_HandleTypeDef hdma_tx;
static DMA_HandleTypeDef hdma_rx;
//SPI2_TX
//==Configure DMA1 - Channel0== (memory -> SPI)
hdma_tx.Instance = DMA1_Stream4;
hdma_tx.Init.Channel = DMA_CHANNEL_0;
hdma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
hdma_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL;
hdma_tx.Init.MemBurst = DMA_MBURST_SINGLE;
hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_tx.Init.MemInc = DMA_MINC_DISABLE;
hdma_tx.Init.Mode = DMA_CIRCULAR;
hdma_tx.Init.PeriphBurst = DMA_PBURST_SINGLE;
hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_tx.Init.Priority = DMA_PRIORITY_MEDIUM;
HAL_DMA_Init(&hdma_tx);
/* Associate the initialized DMA handle to the the SPI handle */
__HAL_LINKDMA(&hspi, hdmatx, hdma_tx);
//SPI2_RX
//==Configure DMA1 - Channel0== (SPI -> memory)
hdma_rx.Instance = DMA1_Stream3;
hdma_rx.Init.Channel = DMA_CHANNEL_0;
hdma_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_rx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
hdma_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL;
hdma_rx.Init.MemBurst = DMA_MBURST_SINGLE;
hdma_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_rx.Init.MemInc = DMA_MINC_DISABLE;
hdma_rx.Init.Mode = DMA_CIRCULAR;
hdma_rx.Init.PeriphBurst = DMA_PBURST_SINGLE;
hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_rx.Init.Priority = DMA_PRIORITY_MEDIUM;
HAL_DMA_Init(&hdma_rx);
/* Associate the initialized DMA handle to the the SPI handle */
__HAL_LINKDMA(&hspi, hdmarx, hdma_rx);
/* NVIC configuration for DMA transfer complete interrupt (SPI2_RX) */
HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn);
HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);
HAL_NVIC_EnableIRQ(SPI2_IRQn); // Enable SPI bus interrupts
DMA1->DMA_S0CR|= 0x08; // HTIE
DMA1->DMA_S0CR|= 0x10; // TCIE
DMA1->DMA_S0CR|= 0x04; // TEIE
DMA1->DMA_S0CR|= 0x02; // DMEIE
SPI2->CR2 |= SPI_CR2_RXNEIE;
}
//Interrupt Service Routine for DMA1_channel3: when the slave finishes transmitting the data to the master
void DMA1_Stream3_IRQHandler(void)
{
UART4_TransmitNullTerminatedString((uint8_t*)''\r\nDMA1_Stream3_IRQHandler'');
UART4_WaitForTransmitToFinish();
}
void DMA1_Stream4_IRQHandler(void)
{
UART4_TransmitNullTerminatedString((uint8_t*)''\r\nDMA1_Stream4_IRQHandler'');
UART4_WaitForTransmitToFinish();
}
void SPI2_IRQHandler(void)
{
uint16_t receivedWord;
while( !(SPI2->SR & SPI_SR_TXE) ); // Wait until transmit complete
while( !(SPI2->SR & SPI_SR_RXNE) ); // Wait until receive complete
while( SPI2->SR & SPI_SR_BSY ); // Wait until SPI is not busy anymore
receivedWord = SPI2->DR; // Return received data from SPI data register
UART4_TransmitNullTerminatedString((uint8_t*)''\r\nSPI2_IRQHandler. Received the following: 0x'');
UART4_TransmitHexNumberAsASCII((uint32_t)receivedWord);
UART4_WaitForTransmitToFinish();
}

#no-hablo-hal
3 REPLIES 3
Posted on February 23, 2016 at 20:43

16-bit values are Half-Words, not Bytes or Words, you must be consistent in all representations to the core about what you are doing.

Don't send several dozen characters via USART in an IRQ, if you must send messages, buffer them and service them with a USART IRQ.

You don't need an SPI interrupt, and it doesn't need to be waiting on stuff.

Your interrupt handlers need to clear the sources, in HAL the expectation is you call back into the HAL layer, and it signals you via a call-back. Not my cup of tea, but that's the mechanics.

You will not get DMA interrupts if the DMA doesn't function. ie it faults or errors based on the parameters and addresses you have furnished it.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
arnold_w
Senior
Posted on March 09, 2016 at 12:38

So, I have the receive part almost working now, the only problem left is that the last byte in each transmission is always missed. So, if I make my master send an extra dummy byte at the end of each transmission, then it works as expected. Can anybody see what I am doing wrong? I don't get any error interrupts.

SPI_HandleTypeDef hspi2;
DMA_HandleTypeDef hdma_spi2_tx;
DMA_HandleTypeDef hdma_spi2_rx;
void initializeSpi2controlPins(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
__SPI2_CLK_ENABLE();
/***************************************************
***************** SPI MISO ***********************
***************************************************/
GPIO_InitStructure.Pin = GPIO_PIN_2;
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
/***************************************************
***************** SPI MOSI ***********************
***************************************************/
GPIO_InitStructure.Pin = GPIO_PIN_3;
GPIO_InitStructure.Mode = GPIO_MODE_AF_OD;
GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
/***************************************************
***************** SPI CLK ************************
***************************************************/
GPIO_InitStructure.Pin = GPIO_PIN_10;
GPIO_InitStructure.Mode = GPIO_MODE_AF_OD;
GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
/***************************************************
***************** SPI NSS ************************
***************************************************/
GPIO_InitStructure.Pin = GPIO_PIN_9;
GPIO_InitStructure.Mode = GPIO_MODE_AF_OD;
GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
}
#define DMA_RECEIVE_BUFFER_SIZE 23
uint8_t receiveDMAbuffer[DMA_RECEIVE_BUFFER_SIZE];
void enableSpi2module(void)
{
__DMA1_CLK_ENABLE();
hspi2.Instance = SPI2;
hspi2.Init.Mode = SPI_MODE_SLAVE;
hspi2.Init.Direction = SPI_DIRECTION_2LINES;
hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi2.Init.CLKPhase = SPI_PHASE_2EDGE;
hspi2.Init.NSS = SPI_NSS_HARD_INPUT;
hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi2.Init.TIMode = SPI_TIMODE_DISABLED;
hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED;
hspi2.Init.CRCPolynomial = 10;
hdma_spi2_rx.Instance = DMA1_Stream3;
hdma_spi2_rx.Init.Channel = DMA_CHANNEL_0;
hdma_spi2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_spi2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi2_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi2_rx.Init.Mode = DMA_CIRCULAR;
hdma_spi2_rx.Init.Priority = DMA_PRIORITY_LOW;
hdma_spi2_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&hdma_spi2_rx);
__HAL_LINKDMA(&hspi2, hdmarx, hdma_spi2_rx);
hdma_spi2_tx.Instance = DMA1_Stream4;
hdma_spi2_tx.Init.Channel = DMA_CHANNEL_0;
hdma_spi2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi2_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi2_tx.Init.Mode = DMA_NORMAL;
hdma_spi2_tx.Init.Priority = DMA_PRIORITY_LOW;
hdma_spi2_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&hdma_spi2_tx);
__HAL_LINKDMA(&hspi2, hdmatx, hdma_spi2_tx);
/* Disable the selected SPI peripheral */
__HAL_SPI_DISABLE(&hspi2);
HAL_SPI_Init(&hspi2);
/* DMA interrupt init */
HAL_NVIC_SetPriority(DMA1_Stream3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn);
HAL_NVIC_SetPriority(DMA1_Stream4_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);
HAL_SPI_Receive_DMA(&hspi2, receiveDMAbuffer, DMA_RECEIVE_BUFFER_SIZE);
}
void DMA1_Stream3_IRQHandler(void)
{
HAL_DMA_IRQHandler(&hdma_spi2_rx);
}
void DMA1_Stream4_IRQHandler(void)
{
HAL_DMA_IRQHandler(&hdma_spi2_tx);
}
void HAL_SPI_RxHalfCpltCallback(SPI_HandleTypeDef *hspi)
{
UART4_TransmitNullTerminatedString((uint8_t*)''

HAL_SPI_RxHalfCpltCallback'');
UART4_WaitForTransmitToFinish();
}
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
UART4_TransmitNullTerminatedString((uint8_t*)''

HAL_SPI_TxCpltCallback'');
UART4_WaitForTransmitToFinish();
}
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
UART4_TransmitNullTerminatedString((uint8_t*)''

HAL_SPI_RxCpltCallback'');
UART4_WaitForTransmitToFinish();
uint16_t i;
UART4_TransmitNullTerminatedString((uint8_t*) ''

Received the following in the receive DMA buffer: '');
for (i = 0; i < DMA_RECEIVE_BUFFER_SIZE; i++)
{
UART4_TransmitNullTerminatedString((uint8_t*) ''

0x'');
UART4_TransmitHexNumberAsASCII((uint32_t)receiveDMAbuffer[i]);
}
}
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
UART4_TransmitNullTerminatedString((uint8_t*)''

HAL_SPI_TxRxCpltCallback'');
UART4_WaitForTransmitToFinish();
}
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
UART4_TransmitNullTerminatedString((uint8_t*)''

HAL_SPI_ErrorCallback'');
UART4_WaitForTransmitToFinish();
}
void HAL_SPI_TxHalfCpltCallback(SPI_HandleTypeDef *hspi)
{
UART4_TransmitNullTerminatedString((uint8_t*)''

HAL_SPI_TxHalfCpltCallback'');
UART4_WaitForTransmitToFinish();
}
void HAL_SPI_TxRxHalfCpltCallback(SPI_HandleTypeDef *hspi)
{
UART4_TransmitNullTerminatedString((uint8_t*)''

HAL_SPI_TxRxHalfCpltCallback'');
UART4_WaitForTransmitToFinish();
}

arnold_w
Senior
Posted on March 09, 2016 at 14:52

I found the problem, my master used SPI_POLARITY_HIGH but my slave used SPI_POLARITY_LOW. When I corrected this the DMA controller started working just fine.