Skip to main content
Visitor II
April 28, 2025
Question

Timer update event delay

  • April 28, 2025
  • 3 replies
  • 453 views

I am using timer15 to generate TRGO by update event, which is used to trigger DMA to transfer data via spi.

From the oscilloscope, I found a delay around 150ns between rising edge of TRGO (PWM output on PA2) and first pulse of SPI sck.

I am not sure whether it is normal?

    This topic has been closed for replies.

    3 replies

    Super User
    April 28, 2025

    Welcome to the forum.

    Please see: How to write your question to maximize your chances to find a solution; in particular How to insert source code.

    You'll need to show your code - using HAL, such a delay could be quite likely ...

    dh_leslieAuthor
    Visitor II
    April 29, 2025

    Please see my post below.

    Do you have any idea about this delay?

    dh_leslieAuthor
    Visitor II
    April 29, 2025
    /* TIM15 init function */
    void MX_TIM15_Init(void)
    {
    
     /* USER CODE BEGIN TIM15_Init 0 */
    
     /* USER CODE END TIM15_Init 0 */
    
     TIM_ClockConfigTypeDef sClockSourceConfig = {0};
     TIM_MasterConfigTypeDef sMasterConfig = {0};
     TIM_OC_InitTypeDef sConfigOC = {0};
     TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
    
     /* USER CODE BEGIN TIM15_Init 1 */
    
     /* USER CODE END TIM15_Init 1 */
     htim15.Instance = TIM15;
     htim15.Init.Prescaler = 0;
     htim15.Init.CounterMode = TIM_COUNTERMODE_UP;
     htim15.Init.Period = 499;
     htim15.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
     htim15.Init.RepetitionCounter = 0;
     htim15.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
     if (HAL_TIM_Base_Init(&htim15) != HAL_OK)
     {
     Error_Handler();
     }
     sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
     if (HAL_TIM_ConfigClockSource(&htim15, &sClockSourceConfig) != HAL_OK)
     {
     Error_Handler();
     }
     if (HAL_TIM_PWM_Init(&htim15) != HAL_OK)
     {
     Error_Handler();
     }
     sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
     sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
     if (HAL_TIMEx_MasterConfigSynchronization(&htim15, &sMasterConfig) != HAL_OK)
     {
     Error_Handler();
     }
     sConfigOC.OCMode = TIM_OCMODE_PWM1;
     sConfigOC.Pulse = 0;
     sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
     sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
     sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
     sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
     sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
     if (HAL_TIM_PWM_ConfigChannel(&htim15, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
     {
     Error_Handler();
     }
     sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
     sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
     sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
     sBreakDeadTimeConfig.DeadTime = 0;
     sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
     sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
     sBreakDeadTimeConfig.BreakFilter = 0;
     sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
     if (HAL_TIMEx_ConfigBreakDeadTime(&htim15, &sBreakDeadTimeConfig) != HAL_OK)
     {
     Error_Handler();
     }
     /* USER CODE BEGIN TIM15_Init 2 */
    
     /* USER CODE END TIM15_Init 2 */
     HAL_TIM_MspPostInit(&htim15);
    
    }
    void MX_SPI3_Init(void)
    {
    
     /* USER CODE BEGIN SPI3_Init 0 */
    
     /* USER CODE END SPI3_Init 0 */
    
     SPI_AutonomousModeConfTypeDef HAL_SPI_AutonomousMode_Cfg_Struct = {0};
    
     /* USER CODE BEGIN SPI3_Init 1 */
    
     /* USER CODE END SPI3_Init 1 */
     hspi3.Instance = SPI3;
     hspi3.Init.Mode = SPI_MODE_MASTER;
     hspi3.Init.Direction = SPI_DIRECTION_2LINES;
     hspi3.Init.DataSize = SPI_DATASIZE_8BIT;
     hspi3.Init.CLKPolarity = SPI_POLARITY_LOW;
     hspi3.Init.CLKPhase = SPI_PHASE_1EDGE;
     hspi3.Init.NSS = SPI_NSS_SOFT;
     hspi3.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
     hspi3.Init.FirstBit = SPI_FIRSTBIT_MSB;
     hspi3.Init.TIMode = SPI_TIMODE_DISABLE;
     hspi3.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
     hspi3.Init.CRCPolynomial = 0x7;
     hspi3.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
     hspi3.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
     hspi3.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
     hspi3.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
     hspi3.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
     hspi3.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
     hspi3.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
     hspi3.Init.IOSwap = SPI_IO_SWAP_DISABLE;
     hspi3.Init.ReadyMasterManagement = SPI_RDY_MASTER_MANAGEMENT_INTERNALLY;
     hspi3.Init.ReadyPolarity = SPI_RDY_POLARITY_HIGH;
     if (HAL_SPI_Init(&hspi3) != HAL_OK)
     {
     Error_Handler();
     }
     HAL_SPI_AutonomousMode_Cfg_Struct.TriggerState = SPI_AUTO_MODE_DISABLE;
     HAL_SPI_AutonomousMode_Cfg_Struct.TriggerSelection = SPI_GRP2_LPDMA_CH0_TCF_TRG;
     HAL_SPI_AutonomousMode_Cfg_Struct.TriggerPolarity = SPI_TRIG_POLARITY_RISING;
     if (HAL_SPIEx_SetConfigAutonomousMode(&hspi3, &HAL_SPI_AutonomousMode_Cfg_Struct) != HAL_OK)
     {
     Error_Handler();
     }
     /* USER CODE BEGIN SPI3_Init 2 */
    
     /* USER CODE END SPI3_Init 2 */
    
    }
    
    void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
    {
    
     GPIO_InitTypeDef GPIO_InitStruct = {0};
     DMA_NodeConfTypeDef NodeConfig= {0};
     RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
     if(spiHandle->Instance==SPI3)
     {
     /* USER CODE BEGIN SPI3_MspInit 0 */
    
     /* USER CODE END SPI3_MspInit 0 */
    
     /** Initializes the peripherals clock
     */
     PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SPI3;
     PeriphClkInit.Spi3ClockSelection = RCC_SPI3CLKSOURCE_SYSCLK;
     if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
     {
     Error_Handler();
     }
    
     /* SPI3 clock enable */
     __HAL_RCC_SPI3_CLK_ENABLE();
    
     __HAL_RCC_GPIOC_CLK_ENABLE();
     /**SPI3 GPIO Configuration
     PC10 ------> SPI3_SCK
     PC11 ------> SPI3_MISO
     PC12 ------> SPI3_MOSI
     */
     GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12;
     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
     GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;
     HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
    
     /* SPI3 DMA Init */
     /* GPDMA1_REQUEST_SPI3_TX Init */
     NodeConfig.NodeType = DMA_GPDMA_LINEAR_NODE;
     NodeConfig.Init.Request = GPDMA1_REQUEST_SPI3_TX;
     NodeConfig.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
     NodeConfig.Init.Direction = DMA_PERIPH_TO_MEMORY;
     NodeConfig.Init.SrcInc = DMA_SINC_INCREMENTED;
     NodeConfig.Init.DestInc = DMA_DINC_FIXED;
     NodeConfig.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;
     NodeConfig.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;
     NodeConfig.Init.SrcBurstLength = 1;
     NodeConfig.Init.DestBurstLength = 1;
     NodeConfig.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0;
     NodeConfig.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
     NodeConfig.Init.Mode = DMA_NORMAL;
     NodeConfig.TriggerConfig.TriggerMode = DMA_TRIGM_SINGLE_BURST_TRANSFER;
     NodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_RISING;
     NodeConfig.TriggerConfig.TriggerSelection = GPDMA1_TRIGGER_TIM15_TRGO;
     NodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;
     NodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;
     if (HAL_DMAEx_List_BuildNode(&NodeConfig, &Node_GPDMA1_Channel0) != HAL_OK)
     {
     Error_Handler();
     }
    
     if (HAL_DMAEx_List_InsertNode(&List_GPDMA1_Channel0, NULL, &Node_GPDMA1_Channel0) != HAL_OK)
     {
     Error_Handler();
     }
    
     if (HAL_DMAEx_List_SetCircularMode(&List_GPDMA1_Channel0) != HAL_OK)
     {
     Error_Handler();
     }
    
     handle_GPDMA1_Channel0.Instance = GPDMA1_Channel0;
     handle_GPDMA1_Channel0.InitLinkedList.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
     handle_GPDMA1_Channel0.InitLinkedList.LinkStepMode = DMA_LSM_FULL_EXECUTION;
     handle_GPDMA1_Channel0.InitLinkedList.LinkAllocatedPort = DMA_LINK_ALLOCATED_PORT0;
     handle_GPDMA1_Channel0.InitLinkedList.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
     handle_GPDMA1_Channel0.InitLinkedList.LinkedListMode = DMA_LINKEDLIST_CIRCULAR;
     if (HAL_DMAEx_List_Init(&handle_GPDMA1_Channel0) != HAL_OK)
     {
     Error_Handler();
     }
    
     if (HAL_DMAEx_List_LinkQ(&handle_GPDMA1_Channel0, &List_GPDMA1_Channel0) != HAL_OK)
     {
     Error_Handler();
     }
    
     __HAL_LINKDMA(spiHandle, hdmatx, handle_GPDMA1_Channel0);
    
     if (HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel0, DMA_CHANNEL_NPRIV) != HAL_OK)
     {
     Error_Handler();
     }
    
     /* SPI3 interrupt Init */
     HAL_NVIC_SetPriority(SPI3_IRQn, 0, 0);
     HAL_NVIC_EnableIRQ(SPI3_IRQn);
     /* USER CODE BEGIN SPI3_MspInit 1 */
    
     /* USER CODE END SPI3_MspInit 1 */
     }
    }
    
    
     uint8_t data[8] = {
    		 0x00, 0x01, 0x02, 0x03,
    		 0x04, 0x05, 0x06, 0x07
     };
     HAL_SPI_Transmit_DMA(&hspi3, data, 8);
    
     TIM15->CCR1 = 20;
     TIM_CCxChannelCmd(htim15.Instance, TIM_CHANNEL_1, TIM_CCx_ENABLE);
     __HAL_TIM_MOE_ENABLE(&htim15);
     HAL_TIM_Base_Start(&htim15);

    scope_3.png

    Green is PWM from timer15, Yellow is SPI sck.

    There is a 150ns delay between Green rising edge and Yellow first rising edge.

    Is it normal? 

    Super User
    April 29, 2025

    How much is that delay in system clocks?

    They may be several sources of delay, all of them add up:

    1. TIM output may be resynchronized with GPDMA clock, as they are on different buses

    2. the DMA will have some internal delays due to the complicated triggering mechanism

    3. there is an arbitration process in the DMA between DMA channels

    4. you appear to use a linked list, DMA has to pick that list from memory (I'm not familiar with the GPDMA in U5 and don't use Cube/HAL so not sure in this)

    5. DMA has to pick data from memory (again, not quite sure if this is not preloaded)

    6. DMA has to store memory to SPI

    7. SPI will have some delay in starting the transmission

    There is a GPDMA-specific appnote, AN5593.

    JW