AnsweredAssumed Answered

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

Question asked by arnold_w on Feb 23, 2016
Latest reply on Mar 9, 2016 by arnold_w
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 contain the 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 in my 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();
}

Outcomes