Search code examples
ctimerinterruptpwmstm32f0

STM32G0 problems with Timer Interrupt PWM doesnt work correctly


I want to use a stm32 to generate a PWM-signal, but i have to be able to change the duty cycle after every signal. My problem is, if i try that it doens't work correctly. It sendes 3-5 pulses with the same duty cycle and after that it changes the value. I don't understand why it doen's change it after every pulse. And there is an other problem, I have to re-enable the CCER-bit for the channel after every pulse or it doenst work it get reset for any reason.

I'm using the STM32G071 Nucleo-64 Board, with Keil uVision 5

I generated the start with STM32CubeMX and added my code so it would work, but it doesnt. I don't know what to do diffrent. I would be glad for some advice.

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define HIGH_PWM_SIGNAL     70//( 45 )
#define LOW_PWM_SIGNAL      10//( 27 )

/* USER CODE END PD */

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

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
TIM_HandleTypeDef htim3;

/* USER CODE BEGIN PV */
uint8_t PWM_Count = 0;

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM3_Init(void);
static void MX_NVIC_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 */

  /* 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();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM3_Init();

  /* Initialize interrupts */
  MX_NVIC_Init();
  /* USER CODE BEGIN 2 */

    HAL_TIM_Base_Start_IT( &htim3 );
    HAL_TIM_PWM_Start_IT( &htim3, TIM_CHANNEL_1 );

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {


    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  // STM32CUbeMX generated deleted for readablitity
}

/**
  * @brief NVIC Configuration.
  * @retval None
  */
static void MX_NVIC_Init(void)
{
  /* TIM3_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(TIM3_IRQn, 1, 0);
  HAL_NVIC_EnableIRQ(TIM3_IRQn);
}

/**
  * @brief TIM3 Initialization Function
  * @param None
  * @retval None
  */
static void MX_TIM3_Init(void)
{

  /* USER CODE BEGIN TIM3_Init 0 */
    HAL_TIM_Base_DeInit( &htim3 );
    HAL_TIM_PWM_DeInit( &htim3 );

  /* USER CODE END TIM3_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};

  /* USER CODE BEGIN TIM3_Init 1 */

  /* USER CODE END TIM3_Init 1 */
  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 0;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 80;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 10;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_ENABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM3_Init 2 */
    HAL_NVIC_SetPriority( TIM3_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ( TIM3_IRQn );
    // Update interrupt
    HAL_TIM_GenerateEvent( &htim3, TIM_EVENTSOURCE_UPDATE );
    // PWM interrupt
    HAL_TIM_GenerateEvent( &htim3, TIM_EVENTSOURCE_CC1 );

  /* USER CODE END TIM3_Init 2 */
  HAL_TIM_MspPostInit(&htim3);

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  // STM32CUbeMX generated deleted for readablitity
}

/* USER CODE BEGIN 4 */
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim){

       // Change PWM Duty Cycle

    PWM_Count += 1;
    if ( PWM_Count > 1 ) 
        PWM_Count = 0;

    if ( PWM_Count == 0 ) TIM3->CCR1  = LOW_PWM_SIGNAL;
    else    TIM3->CCR1  = HIGH_PWM_SIGNAL;

}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){ 

   // I have to re enable it or it doesn't output anything

   TIM_CCxChannelCmd(htim3.Instance, TIM_CHANNEL_1, TIM_CCx_ENABLE);


}
/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */

  /* USER CODE END Error_Handler_Debug */
}

It doesnt change the duty cycle for every singal it needs around 3-5 signales and then it changes the duty cycle. Oscilloscope: Output PWM Channel1


Solution

  • I found the solution. I was using the lib "stm32g0xx_hal_tim.c", which was quite handy. But it used up to much time.

    It is build to work for every problem and checks therefore everything (all interrupt flags). This are many if else's which take some time.

    I programmed it myself that it only checks what i need and then it worked.

    Thank you for your help.