STM32U535 GPDMA LLI and SPI what I'm doing wrong
Hi,
I have a STM32U535 microcontroller, I would like to send data to the display via SPI using GPDMA with LLI. The Frame buffer is about 150kB, so due to the fact that in a single transfer I can send max. 64kB of data, I want to divide it into three LLI nodes create a queue and send via SPI.
For the test, I created two LLI nodes in CubeMX:
DMA_NodeTypeDef YourNodeName;
DMA_QListTypeDef YourQueueName;
DMA_NodeTypeDef YourNodeName2;
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
uint8_t ScrAdrPart1[] = {0xAD, 0xAD,0xAD,0xAD,0xAD,0xAD,0xAD,0xAD,0xAD,0xAD,0xAD,0xAD,0xAD,0xAD,
0xAD,0xAD,0xAD,0xAD,0xAD,0xAD};
uint16_t DataSizePart1 = 20;
uint8_t ScrAdrPart2[] = {0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD};
uint16_t DataSizePart2 = 100;
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/**
* @brief DMA Linked-list YourQueueName configuration
* @PAram None
* @retval None
*/
HAL_StatusTypeDef MX_YourQueueName_Config(void)
{
HAL_StatusTypeDef ret = HAL_OK;
/* DMA node configuration declaration */
DMA_NodeConfTypeDef pNodeConfig;
/* Set node configuration ################################################*/
pNodeConfig.NodeType = DMA_GPDMA_LINEAR_NODE;
pNodeConfig.Init.Request = GPDMA1_REQUEST_SPI2_TX;
pNodeConfig.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
pNodeConfig.Init.Direction = DMA_MEMORY_TO_PERIPH;
pNodeConfig.Init.SrcInc = DMA_SINC_INCREMENTED;
pNodeConfig.Init.DestInc = DMA_DINC_FIXED;
pNodeConfig.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;
pNodeConfig.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;
pNodeConfig.Init.SrcBurstLength = 1;
pNodeConfig.Init.DestBurstLength = 1;
pNodeConfig.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0;
pNodeConfig.Init.TransferEventMode = DMA_TCEM_LAST_LL_ITEM_TRANSFER;
pNodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;
pNodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;
pNodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;
pNodeConfig.SrcAddress = (uint32_t) ScrAdrPart1;
pNodeConfig.DstAddress = (uint32_t) &SPI2->TXDR;
pNodeConfig.DataSize = DataSizePart1;
/* Build YourNodeName Node */
ret |= HAL_DMAEx_List_BuildNode(&pNodeConfig, &YourNodeName);
/* Insert YourNodeName to Queue */
ret |= HAL_DMAEx_List_InsertNode_Tail(&YourQueueName, &YourNodeName);
/* Set node configuration ################################################*/
pNodeConfig.SrcAddress = ScrAdrPart2;
pNodeConfig.DstAddress = &SPI2->TXDR;
pNodeConfig.DataSize = DataSizePart2;
/* Build YourNodeName2 Node */
ret |= HAL_DMAEx_List_BuildNode(&pNodeConfig, &YourNodeName2);
/* Insert YourNodeName2 to Queue */
ret |= HAL_DMAEx_List_InsertNode_Tail(&YourQueueName, &YourNodeName2);
return ret;
}I called the MX_YourQueueName_Config(); function in main after initialization to create nodes and a queue.
The GPDMA was configured as follows:
DMA_HandleTypeDef handle_GPDMA1_Channel15;
/* GPDMA1 init function */
void MX_GPDMA1_Init(void)
{
/* USER CODE BEGIN GPDMA1_Init 0 */
/* USER CODE END GPDMA1_Init 0 */
/* Peripheral clock enable */
__HAL_RCC_GPDMA1_CLK_ENABLE();
/* GPDMA1 interrupt Init */
HAL_NVIC_SetPriority(GPDMA1_Channel15_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(GPDMA1_Channel15_IRQn);
/* USER CODE BEGIN GPDMA1_Init 1 */
/* USER CODE END GPDMA1_Init 1 */
handle_GPDMA1_Channel15.Instance = GPDMA1_Channel15;
handle_GPDMA1_Channel15.InitLinkedList.Priority = DMA_HIGH_PRIORITY;
handle_GPDMA1_Channel15.InitLinkedList.LinkStepMode = DMA_LSM_FULL_EXECUTION;
handle_GPDMA1_Channel15.InitLinkedList.LinkAllocatedPort = DMA_LINK_ALLOCATED_PORT0;
handle_GPDMA1_Channel15.InitLinkedList.TransferEventMode = DMA_TCEM_EACH_LL_ITEM_TRANSFER;
handle_GPDMA1_Channel15.InitLinkedList.LinkedListMode = DMA_LINKEDLIST_NORMAL;
if (HAL_DMAEx_List_Init(&handle_GPDMA1_Channel15) != HAL_OK)
{
Error_Handler();
}
if (HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel15, DMA_CHANNEL_PRIV) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN GPDMA1_Init 2 */
/* USER CODE END GPDMA1_Init 2 */
}SPI as follows:
void MX_SPI2_Init(void)
{
/* USER CODE BEGIN SPI2_Init 0 */
/* USER CODE END SPI2_Init 0 */
SPI_AutonomousModeConfTypeDef HAL_SPI_AutonomousMode_Cfg_Struct = {0};
/* USER CODE BEGIN SPI2_Init 1 */
/* USER CODE END SPI2_Init 1 */
hspi2.Instance = SPI2;
hspi2.Init.Mode = SPI_MODE_MASTER;
hspi2.Init.Direction = SPI_DIRECTION_2LINES_TXONLY;
hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi2.Init.NSS = SPI_NSS_SOFT;
hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi2.Init.CRCPolynomial = 0x7;
hspi2.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
hspi2.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
hspi2.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
hspi2.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
hspi2.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
hspi2.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
hspi2.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
hspi2.Init.IOSwap = SPI_IO_SWAP_DISABLE;
hspi2.Init.ReadyMasterManagement = SPI_RDY_MASTER_MANAGEMENT_INTERNALLY;
hspi2.Init.ReadyPolarity = SPI_RDY_POLARITY_HIGH;
if (HAL_SPI_Init(&hspi2) != HAL_OK)
{
Error_Handler();
}
HAL_SPI_AutonomousMode_Cfg_Struct.TriggerState = SPI_AUTO_MODE_DISABLE;
HAL_SPI_AutonomousMode_Cfg_Struct.TriggerSelection = SPI_GRP1_GPDMA_CH0_TCF_TRG;
HAL_SPI_AutonomousMode_Cfg_Struct.TriggerPolarity = SPI_TRIG_POLARITY_RISING;
if (HAL_SPIEx_SetConfigAutonomousMode(&hspi2, &HAL_SPI_AutonomousMode_Cfg_Struct) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN SPI2_Init 2 */
/* USER CODE END SPI2_Init 2 */
}All of the above generated from CubeMX.
Then in the main I tried to start transmission with such code by observing CLK on SPI2 with a triggered oscilloscope, unfortunately, in this case the transmission is not started interrupts are not generated.
extern DMA_NodeTypeDef YourNodeName;
extern DMA_QListTypeDef YourQueueName;
extern uint8_t ScrAdrPart1[] ;
extern uint16_t DataSizePart1;
extern uint16_t DataSizePart2;
void HAL_DMAEx_List_XferCpltCallback(DMA_HandleTypeDef *hdma)
{
// Tutaj akcja po zakończeniu transferu całej listy
// Np. dla LVGL:
;//lv_disp_flush_ready(DISPLAY_returnPnt()->lv_display);
//CS_HIGH();
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_GPDMA1_Init();
MX_ICACHE_Init();
MX_SPI2_Init();
MX_TIM3_Init();
MX_USART1_UART_Init();
MX_OCTOSPI1_Init();
MX_LPUART1_UART_Init();
MX_I2C1_Init();
MX_TIM1_Init();
MX_TIM8_Init();
MX_DCACHE1_Init();
MX_FLASH_Init();
/* USER CODE BEGIN 2 */
MX_YourQueueName_Config();
//HAL_DMAEx_List_ConvertQToDynamic(&YourQueueName);
HAL_StatusTypeDef status = HAL_DMAEx_List_LinkQ(&handle_GPDMA1_Channel15, &YourQueueName);
if (status != HAL_OK)
;
;
__HAL_LINKDMA(&hspi2, hdmatx, handle_GPDMA1_Channel15);
handle_GPDMA1_Channel15.XferCpltCallback = HAL_DMAEx_List_XferCpltCallback;
status = HAL_DMAEx_List_Start_IT(&handle_GPDMA1_Channel15);
if (status != HAL_OK)
;
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}If, on the other hand, it uses the function not HAL_DMAEx_List_Start_IT but HAL_SPI_Transmit_DMA(&hspi2, ScrAdrPart1, DataSizePart1) to send;
SPI only sends data from the first node and does not automatically switch to the second.
How, then, should GPDMA SPI and ILL be configured, or how should the transmission be started to ensure that the data configured in all nodes of the list is transmitted without software intervention.
Greetings, calka.
