cancel
Showing results for 
Search instead for 
Did you mean: 

multiple TIM1 channels dutycycle update single DMA

RaulPosada
Associate II

I'm trying to update the duty cycle of 3 channels of timer 1 simultaneously with just one DMA event.

 

RaulPosada_1-1717988792782.png

 

RaulPosada_2-1717990104114.png

 

1 ACCEPTED SOLUTION

Accepted Solutions
Sarra.S
ST Employee

Hello @RaulPosada

In the TIM2_IRQHandler, your code attempts to directly assign values to the DMA channel's Control Register (CCR):

DMA1_Channel4->CCR = a * fasea[theta];
DMA1_Channel5->CCR = a * faseb[theta];
DMA1_Channel6->CCR = a * fasec[theta];

 This is not the correct way to update the duty cycle of the PWM channels. The CCR of the timer channels should be updated with the duty cycle values, not the DMA channel's CCR. The DMA channel's CCR is used to configure the DMA channel itself, not to transfer data.

Also, the variable "theta" that you're declaring, needs to be a valid index within the bounds of the arrays

I suppose it represents an angle,in this case it needs to stay within the range of 0 to 359, which corresponds to the valid indices for the arrays.

So, theta needs to be properly defined, initialized, and updated somewhere in your code

Also, this line is not clear to me: 

a=(((1/((Wref/4096)*10))/360)/150000000);

 

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.

View solution in original post

4 REPLIES 4
Sarra.S
ST Employee

Hello @RaulPosada, welcome to ST community, 

Yes, you can use the DMA burst mode to update multiple Capture/Compare Registers (CCRs) of a single timer simultaneously with one DMA request, which is triggered by the timer's update event.

If you need more details on burst mode, you can refer to the Timer cookbook AN4776

Otherwise, can you be more specific about your question? what's working and what's not... maybe include a code snippet using </> 

 

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.

RaulPosada
Associate II

In the image above, there's a section marked in blue, which is what I'd like to implement using DMA. Below, I attempted a different approach but without success.

RaulPosada_1-1718037332205.png

 

Here is my stm32g4xx_it.c 

 

 

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32g4xx_it.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN TD */

/* USER CODE END TD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
uint32_t Wref=0;
uint32_t Ishunt=0;
int flagTim3=0;
int theta;
int a=0;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/* External variables --------------------------------------------------------*/
extern DMA_HandleTypeDef hdma_adc1;
extern DMA_HandleTypeDef hdma_cordic_read;
extern DMA_HandleTypeDef hdma_cordic_write;
extern DMA_HandleTypeDef hdma_tim1_ch1;
extern DMA_HandleTypeDef hdma_tim1_ch2;
extern DMA_HandleTypeDef hdma_tim1_ch3;
extern TIM_HandleTypeDef htim2;
extern TIM_HandleTypeDef htim3;
/* USER CODE BEGIN EV */
extern ADC_HandleTypeDef hadc1;
extern ADC_HandleTypeDef hadc2;
extern float fasea;
extern float faseb;
extern float fasec;
/* USER CODE END EV */
void TIM2_IRQHandler(void)
{
  /* USER CODE BEGIN TIM2_IRQn 0 */

  /* USER CODE END TIM2_IRQn 0 */
  HAL_TIM_IRQHandler(&htim2);
  /* USER CODE BEGIN TIM2_IRQn 1 */

  DMA1_Channel4->CCR=a*fasea[theta];
  DMA1_Channel5->CCR=a*faseb[theta];
  DMA1_Channel6->CCR=a*fasec[theta];

  /* USER CODE END TIM2_IRQn 1 */
}

/**
  * @brief This function handles TIM3 global interrupt.
  */
void TIM3_IRQHandler(void)
{
  /* USER CODE BEGIN TIM3_IRQn 0 */

  /* USER CODE END TIM3_IRQn 0 */
  HAL_TIM_IRQHandler(&htim3);
  /* USER CODE BEGIN TIM3_IRQn 1 */
  HAL_ADC_Start_DMA(&hadc1, &Ishunt, 1);
  flagTim3++;

  if(flagTim3==1000){
  HAL_ADC_Start_DMA(&hadc2, &Wref, 1);
  a=(((1/((Wref/4096)*10))/360)/150000000);
  TIM2->ARR=a; //Update the period for update interrupt on timer2
  TIM2->CNT=0;
  flagTim3=0;
  }

  /* USER CODE END TIM3_IRQn 1 */
}

 

 

 

my main.c follows:

 

 

 
/* Private variables ---------------------------------------------------------*/
ADC_HandleTypeDef hadc1;
ADC_HandleTypeDef hadc2;
DMA_HandleTypeDef hdma_adc1;

CORDIC_HandleTypeDef hcordic;
DMA_HandleTypeDef hdma_cordic_read;
DMA_HandleTypeDef hdma_cordic_write;

FMAC_HandleTypeDef hfmac;

OPAMP_HandleTypeDef hopamp1;

TIM_HandleTypeDef htim1;
TIM_HandleTypeDef htim2;
TIM_HandleTypeDef htim3;
DMA_HandleTypeDef hdma_tim1_ch1;
DMA_HandleTypeDef hdma_tim1_ch2;
DMA_HandleTypeDef hdma_tim1_ch3;

DMA_HandleTypeDef hdma_dma_generator0;
/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_DMA_Init(void);
static void MX_GPIO_Init(void);
static void MX_ADC1_Init(void);
static void MX_OPAMP1_Init(void);
static void MX_TIM1_Init(void);
static void MX_ADC2_Init(void);
static void MX_CORDIC_Init(void);
static void MX_TIM3_Init(void);
static void MX_TIM2_Init(void);
static void MX_FMAC_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */
	HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
	HAL_ADCEx_Calibration_Start(&hadc2, ADC_SINGLE_ENDED);
	HAL_TIM_Base_Start_IT(&htim3);
	HAL_TIM_Base_Start_IT(&htim2);

	float fasea[360];
	float faseb[360];
	float fasec[360];
	int i = 0;

	for (i = 0; i < 360; ++i) {

		fasea[i]= ( 0.4715 + 0.5*( (sin((i)/57.29578)) + (sin(3*(i)/57.29578))/3) );
		faseb[i]= ( 0.4715 + 0.5*( (sin((120+i)/57.29578)) + (sin(3*(120+i)/57.29578))/3) );
		fasec[i]= ( 0.4715 + 0.5*( (sin((-120+i)/57.29578)) + (sin(3*(-120+i)/57.29578))/3) );


	}

  /* USER CODE END 1 */

 

 

 

Hello there, Sarra.S! Thank you for your answer. I have updated the post with some code snippets.

Sarra.S
ST Employee

Hello @RaulPosada

In the TIM2_IRQHandler, your code attempts to directly assign values to the DMA channel's Control Register (CCR):

DMA1_Channel4->CCR = a * fasea[theta];
DMA1_Channel5->CCR = a * faseb[theta];
DMA1_Channel6->CCR = a * fasec[theta];

 This is not the correct way to update the duty cycle of the PWM channels. The CCR of the timer channels should be updated with the duty cycle values, not the DMA channel's CCR. The DMA channel's CCR is used to configure the DMA channel itself, not to transfer data.

Also, the variable "theta" that you're declaring, needs to be a valid index within the bounds of the arrays

I suppose it represents an angle,in this case it needs to stay within the range of 0 to 359, which corresponds to the valid indices for the arrays.

So, theta needs to be properly defined, initialized, and updated somewhere in your code

Also, this line is not clear to me: 

a=(((1/((Wref/4096)*10))/360)/150000000);

 

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.