cancel
Showing results for 
Search instead for 
Did you mean: 

STM32U575 GPDMA GPIO TIM synchronization output setting issue

mikesmith100
Associate II

Hello,
I am using the Nucleo U575ZI-Q board. I need to use GPDMA synchronized with a timer to set multiple GPIO pins synchronously, perform SPI transmission, and configure PWM periods.
I have found a working combination: software request + trigger TRGO. However, TRGO is only available for TIM15 and TIM2, which limits its versatility. Ideally, I would like to use hardware requests (such as REQUEST_TIM15_UP).

mikesmith100_0-1762309636774.png

Set TIM15 to output TRGO. Configure GPDMA1_CHANNEL7 with LinkedList for DMA_REQUEST_SW and set the trigger to GPDMA1_TRIGGER_TIM15_TRGO. The direction should be set to Memory-to-Memory. Specify the source as memory and the destination as GPIOA->BSRR or SPI2->TXDR. This will allow you to generate the waveform shown in the attached oscilloscope.

uint32_t gpio_node_data[4] = {
0x00000100U, // PA8 = High -> bit8 set (1 << 8)
0x01000000U, // PA8 = Low -> bit24 set (1 << (8 + 16))
0xFFFFFFFF,
0xFFFFFFFF
};

uint32_t spi2_node_data[4] = {
0xAAAAAAAA,
0x55555555,
0x11111111,
0xFFFFFFFF
};

HAL_StatusTypeDef MX_TimingSPI_GPIO_O_I_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 = DMA_REQUEST_SW;
pNodeConfig.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
pNodeConfig.Init.Direction = DMA_MEMORY_TO_MEMORY;
pNodeConfig.Init.SrcInc = DMA_SINC_FIXED;
pNodeConfig.Init.DestInc = DMA_DINC_FIXED;
pNodeConfig.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD;
pNodeConfig.Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD;
pNodeConfig.Init.SrcBurstLength = 1;
pNodeConfig.Init.DestBurstLength = 1;
pNodeConfig.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0;
pNodeConfig.Init.TransferEventMode = DMA_TCEM_EACH_LL_ITEM_TRANSFER;
pNodeConfig.TriggerConfig.TriggerMode = DMA_TRIGM_BLOCK_TRANSFER;
pNodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_RISING;
pNodeConfig.TriggerConfig.TriggerSelection = GPDMA1_TRIGGER_TIM15_TRGO;
pNodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;
pNodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;
pNodeConfig.SrcAddress = (uint32_t)&gpio_node_data[0];
pNodeConfig.DstAddress = (uint32_t)&(GPIOA->BSRR);
pNodeConfig.DataSize = sizeof(uint32_t);

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

/* Insert GPIO_High_Node to Queue */
ret |= HAL_DMAEx_List_InsertNode_Tail(&TimingSPI_GPIO_O_I, &GPIO_High_Node);

/* Set node configuration ################################################*/
pNodeConfig.Init.TransferEventMode = DMA_TCEM_LAST_LL_ITEM_TRANSFER;
pNodeConfig.SrcAddress = (uint32_t)&gpio_node_data[1];

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

/* Insert GPIO_Low_Node to Queue */
ret |= HAL_DMAEx_List_InsertNode_Tail(&TimingSPI_GPIO_O_I, &GPIO_Low_Node);

/* Set node configuration ################################################*/
pNodeConfig.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
pNodeConfig.SrcAddress = (uint32_t)&spi2_node_data[0];
pNodeConfig.DstAddress = (uint32_t)&(SPI2->TXDR);

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

/* Insert SPI2_TX_n1 to Queue */
ret |= HAL_DMAEx_List_InsertNode_Tail(&TimingSPI_GPIO_O_I, &SPI2_TX_n1);

/* Set node configuration ################################################*/
pNodeConfig.SrcAddress = (uint32_t)&spi2_node_data[1];

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

