cancel
Showing results for 
Search instead for 
Did you mean: 

SPI DMA with HAL (STM32F4Disco)

Leonelf
Associate II
Posted on October 17, 2015 at 11:07

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^^
1 REPLY 1
krzysztofrybak6
Associate II
Posted on October 22, 2015 at 22:18

Hi,

You use dma2stream3, channel 3 for transmission on SPI1?

You use normal mode, upon transfer is complete, DMA stops, maybe You need to enable it again.

You can check this using interrupt when transfer is complete and this way verify if DMA is working.

Unfortunately, I don't know HAL well...