AnsweredAssumed Answered

SPI DMA with HAL (STM32F4Disco)

Question asked by loeser.leon on Oct 17, 2015
Latest reply on Oct 22, 2015 by rybak.krzysztof
I am currently trying to make DMA periodically pull data from memory (array "buffer") and push it to spi. When I manually call the SPI_Transmit function, it transmits something, the clock line shows up on my oscilloscope. But when I use DMA; nothing happens.

This is my code:
void initSPI(void) {
    __HAL_RCC_SPI1_CLK_ENABLE();
    spi.Instance = SPI1;
    spi.Init.Direction = SPI_DIRECTION_2LINES;
    spi.Init.Mode = SPI_MODE_MASTER;
    spi.Init.DataSize = SPI_DATASIZE_16BIT;
    spi.Init.CLKPolarity = SPI_POLARITY_LOW;
    spi.Init.CLKPhase = SPI_PHASE_1EDGE;
    spi.Init.NSS = SPI_NSS_SOFT;
    spi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
    spi.Init.FirstBit = SPI_FIRSTBIT_MSB;
    spi.Init.TIMode = SPI_TIMODE_DISABLED;
    spi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED;
    spi.Init.CRCPolynomial = 1;
    HAL_SPI_Init(&spi);
    __HAL_SPI_ENABLE(&spi);
    __HAL_LINKDMA(&spi, hdmatx, dma2stream3);
}

void initGPIO(void) {
    __HAL_RCC_GPIOA_CLK_ENABLE()
    ;
    __HAL_RCC_GPIOB_CLK_ENABLE()
    ;
    __HAL_RCC_GPIOD_CLK_ENABLE()
    ;
    GPIO_InitTypeDef gpio;
    gpio.Mode = GPIO_MODE_AF_PP;
    gpio.Pin = MOSI_Pin | SCK_Pin;
    gpio.Alternate = GPIO_AF5_SPI1;
    gpio.Speed = GPIO_SPEED_HIGH;
    gpio.Pull = GPIO_PULLDOWN;
    HAL_GPIO_Init(GPIOA, &gpio);
 
    gpio.Mode = GPIO_MODE_OUTPUT_PP;
    gpio.Pin = LAT_Pin | OE_Pin;
    HAL_GPIO_Init(GPIOA, &gpio);
 
    gpio.Mode = GPIO_MODE_AF_PP;
    gpio.Pin = RX_Pin | TX_Pin;
    HAL_GPIO_Init(GPIOB, &gpio);
 
    gpio.Mode = GPIO_MODE_OUTPUT_PP;
    gpio.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3;
    HAL_GPIO_Init(GPIOB, &gpio);
}

void initDMA(void) {
    __DMA1_CLK_ENABLE()
    ;
    __DMA2_CLK_ENABLE()
    ;
 
    dma1stream1.Instance = DMA1_Stream1;
    dma1stream1.Init.Channel = DMA_CHANNEL_4;
    dma1stream1.Init.Direction = DMA_PERIPH_TO_MEMORY;
    dma1stream1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    dma1stream1.Init.MemBurst = DMA_MBURST_SINGLE;
    dma1stream1.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    dma1stream1.Init.MemInc = DMA_MINC_ENABLE;
    dma1stream1.Init.Mode = DMA_NORMAL;
    dma1stream1.Init.PeriphBurst = DMA_PBURST_SINGLE;
    dma1stream1.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    dma1stream1.Init.PeriphInc = DMA_PINC_DISABLE;
    dma1stream1.Init.Priority = DMA_PRIORITY_HIGH;
    HAL_DMA_Init(&dma1stream1);
    __HAL_DMA_ENABLE(&dma1stream1);
 
    dma2stream3.Instance = DMA2_Stream3;
    dma2stream3.Init.Channel = DMA_CHANNEL_3;
    dma2stream3.Init.Direction = DMA_MEMORY_TO_PERIPH;
    dma2stream3.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    dma2stream3.Init.MemBurst = DMA_MBURST_SINGLE;
    dma2stream3.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    dma2stream3.Init.MemInc = DMA_MINC_ENABLE;
    dma2stream3.Init.Mode = DMA_NORMAL;
    dma2stream3.Init.PeriphBurst = DMA_PBURST_SINGLE;
    dma2stream3.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    dma2stream3.Init.PeriphInc = DMA_PINC_DISABLE;
    dma2stream3.Init.Priority = DMA_PRIORITY_HIGH;
    HAL_DMA_Init(&dma2stream3);
    __HAL_DMA_ENABLE(&dma2stream3);
 
    HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 1);
    HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
    HAL_DMA_Start_IT(&dma1stream1, (uint32_t) &(USART3->DR), (uint32_t) buffer, (16 * 16));
}

void initTimers(void) {
    __TIM2_CLK_ENABLE()
    ;
    tim.Instance = TIM2;
    tim.Init.Prescaler = multiplier - 1;
    tim.Init.CounterMode = TIM_COUNTERMODE_UP;
    tim.Init.Period = period - 1;
    tim.Init.RepetitionCounter = 0;
    HAL_TIM_Base_Init(&tim);
    HAL_TIM_Base_Start_IT(&tim);
 
    HAL_NVIC_SetPriority(TIM2_IRQn, 0, 1);
    HAL_NVIC_EnableIRQ(TIM2_IRQn);
}

void TIM2_IRQHandler(void) {
    if (__HAL_TIM_GET_FLAG(&tim, TIM_FLAG_UPDATE) != RESET) {
        if (__HAL_TIM_GET_ITSTATUS(&tim, TIM_IT_UPDATE) != RESET) {
            __HAL_TIM_CLEAR_FLAG(&tim, TIM_FLAG_UPDATE);
 
            HAL_GPIO_WritePin(OE_Port, LAT_Pin, ENABLE);
            HAL_GPIO_WritePin(LAT_Port, LAT_Pin, ENABLE);
            HAL_GPIO_WritePin(LAT_Port, LAT_Pin, DISABLE);
 
            LAYER_Port->ODR = ((LAYER_Port->ODR & ~(0xF)) | layer);
 
            HAL_GPIO_WritePin(OE_Port, LAT_Pin, DISABLE);
 
            layer++;
            if (layer > 7)
                layer = 0;
            HAL_DMA_Start(&dma2stream3, (uint32_t) buffer[currentBuffer][layer], (uint32_t) SPI1->DR, 16);
            //HAL_SPI_Transmit_DMA(&spi, (uint8_t*) "b", 1);
        }
    }
}

int main(int argc, char* argv[]) {
    initGPIO();
    initDMA();
    initUART();
    initSPI();
    initTimers();
    while (1) {
    }
    return 0;
}

Some variable definitions:
TIM_HandleTypeDef tim;
DMA_HandleTypeDef dma1stream1, dma2stream3;
UART_HandleTypeDef uart3;
SPI_HandleTypeDef spi;
 
uint16_t buffer[2][16][16] = { { { 0 } } };
uint8_t currentBuffer = 0;
uint8_t bufferChanged = 0;
uint8_t layer = 0;


The timer is working properly, code in their get's called, printf has proven that to me. The only problem is SPI not outputting anything.
Do you find anything wrong with my code? I'm currently transitioning to HAL from std_lib^^

Outcomes