/* Insert SPI2_TX_n2 to Queue */
ret |= HAL_DMAEx_List_InsertNode_Tail(&TimingSPI_GPIO_O_I, &SPI2_TX_n2);

/* Set node configuration ################################################*/
pNodeConfig.SrcAddress = (uint32_t)&spi2_node_data[2];

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

/* Insert SPI2_TX_n3 to Queue */
ret |= HAL_DMAEx_List_InsertNode_Tail(&TimingSPI_GPIO_O_I, &SPI2_TX_n3);

ret |= HAL_DMAEx_List_SetCircularModeConfig(&TimingSPI_GPIO_O_I, &GPIO_High_Node);

return ret;
}


HAL_TIM_PWM_Start(&htim15, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim15, TIM_CHANNEL_2);

SPI2->CR1 |= SPI_CR1_SPE;
SPI2->CR1 |= SPI_CR1_CSTART;

MX_TimingSPI_GPIO_O_I_Config();
HAL_DMAEx_List_LinkQ(&handle_GPDMA1_Channel7, &TimingSPI_GPIO_O_I);
HAL_DMAEx_List_Start(&handle_GPDMA1_Channel7);


---

ChatGPT advised to do the following, but it does not work (it seems that GPDMA1 is not activated).

// gpio_node_data should be non-const
static uint32_t gpio_node_data[2] = { 0x00000100U, 0x01000000U, 0, 0 };

// Node configuration (only changes are shown)
pNodeConfig.Init.Request = GPDMA1_REQUEST_TIM15_UP;      // HW request
pNodeConfig.Init.Direction = DMA_MEMORY_TO_PERIPH;       // Write to PERIPH
pNodeConfig.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0 | DMA_DEST_ALLOCATED_PORT0;
pNodeConfig.DataSize = sizeof(uint32_t);                 // 4
pNodeConfig.TriggerConfig.TriggerMode = DMA_TRIGM_BLOCK_TRANSFER;
pNodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_RISING;
// TriggerSelection is unnecessary when using DMAMUX, or align it with DMAMUX settings
// pNodeConfig.TriggerConfig.TriggerSelection = GPDMA1_TRIGGER_TIM15_TRGO; // Usually left to DMAMUX
pNodeConfig.SrcAddress = (uint32_t)&gpio_node_data[0];
pNodeConfig.DstAddress = (uint32_t)&(GPIOA->BSRR);

 

Disable the trigger: pNodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;
Hard request and: pNodeConfig.Init.Request = GPDMA1_REQUEST_TIM15_UP;
Direction: Memory to Memory pNodeConfig.Init.Direction = DMA_MEMORY_TO_MEMORY;
Set the actual destination to memory:
pNodeConfig.SrcAddress = (uint32_t)&gpio_node_data[0];
pNodeConfig.DstAddress = (uint32_t)&gpio_node_data[3];
→ GPDMA operates, and transfer occurs between memory.

Disable the trigger: pNodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;
Hard request and: pNodeConfig.Init.Request = GPDMA1_REQUEST_TIM15_UP;
Direction: Memory to Memory pNodeConfig.Init.Direction = DMA_MEMORY_TO_MEMORY;
Set the actual destination to peripheral:
pNodeConfig.SrcAddress = (uint32_t)&gpio_node_data[0];
pNodeConfig.DstAddress = (uint32_t)&(GPIOA->BSRR);
→ Writing to the peripheral does not occur (GPIO does not change).

Disable the trigger: pNodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;
Hard request and: pNodeConfig.Init.Request = GPDMA1_REQUEST_TIM15_UP;
Direction: Memory to Peripheral pNodeConfig.Init.Direction = DMA_MEMORY_TO_PERIPH;
Set the actual destination to peripheral:
pNodeConfig.SrcAddress = (uint32_t)&gpio_node_data[0];
pNodeConfig.DstAddress = (uint32_t)&(GPIOA->BSRR);
→ Writing to the peripheral does not occur (GPIO does not change).

 

 

0 REPLIES 0