cancel
Showing results for 
Search instead for 
Did you mean: 

How to setup a SPI + DMA by the use of the LL lib for the STM32MP151C?

Machilus
Associate III

Hi All.​

I develop M4 Core firmware using a custom board based on STM32MP151C.

There is no problem with SPI communication without using DMA. However, when DMA is used, waveforms do not occur the pins or only the NSS pins react, resulting in waveforms.

I want to know if I set the DMA wrong.

Below is the corresponding code.

__IO uint16_t __TEST_BUFFER[3];

void

MX_DMA_Init (void)

{

/* DMA controller clock enable */

__HAL_RCC_DMA2_CLK_ENABLE();

__HAL_RCC_DMAMUX_CLK_ENABLE();

/* DMA2_Stream1_IRQn interrupt configuration */

HAL_NVIC_SetPriority (DMA2_Stream1_IRQn, 0, 0);

HAL_NVIC_EnableIRQ (DMA2_Stream1_IRQn);

return;

}

void

MX_SPI2_Init ()

{

LL_SPI_InitTypeDef SPI_InitStruct =

{ 0 };

LL_GPIO_InitTypeDef GPIO_InitStruct =

{ 0 };

if (IS_ENGINEERING_BOOT_MODE())

{

LL_RCC_SetSPIClockSource (LL_RCC_SPI23_CLKSOURCE_PLL3Q);

}

/* Peripheral clock enable */

LL_APB1_GRP1_EnableClock (LL_APB1_GRP1_PERIPH_SPI2);

LL_AHB4_GRP1_EnableClock (LL_AHB4_GRP1_PERIPH_GPIOB);

LL_AHB4_GRP1_EnableClock (LL_AHB4_GRP1_PERIPH_GPIOI);

/**SPI2 GPIO Configuration

PB4  ------> SPI2_NSS

PI1  ------> SPI2_SCK

PI3  ------> SPI2_MOSI

*/

GPIO_InitStruct.Pin = LL_GPIO_PIN_4;

GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;

GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_MEDIUM;

GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;

GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;

GPIO_InitStruct.Alternate = LL_GPIO_AF_7;

LL_GPIO_Init (GPIOB, &GPIO_InitStruct);

GPIO_InitStruct.Pin = LL_GPIO_PIN_1 | LL_GPIO_PIN_2 | LL_GPIO_PIN_3;

GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;

GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_MEDIUM;

GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;

GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;

GPIO_InitStruct.Alternate = LL_GPIO_AF_5;

LL_GPIO_Init (GPIOI, &GPIO_InitStruct);

/* SPI2 parameter configuration*/

SPI_InitStruct.TransferDirection = LL_SPI_HALF_DUPLEX_TX;

SPI_InitStruct.Mode = LL_SPI_MODE_MASTER;

SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_16BIT;

SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_LOW;

SPI_InitStruct.ClockPhase = LL_SPI_PHASE_1EDGE;

SPI_InitStruct.NSS = LL_SPI_NSS_HARD_OUTPUT;

SPI_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV2;

SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST;

SPI_InitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;

SPI_InitStruct.CRCPoly = 0xD;

LL_SPI_Init (SPI2, &SPI_InitStruct);

LL_SPI_SetStandard (SPI2, LL_SPI_PROTOCOL_MOTOROLA);

LL_SPI_EnableNSSPulseMgt (SPI2);

LL_SPI_Enable(SPI2);

LL_DMA_SetPeriphRequest(DMA2, LL_DMA_STREAM_1, LL_DMAMUX1_REQ_SPI2_TX);

LL_DMA_SetDataTransferDirection (DMA2,

LL_DMA_STREAM_1,

LL_DMA_DIRECTION_MEMORY_TO_PERIPH);

LL_DMA_SetStreamPriorityLevel (DMA2,

  LL_DMA_STREAM_1,

  LL_DMA_PRIORITY_VERYHIGH);

LL_DMA_SetMode (DMA2, LL_DMA_STREAM_1, LL_DMA_MODE_NORMAL);

LL_DMA_SetPeriphIncMode (DMA2, LL_DMA_STREAM_1, LL_DMA_PERIPH_NOINCREMENT);

LL_DMA_SetMemoryIncMode (DMA2, LL_DMA_STREAM_1, LL_DMA_MEMORY_INCREMENT);

LL_DMA_SetPeriphSize (DMA2, LL_DMA_STREAM_1, LL_DMA_PDATAALIGN_HALFWORD);

LL_DMA_SetMemorySize (DMA2, LL_DMA_STREAM_1, LL_DMA_MDATAALIGN_HALFWORD);

LL_DMA_DisableFifoMode (DMA2, LL_DMA_STREAM_1);

LL_DMA_ConfigAddresses (DMA2,

LL_DMA_STREAM_1,

(uint32_t) &__TEST_BUFFER[0],

(uint32_t) &(SPI2->TXDR),

LL_DMA_DIRECTION_PERIPH_TO_MEMORY);

LL_DMA_SetDataLength (DMA2, LL_DMA_STREAM_1, 3);

LL_DMA_EnableStream (DMA2, LL_DMA_STREAM_1);

LL_DMA_EnableIT_TC (DMA2, LL_DMA_STREAM_1); // Enable transfer complete interrupt.

LL_DMA_EnableIT_TE (DMA2, LL_DMA_STREAM_1); // Enable transfer error interrupt.

return;

}

