2022-07-30 9:35 AM
Under the HAL template the SPI2/DMA in received only which worked fine. I have MISO and MOSI loop back for test purpose and need to send 3 or 4 byte per session.
Because the client code is LL template so I can't use HAL solution. Below is the LL snips for which I use UART command to run the init. The DMA interrupt is not invoked after transmitting 3 or 4 byte data. After checking out the SRC in DMA1 and SPI2 register list including NVIC I found no difference from the working HAL template code. I don't see DMA interrupt flag set. I'm running out of ideas about what to do next and why DMA interrupt is not invoked by SPI2 received operation, have I missed something?
NB: The BOOT1 is grounded by eval board (via 10K). I also have UART/Systick up and running which means the interrupt system is working fine. I wish to note this is demo FW as testbed which is MIXED HAL and LL template.
//========================================================================
// Purpose:- None MX Way to setup GPIO
// Input:-
// Output:-
// Note:- None
//========================================================================
static void STM32_DMASPI_GPIO_Init(void)
{
/* Peripheral clock enable */
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2);
//LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);
//LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1); // Already Enabled by previous code
//__HAL_RCC_DMA1_CLK_ENABLE();
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
/**SPI2 GPIO Configuration
PB13 ------> SPI2_SCK
PB14 ------> SPI2_MISO
PB15 ------> SPI2_MOSI
*/
GPIO_InitStruct.Pin = LL_GPIO_PIN_13|LL_GPIO_PIN_14|LL_GPIO_PIN_15;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_5;
LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
//------------------------------------------------------/CS
GPIO_InitStruct.Pin = SPI2_CS_PIN;
GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_0; // Ignored due to MODE.
LL_GPIO_Init(SPI2_CS_GPIO_Port, &GPIO_InitStruct);
// or in G12 Load MCU
// LL_GPIO_SetAFPin_0_7(SPI1_SCK_LL,LL_GPIO_AF_5);
// LL_GPIO_SetAFPin_0_7(SPI1_MOSI_LL,LL_GPIO_AF_5);
// LL_GPIO_SetAFPin_0_7(SPI1_MISO_LL,LL_GPIO_AF_5);
}
//========================================================================
// Purpose:- None MX Way to setup DMA and SPI
// Input:-
// Output:-
// Note:- None
//========================================================================
static void SMT32_DMASPI_Init(bool IncludeDMA)
{
//L99DM02_SPI_SEND TxData;
if (IncludeDMA==FALSE)
{
STM32_DMASPI_InitSPI2();
LL_SPI_Enable( SPI2 );//enable SPI2 port
return;
}
STM32_DMASPI_DMA1_A();
STM32_DMASPI_InitSPI2();
}
static void STM32_DMASPI_DMA1_A(void)
{
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);
/* (2) Configure NVIC for DMA transfer complete/error interrupts */
//__HAL_RCC_DMA1_CLK_ENABLE();
HAL_NVIC_SetPriority(DMA1_Channel4_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
//LL_SPI_SetDMAParity_RX(SPI2,LL_SPI_DMA_PARITY_ODD);
/* (4) Configure the DMA1_Channel4 functional parameters */
LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_4, LL_DMA_REQUEST_4);
LL_DMA_ConfigTransfer(DMA1, LL_DMA_CHANNEL_4,
LL_DMA_DIRECTION_PERIPH_TO_MEMORY | LL_DMA_PRIORITY_HIGH | LL_DMA_MODE_CIRCULAR |
LL_DMA_PERIPH_NOINCREMENT | LL_DMA_MEMORY_INCREMENT |
LL_DMA_PDATAALIGN_BYTE | LL_DMA_MDATAALIGN_BYTE);
LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_4, LL_SPI_DMA_GetRegAddr(SPI2), (uint32_t)SPIRXData,
LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_CHANNEL_4));
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_4, 3);
/* (5) Enable DMA interrupts complete/error */
LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_4);
LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_4);
LL_DMA_EnableIT_HT(DMA1, LL_DMA_CHANNEL_4); // HAL has this set, not sure why?
}
static void STM32_DMASPI_InitSPI2(void)
{
LL_SPI_InitTypeDef SpiInitStruct;
LL_SPI_StructInit( &SpiInitStruct );
// L99 : CPOL = 0 CPHA = 0 which is not same as TLE which operate with CPOL = 0 CPHA = 1
SpiInitStruct.TransferDirection = LL_SPI_FULL_DUPLEX;
SpiInitStruct.Mode = LL_SPI_MODE_MASTER;
SpiInitStruct.DataWidth = LL_SPI_DATAWIDTH_8BIT;
SpiInitStruct.ClockPolarity = LL_SPI_POLARITY_HIGH;
SpiInitStruct.ClockPhase = LL_SPI_PHASE_2EDGE;
//SpiInitStruct.ClockPolarity = LL_SPI_POLARITY_LOW; //CPOL=0
//SpiInitStruct.ClockPhase = LL_SPI_PHASE_1EDGE; //CPHA=0
SpiInitStruct.NSS = LL_SPI_NSS_SOFT;
SpiInitStruct.BitOrder = LL_SPI_MSB_FIRST;
SpiInitStruct.CRCPoly = 7;
SpiInitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;
SpiInitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV64;
HAL_NVIC_DisableIRQ( SPI2_IRQn );
LL_SPI_DeInit( SPI2 );
LL_SPI_Init( SPI2, &SpiInitStruct );
LL_SPI_SetStandard(SPI2, LL_SPI_PROTOCOL_MOTOROLA);
//LL_SPI_DisableNSSPulseMgt(SPI2);
//LL_SPI_EnableNSSPulseMgt(SPI2);
LL_SPI_SetRxFIFOThreshold( SPI2, LL_SPI_RX_FIFO_TH_QUARTER ); // set RXNE to trigger on 1 byte
//LL_SPI_EnableIT_RXNE(SPI2);
}
static void STM32_DMASPI_Run(void)
{
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_4);
LL_SPI_Disable( SPI2 );
//NVIC_EnableIRQ(DMA1_Channel4_IRQn);
LL_DMA_ClearFlag_TC4(DMA1);
LL_DMA_ClearFlag_TE4(DMA1);
LL_DMA_SetMemoryAddress( DMA1, LL_DMA_CHANNEL_4, (uint32_t)&SPIRXData );
HAL_NVIC_EnableIRQ(SPI2_IRQn );
HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
LL_SPI_Enable( SPI2 );//enable SPI2 port
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_4);
LL_SPI_EnableDMAReq_RX(SPI2);
zprintf("__NVIC_GetActive: 0x%4x\n",__NVIC_GetActive(DMA1_Channel4_IRQn));
zprintf("__NVIC_GetEnableIRQ: 0x%4x\n",__NVIC_GetEnableIRQ(DMA1_Channel4_IRQn));
zprintf("__NVIC_GetPriorityGrouping: 0x%4x\n",__NVIC_GetPriorityGrouping());
ActivateSpiCS( 0 );
// write transmit data to SPI, command first, then upper data byte, then lower data byte
LL_SPI_TransmitData8( SPI2, 0x1A );
LL_SPI_TransmitData8( SPI2, 0x2B );
LL_SPI_TransmitData8( SPI2, 0xAA );
LL_SPI_TransmitData8( SPI2, 0xBB );
}
static void STM32_DMASPI_Polling_Run(void)
{
SMT32_DMASPI_Init(FALSE); // SPI Only.
ActivateSpiCS( 0 );
// write transmit data to SPI, command first, then upper data byte, then lower data byte
LL_SPI_TransmitData8( SPI2, 0x1A );
LL_SPI_TransmitData8( SPI2, 0x2B );
LL_SPI_TransmitData8( SPI2, 0xAA );
while( LL_SPI_IsActiveFlag_BSY( SPI2 ) ); // wait for SPI transfer complete
DeactivateSpiCS(); // unset device CS active
SPIRXData[0] = *((BYTE*)&SPI2->DR);;
SPIRXData[1] = *((BYTE*)&SPI2->DR);;
SPIRXData[2] = *((BYTE*)&SPI2->DR);;
zprintf("Received Data 0x%1x, 0x%1x, 0x%1x\n",SPIRXData[0],SPIRXData[1],SPIRXData[2]);
}
2022-07-30 4:59 PM
I just fixed the bug after discovering this statement:
LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_4, LL_DMA_REQUEST_4);
The datasheet indicated SPI2-RX goes to DMA_CHANNEL_4 and also DMA_REQUEST_4 but when MXCube creates code it points to LL_DMA_REQUEST_1 not LL_DMA_REQUEST_4 as per datasheet s
It is in reference manual RM0351 Page 338 (STM32L47xxx, STM32L48xxx, STM32L49xxx and STM32L4Axxx) which clearly link SPI2_RX to LL_DMA_REQUEST_4 so I still confused between LL_DMA_REQUEST_4 and LL_DMA_REQUEST_1 is reference manual in error?.
Can anyone explain this?
2022-08-17 3:53 AM
Hi @Community member ,
Generated code with current STM32CubeMX version (6.6.1) contains following line:
LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_4, LL_DMA_REQUEST_1);This is aligned with the content of table 44 in the RM0351:
Are you sing an older version of the tool where it is possible that there was an issue?
-Amel
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
We’re moving the ST Community to a new platform to give you a better and more reliable community experience.