Skip to main content
Visitor II
July 1, 2025
Question

GPDMA - Linked list - SPI

  • July 1, 2025
  • 3 replies
  • 381 views

Hi to everybody.

I can't get spi to work with linked lists. I followed the procedures in the documentation but it still doesn't work. Maybe someone can tell me why.
This is my configuration: STM32U575, cubeMX 6.12.0, cubeIDE 1.9.0
The linked list has two nodes. The first one writes 4 bytes on SPI2 and the second one reads 4 bytes on SPI2.
I don't see the clock strokes on the SPI2 bus.

Thanks a lot in advance.

main.c

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();

 /* Configure the System Power */
 SystemPower_Config();

 /* USER CODE BEGIN SysInit */

 /* USER CODE END SysInit */

 /* Initialize all configured peripherals */
 MX_GPIO_Init();
 MX_GPDMA1_Init();
 MX_ADC1_Init();
 MX_DAC1_Init();
 MX_ICACHE_Init();
 MX_RAMCFG_Init();
 MX_SPI1_Init();
 MX_SPI2_Init();
 MX_USB_OTG_FS_PCD_Init();
 MX_CORDIC_Init();
 MX_I2C4_Init();
 MX_USART2_UART_Init();
 MX_USART1_UART_Init();
 MX_LPTIM1_Init();
 /* USER CODE BEGIN 2 */

 HAL_StatusTypeDef cret3 = MX_List_ADC3_Config(); 

 HAL_StatusTypeDef ret3 = HAL_DMAEx_List_LinkQ(&handle_GPDMA1_Channel1, &List_ADC3);

 HAL_StatusTypeDef sret3 = HAL_DMAEx_List_Start_IT(&handle_GPDMA1_Channel1);

 /* USER CODE END 2 */

 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
 /* USER CODE END WHILE */

 /* USER CODE BEGIN 3 */
 }
 /* USER CODE END 3 */
}

 

spi.c

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;
 hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
 hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
 hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
 hspi2.Init.NSS = SPI_NSS_HARD_OUTPUT;
 hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64;
 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_ENABLE;
 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 */

}

gpdma.c

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_Channel0_IRQn, 0, 0);
 HAL_NVIC_EnableIRQ(GPDMA1_Channel0_IRQn);
 HAL_NVIC_SetPriority(GPDMA1_Channel1_IRQn, 0, 0);
 HAL_NVIC_EnableIRQ(GPDMA1_Channel1_IRQn);

 /* USER CODE BEGIN GPDMA1_Init 1 */

 /* USER CODE END GPDMA1_Init 1 */
 handle_GPDMA1_Channel1.Instance = GPDMA1_Channel1;
 handle_GPDMA1_Channel1.InitLinkedList.Priority = DMA_LOW_PRIORITY_MID_WEIGHT;
 handle_GPDMA1_Channel1.InitLinkedList.LinkStepMode = DMA_LSM_FULL_EXECUTION;
 handle_GPDMA1_Channel1.InitLinkedList.LinkAllocatedPort = DMA_LINK_ALLOCATED_PORT1;
 handle_GPDMA1_Channel1.InitLinkedList.TransferEventMode = DMA_TCEM_LAST_LL_ITEM_TRANSFER;
 handle_GPDMA1_Channel1.InitLinkedList.LinkedListMode = DMA_LINKEDLIST_NORMAL;
 if (HAL_DMAEx_List_Init(&handle_GPDMA1_Channel1) != HAL_OK)
 {
 Error_Handler();
 }
 if (HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel1, DMA_CHANNEL_NPRIV) != HAL_OK)
 {
 Error_Handler();
 }
 /* USER CODE BEGIN GPDMA1_Init 2 */
 handle_GPDMA1_Channel1.XferCpltCallback = HAL_DMA_ConvCpltCallback;
 /* USER CODE END GPDMA1_Init 2 */

}

 

linked_list.c

HAL_StatusTypeDef MX_List_ADC3_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_PORT1;
 pNodeConfig.Init.TransferEventMode = DMA_TCEM_BLOCK_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) &adc_command_byte[0];
 pNodeConfig.DstAddress = (uint32_t)&SPI2->TXDR;
 pNodeConfig.DataSize = 4;

 /* Build ND_SPITX Node */
 ret |= HAL_DMAEx_List_BuildNode(&pNodeConfig, &ND_SPITX);

 /* Insert ND_SPITX to Queue */
 ret |= HAL_DMAEx_List_InsertNode_Tail(&List_ADC3, &ND_SPITX);

 /* Set node configuration ################################################*/
 pNodeConfig.Init.Request = GPDMA1_REQUEST_SPI2_RX;
 pNodeConfig.Init.Direction = DMA_PERIPH_TO_MEMORY;
 pNodeConfig.Init.SrcInc = DMA_SINC_FIXED;
 pNodeConfig.Init.DestInc = DMA_DINC_INCREMENTED;
 pNodeConfig.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT1|DMA_DEST_ALLOCATED_PORT0;
 pNodeConfig.SrcAddress = (uint32_t)&SPI2->RXDR;
 pNodeConfig.DstAddress = (uint32_t) &adc_buffer[2][adc_ram_write_index[2]];

 /* Build ND_SPIRX Node */
 ret |= HAL_DMAEx_List_BuildNode(&pNodeConfig, &ND_SPIRX);

 /* Insert ND_SPIRX to Queue */
 ret |= HAL_DMAEx_List_InsertNode_Tail(&List_ADC3, &ND_SPIRX);

 return ret;
}


 

    This topic has been closed for replies.

    3 replies

    Super User
    July 1, 2025

    You'll need to enable the SPI before you can send it data.

    Get it working without the linked lists first--by sending data to TXDR. Once that's working, incorporate the linked lists.

    Or use HAL_SPI_TransmitReceive_DMA.

    Technical Moderator
    July 1, 2025

    Hello @gius2705 

    In addition to the recommandation of @TDK , please refer to the article below to configure your DMA linked list mode.

    How to configure the linked list mode in STM32Cube... - STMicroelectronics Community

    gius2705Author
    Visitor II
    July 1, 2025

    Thanks Saket_Om, I have already read that article.
    Thanks TDK, I have insert these commands at bottom of MX_SPI2_Init():

     

     SET_BIT(SPI2->CFG1, SPI_CFG1_TXDMAEN | SPI_CFG1_RXDMAEN);
     SET_BIT(SPI2->CR1, SPI_CR1_SPE);

     

    but doesn't work. No clocks no data on the bus.