​void DMA2_Stream1_IRQHandler(void)

{

if (LL_DMA_IsActiveFlag_TC1 (DMA2) == 1)

{

/* Clear flag DMA transfer complete */

LL_DMA_ClearFlag_TC1 (DMA2);

LL_SPI_DisableDMAReq_TX(SPI2);

}

if (LL_DMA_IsActiveFlag_TE1 (DMA2) == 1)

{

/* Clear flag DMA transfer error */

LL_DMA_ClearFlag_TE1 (DMA2);

LL_SPI_DisableDMAReq_TX(SPI2);

}

return;

}

int

main (void)

{

HAL_Init ();

/* If booted from Engineering mode */

if (IS_ENGINEERING_BOOT_MODE())

{

/* Configure the system clock */

SystemClock_Config ();

}

else

{

/*HW semaphore Clock enable*/

__HAL_RCC_HSEM_CLK_ENABLE();

/* IPCC initialisation */

MX_IPCC_Init ();

MX_VUART_Init ();

}

MX_DMA_Init ();

MX_SPI2_Init ();

__MTR_FEED_BFR = { 4152, 20536, 46700 };

while (1)

{

LL_DMA_ClearFlag_TC1(DMA2);

LL_SPI_EnableDMAReq_TX(SPI2);

while(!LL_SPI_IsEnabledDMAReq_TX(SPI2))

{

HAL_Delay(1);

}

}

}

need a lot of advice

Machilus​

4 REPLIES 4
JeanPhilippeR
ST Employee

Hello @Machilus​ 

when looking at your code, after configure the DMA stream, you have to associate it to a DMA channel, to complete the DMA path, by using the function LL_DMA_SetChannelSelection:

LL_DMA_SetDataLength (DMA2, LL_DMA_STREAM_1, 3);

LL_DMA_EnableStream (DMA2, LL_DMA_STREAM_1);

+ LL_DMA_SetChannelSelection(DMA2, LL_DMA_STREAM_1, LL_DMA_CHANNEL_0);

LL_DMA_EnableIT_TC (DMA2, LL_DMA_STREAM_1); // Enable transfer complete interrupt.

LL_DMA_EnableIT_TE (DMA2, LL_DMA_STREAM_1); // Enable transfer error interrupt.

Best regards

Jean-Philippe

Machilus
Associate III

None

Hi JeanPhilippeR (ST Employee)

Thank you for your opinion.

However, the "LL_DMA_SetChannelSelection" function is not defined in the "stm32mp1xx_ll_dma.h" file.

Similarly, "LL_DMA_CHANNEL_0" is not defined.

The stm32mp1 chip family does not seem to use channels when using DMA. 

Neither the HAL library nor the LL library could find the defined portion for the channel.

I hope you check the above and suggest another solution.

Best regards

Machilus

Hi @Machilus​ 

Sure, sorry, you're right. I was comparing your usecase with STM32MCU code, as no such example in CubeFW for STM32MP1.

One more suggestion.

LL_DMA_ConfigAddresses is called with LL_DMA_DIRECTION_PERIPH_TO_MEMORY direction parameter.

In previous call of LL_DMA_SetDataTransferDirection, LL_DMA_DIRECTION_MEMORY_TO_PERIPH is set.

In order to avoid any confusion, could you please use "LL_DMA_GetDataTransferDirection(DMA2, LL_DMA_STREAM_1)" function as Direction parameter in LL_DMA_ConfigAddresses function?

Thank you

BR

Jean-Philippe