cancel
Showing results for 
Search instead for 
Did you mean: 

STM32U5 Triggering DMA request from timer to write to GPIOD ODR register

clemens
Associate

Hi,

I am experimenting with the STM32U5G9J-DK2 discovery kit and want to use one of the basic timers to regularly trigger a memory-to-peripheral DMA request to write different values into the GPIOD ODR register.

I set up TIM7 to trigger about every 1s and connected it to GPDMA channel 5 which is set up as memory-to-peripheral transfer on TIM_DMA_ID_UPDATE. I start the DMA to write values of an array (~RED_LED_Pin, ~GREEN_LED_Pin) into the ODR register of GPIOD to alternate those two LEDs on the discovery board every second.

When I disable circular mode in the GPDMA channel, it works exactly once. (First the red LED lights up and then after 1s the red LED turns off and the green LED turns on and stays on)

But as I want this to repeat itself, I tried to enable circular DMA mode. In that case however, both LEDs stay dark. Nothing is ever written into the ODR register.

 

Maybe someone has an idea what the cause of the problem could be. Thank you in advance!

 

These are the relevant parts in main.c

 

 

uint8_t data[] = {~RED_LED_Pin, ~GREEN_LED_Pin}; /* Active low outputs */

/* ... */

static 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_Channel5_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(GPDMA1_Channel5_IRQn);

  /* USER CODE BEGIN GPDMA1_Init 1 */

  /* USER CODE END GPDMA1_Init 1 */
  /* USER CODE BEGIN GPDMA1_Init 2 */

  /* USER CODE END GPDMA1_Init 2 */
}

static void MX_TIM7_Init(void)
{
  /* USER CODE BEGIN TIM7_Init 0 */

  /* USER CODE END TIM7_Init 0 */

  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM7_Init 1 */

  /* USER CODE END TIM7_Init 1 */
  htim7.Instance = TIM7;
  htim7.Init.Prescaler = 63999;
  htim7.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim7.Init.Period = 2499;
  htim7.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim7) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim7, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM7_Init 2 */
  HAL_TIM_Base_Start(&htim7);
  HAL_DMA_Start(&handle_GPDMA1_Channel5, (uint32_t)data, (uint32_t)&GPIOD->ODR, 2);
  __HAL_TIM_ENABLE_DMA(&htim7, TIM_DMA_UPDATE);
  /* USER CODE END TIM7_Init 2 */
}

 

 

 And here the parts in stm32u5xx_hal_msp.c (when I enable circular mode):

 

 

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{
  DMA_NodeConfTypeDef NodeConfig;
  if(htim_base->Instance==TIM7)
  {
  /* USER CODE BEGIN TIM7_MspInit 0 */

  /* USER CODE END TIM7_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_TIM7_CLK_ENABLE();

    /* TIM7 DMA Init */
    /* GPDMA1_REQUEST_TIM7_UP Init */
    NodeConfig.NodeType = DMA_GPDMA_LINEAR_NODE;
    NodeConfig.Init.Request = GPDMA1_REQUEST_TIM7_UP;
    NodeConfig.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
    NodeConfig.Init.Direction = DMA_MEMORY_TO_PERIPH;
    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.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;
    NodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;
    NodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;
    if (HAL_DMAEx_List_BuildNode(&NodeConfig, &Node_GPDMA1_Channel5) != HAL_OK)
    {
      Error_Handler();
    }

    if (HAL_DMAEx_List_InsertNode(&List_GPDMA1_Channel5, NULL, &Node_GPDMA1_Channel5) != HAL_OK)
    {
      Error_Handler();
    }

    if (HAL_DMAEx_List_SetCircularMode(&List_GPDMA1_Channel5) != HAL_OK)
    {
      Error_Handler();
    }

    handle_GPDMA1_Channel5.Instance = GPDMA1_Channel5;
    handle_GPDMA1_Channel5.InitLinkedList.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
    handle_GPDMA1_Channel5.InitLinkedList.LinkStepMode = DMA_LSM_FULL_EXECUTION;
    handle_GPDMA1_Channel5.InitLinkedList.LinkAllocatedPort = DMA_LINK_ALLOCATED_PORT0;
    handle_GPDMA1_Channel5.InitLinkedList.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
    handle_GPDMA1_Channel5.InitLinkedList.LinkedListMode = DMA_LINKEDLIST_CIRCULAR;
    if (HAL_DMAEx_List_Init(&handle_GPDMA1_Channel5) != HAL_OK)
    {
      Error_Handler();
    }

    if (HAL_DMAEx_List_LinkQ(&handle_GPDMA1_Channel5, &List_GPDMA1_Channel5) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(htim_base, hdma[TIM_DMA_ID_UPDATE], handle_GPDMA1_Channel5);

    if (HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel5, DMA_CHANNEL_NPRIV) != HAL_OK)
    {
      Error_Handler();
    }

    /* TIM7 interrupt Init */
    HAL_NVIC_SetPriority(TIM7_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(TIM7_IRQn);
  /* USER CODE BEGIN TIM7_MspInit 1 */

  /* USER CODE END TIM7_MspInit 1 */
  }
}

 

 

 

1 ACCEPTED SOLUTION

Accepted Solutions
clemens
Associate

Hi @Sarra.S ,

Thank you for your response. I found the problem: I used HAL_DMA_Start.

It works if I use HAL_DMAEx_List_Start and instead of passing the source/destination address, etc. as arguments, I set it on the NodeConfig as follows:

/* USER CODE BEGIN TIM7_MspInit 0 */
NodeConfig.SrcAddress = (uint32_t)data;
NodeConfig.DstAddress = (uint32_t)&GPIOD->ODR;
NodeConfig.DataSize = 2;
/* USER CODE END TIM7_MspInit 0 */

 

View solution in original post

2 REPLIES 2
Sarra.S
ST Employee

Hello @clemens

Could you re-configure DMA in circular mode and check for DMA's current state and errors in the DMA status register 

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

clemens
Associate

Hi @Sarra.S ,

Thank you for your response. I found the problem: I used HAL_DMA_Start.

It works if I use HAL_DMAEx_List_Start and instead of passing the source/destination address, etc. as arguments, I set it on the NodeConfig as follows:

/* USER CODE BEGIN TIM7_MspInit 0 */
NodeConfig.SrcAddress = (uint32_t)data;
NodeConfig.DstAddress = (uint32_t)&GPIOD->ODR;
NodeConfig.DataSize = 2;
/* USER CODE END TIM7_MspInit 0 */