2024-04-11 12:58 AM - edited 2024-04-11 06:29 PM
Hi All,
I’m new to using the STM32H563 solution. To send SPI data using DMA, I referred to the sample code from the SPI DMA sample of the H533RE project.
I'm not sure when exactly the SPI is start to transfer the data by DMA.
The following is a part of my test code and the analyzer result.
In Main Function:
/* USER CODE BEGIN 1 */
volatile uint32_t curr_tick = 0U;
// LL_DMA_InitTypeDef DMA_InitStruct = { 0 };
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
/* System interrupt init*/
NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
/* SysTick_IRQn interrupt configuration */
NVIC_SetPriority(SysTick_IRQn,
NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 15, 0));
/** Disable the internal Pull-Up in Dead Battery pins of UCPD peripheral
*/
LL_PWR_DisableUCPDDeadBattery();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config(SYS_CLOCK);
/* Configure the peripherals common clocks */
PeriphCommonClock_Config();
/* USER CODE BEGIN SysInit */
LL_SYSTICK_EnableIT();
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_GPDMA1_Init();
MX_SPI1_Init();
MX_ICACHE_Init();
/* USER CODE BEGIN 2 */
EnableSPI_DMA_Transfer(SPI1);
WaitAndCheckTransfer();
LL_GPIO_SetOutputPin(GPIOB, LL_GPIO_PIN_4);
SPI_TX_BUFF[0] = (0x4f << 1);
memset(&SPI_TX_BUFF[1], 0, SPI_TRANSFER_LEN - 1);
LL_DMA_SetBlkDataLength(GPDMA1, LL_DMA_CHANNEL_1, SPI_TRANSFER_LEN);
LL_DMA_ConfigAddresses(GPDMA1, LL_DMA_CHANNEL_1, (uint32_t)&SPI_TX_BUFF[0], LL_SPI_DMA_GetTxRegAddr(SPI1));
LL_DMA_SetBlkDataLength(GPDMA1, LL_DMA_CHANNEL_0, SPI_TRANSFER_LEN);
LL_DMA_ConfigAddresses(GPDMA1, LL_DMA_CHANNEL_0, LL_SPI_DMA_GetRxRegAddr(SPI1), (uint32_t)&SPI_RX_BUFF[0]);
LL_DMA_EnableChannel(GPDMA1, LL_DMA_CHANNEL_0);
LL_DMA_EnableChannel(GPDMA1, LL_DMA_CHANNEL_1);
LL_SPI_EnableDMAReq_RX(SPI1);
LL_SPI_EnableDMAReq_TX(SPI1);
LL_GPIO_ResetOutputPin(GPIOB, LL_GPIO_PIN_4);
EnableSPI_DMA_Transfer(SPI1); // will set CR1_SPE and CR1_CSTART here
WaitAndCheckTransfer();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
curr_tick = Get_SystickCounter();
while (1)
{
/* USER CODE END WHILE */
if(Get_SystickCounter() - curr_tick > LED_TOGGLE_INTERVAL)
{
LL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
curr_tick = Get_SystickCounter();
}
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
In MX_GPDMA1_Init:
static void MX_GPDMA1_Init(void)
{
/* USER CODE BEGIN GPDMA1_Init 0 */
/* USER CODE END GPDMA1_Init 0 */
/* Peripheral clock enable */
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPDMA1);
/* GPDMA1 interrupt Init */
NVIC_SetPriority(GPDMA1_Channel0_IRQn,
NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0));
NVIC_EnableIRQ(GPDMA1_Channel0_IRQn);
NVIC_SetPriority(GPDMA1_Channel1_IRQn,
NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0));
NVIC_EnableIRQ(GPDMA1_Channel1_IRQn);
}
In MX_SPI1_Init:
static void MX_SPI1_Init(void)
{
/* USER CODE BEGIN SPI1_Init 0 */
/* USER CODE END SPI1_Init 0 */
LL_SPI_InitTypeDef SPI_InitStruct = { 0 };
LL_GPIO_InitTypeDef GPIO_InitStruct = { 0 };
LL_DMA_InitTypeDef DMA_InitStruct = { 0 };
LL_RCC_SetSPIClockSource(LL_RCC_SPI1_CLKSOURCE_CLKP);
/* Peripheral clock enable */
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1);
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOG);
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);
/**SPI1 GPIO Configuration
PA5 ------> SPI1_SCK
PG9 ------> SPI1_MISO
PG10 ------> SPI1_NSS
PB5 ------> SPI1_MOSI
*/
GPIO_InitStruct.Pin = LL_GPIO_PIN_5;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_5;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LL_GPIO_PIN_9 | LL_GPIO_PIN_10;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_5;
LL_GPIO_Init(GPIOG, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LL_GPIO_PIN_5;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
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);
/* SPI1 DMA Init */
/* GPDMA1_REQUEST_SPI1_TX Init */
SPI_TX_BUFF[0] = (0x01 << 1);
memset(&SPI_TX_BUFF[1], 0, SPI_TRANSFER_LEN - 1);
DMA_InitStruct.SrcAddress = (uint32_t)&SPI_TX_BUFF[0];
DMA_InitStruct.DestAddress = LL_SPI_DMA_GetTxRegAddr(SPI1);
DMA_InitStruct.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
DMA_InitStruct.BlkHWRequest = LL_DMA_HWREQUEST_SINGLEBURST;
DMA_InitStruct.DataAlignment = LL_DMA_DATA_ALIGN_ZEROPADD;
DMA_InitStruct.SrcBurstLength = 1;
DMA_InitStruct.DestBurstLength = 1;
DMA_InitStruct.SrcDataWidth = LL_DMA_SRC_DATAWIDTH_BYTE;
DMA_InitStruct.DestDataWidth = LL_DMA_DEST_DATAWIDTH_BYTE;
DMA_InitStruct.SrcIncMode = LL_DMA_SRC_INCREMENT;
DMA_InitStruct.DestIncMode = LL_DMA_DEST_FIXED;
DMA_InitStruct.Priority = LL_DMA_LOW_PRIORITY_LOW_WEIGHT;
DMA_InitStruct.BlkDataLength = SPI_TRANSFER_LEN;
DMA_InitStruct.Mode = LL_DMA_NORMAL;
DMA_InitStruct.TriggerMode = LL_DMA_TRIGM_BLK_TRANSFER;
DMA_InitStruct.TriggerPolarity = LL_DMA_TRIG_POLARITY_MASKED;
DMA_InitStruct.TriggerSelection = 0x00000000U;
DMA_InitStruct.Request = LL_GPDMA1_REQUEST_SPI1_TX;
DMA_InitStruct.TransferEventMode = LL_DMA_TCEM_BLK_TRANSFER;
DMA_InitStruct.Mode = LL_DMA_NORMAL;
DMA_InitStruct.SrcAllocatedPort = LL_DMA_SRC_ALLOCATED_PORT0;
DMA_InitStruct.DestAllocatedPort = LL_DMA_DEST_ALLOCATED_PORT0;
DMA_InitStruct.LinkAllocatedPort = LL_DMA_LINK_ALLOCATED_PORT1;
DMA_InitStruct.LinkStepMode = LL_DMA_LSM_FULL_EXECUTION;
DMA_InitStruct.LinkedListBaseAddr = 0x00000000U;
DMA_InitStruct.LinkedListAddrOffset = 0x00000000U;
LL_DMA_Init(GPDMA1, LL_DMA_CHANNEL_1, &DMA_InitStruct);
/* GPDMA1_REQUEST_SPI1_RX Init */
DMA_InitStruct.SrcAddress = LL_SPI_DMA_GetRxRegAddr(SPI1);
DMA_InitStruct.DestAddress = (uint32_t)&SPI_RX_BUFF[0];
DMA_InitStruct.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY;
DMA_InitStruct.BlkHWRequest = LL_DMA_HWREQUEST_SINGLEBURST;
DMA_InitStruct.DataAlignment = LL_DMA_DATA_ALIGN_ZEROPADD;
DMA_InitStruct.SrcBurstLength = 1;
DMA_InitStruct.DestBurstLength = 1;
DMA_InitStruct.SrcDataWidth = LL_DMA_SRC_DATAWIDTH_BYTE;
DMA_InitStruct.DestDataWidth = LL_DMA_DEST_DATAWIDTH_BYTE;
DMA_InitStruct.SrcIncMode = LL_DMA_SRC_FIXED;
DMA_InitStruct.DestIncMode = LL_DMA_DEST_INCREMENT;
DMA_InitStruct.Priority = LL_DMA_LOW_PRIORITY_LOW_WEIGHT;
DMA_InitStruct.BlkDataLength = SPI_TRANSFER_LEN;
DMA_InitStruct.Mode = LL_DMA_NORMAL;
DMA_InitStruct.TriggerMode = LL_DMA_TRIGM_BLK_TRANSFER;
DMA_InitStruct.TriggerPolarity = LL_DMA_TRIG_POLARITY_MASKED;
DMA_InitStruct.TriggerSelection = 0x00000000U;
DMA_InitStruct.Request = LL_GPDMA1_REQUEST_SPI1_RX;
DMA_InitStruct.TransferEventMode = LL_DMA_TCEM_BLK_TRANSFER;
DMA_InitStruct.Mode = LL_DMA_NORMAL;
DMA_InitStruct.SrcAllocatedPort = LL_DMA_SRC_ALLOCATED_PORT0;
DMA_InitStruct.DestAllocatedPort = LL_DMA_DEST_ALLOCATED_PORT0;
DMA_InitStruct.LinkAllocatedPort = LL_DMA_LINK_ALLOCATED_PORT1;
DMA_InitStruct.LinkStepMode = LL_DMA_LSM_FULL_EXECUTION;
DMA_InitStruct.LinkedListBaseAddr = 0x00000000U;
DMA_InitStruct.LinkedListAddrOffset = 0x00000000U;
LL_DMA_Init(GPDMA1, LL_DMA_CHANNEL_0, &DMA_InitStruct);
/* USER CODE BEGIN SPI1_Init 1 */
/* Enable DMA interrupts complete/error */
LL_DMA_EnableIT_TC(GPDMA1, LL_DMA_CHANNEL_0);
LL_DMA_EnableIT_DTE(GPDMA1, LL_DMA_CHANNEL_0);
/* Configure the GPDMA1_Channel1 functional parameters */
/* Enable DMA interrupts complete/error */
LL_DMA_EnableIT_TC(GPDMA1, LL_DMA_CHANNEL_1);
LL_DMA_EnableIT_DTE(GPDMA1, LL_DMA_CHANNEL_1);
/* Enable DMA Channels */
LL_DMA_EnableChannel(GPDMA1, LL_DMA_CHANNEL_0);
LL_DMA_EnableChannel(GPDMA1, LL_DMA_CHANNEL_1);
/* USER CODE END SPI1_Init 1 */
/* SPI1 parameter configuration*/
SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX;
SPI_InitStruct.Mode = LL_SPI_MODE_MASTER;
SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_8BIT;
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 = 0x7;
LL_SPI_Init(SPI1, &SPI_InitStruct);
LL_SPI_SetStandard(SPI1, LL_SPI_PROTOCOL_MOTOROLA);
LL_SPI_EnableNSSPulseMgt(SPI1);
/* USER CODE BEGIN SPI1_Init 2 */
/* Configure SPI1 DMA transfer interrupts */
/* Enable DMA RX Interrupt */
LL_SPI_EnableDMAReq_RX(SPI1);
/* Enable DMA TX Interrupt */
LL_SPI_EnableDMAReq_TX(SPI1);
/* USER CODE END SPI1_Init 2 */
}
In GPDMA1_Channel0_IRQHandler:
void GPDMA1_Channel0_IRQHandler(void)
{
/* USER CODE BEGIN GPDMA1_Channel0_IRQn 0 */
if (LL_DMA_IsActiveFlag_TC(GPDMA1, LL_DMA_CHANNEL_0))
{
LL_DMA_ClearFlag_TC(GPDMA1, LL_DMA_CHANNEL_0);
/* Call function Reception complete Callback */
DMA_ReceComplete_Callback();
} else if (LL_DMA_IsActiveFlag_DTE(GPDMA1, LL_DMA_CHANNEL_0))
{
/* Call Error function */
SPI1_TransferError_Callback();
}
}
In GPDMA1_Channel1_IRQHandler:
if (LL_DMA_IsActiveFlag_TC(GPDMA1, LL_DMA_CHANNEL_1))
{
LL_DMA_ClearFlag_TC(GPDMA1, LL_DMA_CHANNEL_1);
/* Call function Reception complete Callback */
DMA_TransComplete_Callback();
} else if (LL_DMA_IsActiveFlag_DTE(GPDMA1, LL_DMA_CHANNEL_1))
{
/* Call Error function */
SPI1_TransferError_Callback(); // this callback only change the flag to notify main loop that SPI transfer is completed.
}
}
In WaitAndCheckTransfer:
static void WaitAndCheckTransfer(void)
{
/* 1 - Wait end of transmission */
while (ubTransmissionComplete != 1)
{
}
/* Disable GPDMA1 Tx Channel */
LL_DMA_DisableChannel(GPDMA1, LL_DMA_CHANNEL_1);
/* 2 - Wait end of reception */
while (ubReceptionComplete != 1)
{
}
LL_GPIO_SetOutputPin(GPIOB, LL_GPIO_PIN_4);
ubTransmissionComplete = 0;
ubReceptionComplete = 0;
/* Disable GPDMA1 Rx Channel */
LL_DMA_DisableChannel(GPDMA1, LL_DMA_CHANNEL_0);
LL_SPI_DisableDMAReq_TX(SPI1);
LL_SPI_DisableDMAReq_RX(SPI1);
LL_GPIO_ResetOutputPin(GPIOB, LL_GPIO_PIN_4);
}
Analyzer result:
1. In my code, I didn’t use LL_SPI_SetTransferSize. I’m curious about the difference if I were to set LL_SPI_SetTransferSize. Would any register change after the SPI sends the frame count we set earlier?
2. Is there a reference document related to the ping-pong buffer for STM32H5 SPI DMA?
3. In my code, it appears that the SPI starts to transfer data before I set CR1_SPE and CR1_CSTART. What exactly is the SPI DMA start bit for transferring data via DMA?
Thanks.
BR,
Peter