2022-07-30 09: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 04: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 03: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.