2020-04-19 09:31 PM
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
2020-05-28 08:25 AM
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
2020-06-03 06:02 PM
None
2020-06-03 06:02 PM
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
2020-06-04 03:42 AM
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