2025-07-01 5:46 AM
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;
}
2025-07-01 6:51 AM
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.
2025-07-01 7:23 AM
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
2025-07-01 7:48 AM
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.