generando un ciclo de trabajo diferente en dos pines diferentes del mismo temporizador pwm STM32 Nucleo

0

Utilicé STCube para generar mi código para obtener un ciclo de trabajo diferente en dos pines diferentes del mismo temporizador en mi tablero Nucleo F446ZE. Funciona en su mayor parte, ambos pines tienen la misma frecuencia pero ambos tienen el mismo ciclo de trabajo, el ciclo de trabajo que configuré como PULSE1_VALUE. He intentado varias cosas, incluido el intento de replicar el código de ejemplo para las salidas PWM que venían con la placa F446Ze, pero parece que mi pin TIM_CHANNEL_2 no puede alternar en un ciclo de trabajo diferente. Aquí está el código relevante:

/* Private variables      ---------------------------------------------------------*/
TIM_HandleTypeDef htim2;

/* Private typedef -----------------------------------------------------------*/
#define  PERIOD_VALUE       (uint32_t)(661-1)  /* Period Value  */ counter clock of 15MHz and period of 660 gives a frequency of 22.7kHz
#define  PULSE1_VALUE       (uint32_t)(PERIOD_VALUE*12.5/100)        /*    Capture Compare 1 Value  12.5% duty */
#define  PULSE2_VALUE       (uint32_t)(PERIOD_VALUE*1/100) /* Capture  Compare 2 Value  1%duty*/

TIM2 init function

static void MX_TIM2_Init(void)
{
  uhPrescalerValue = (uint32_t)((SystemCoreClock/2)/15000000)-1; //this gives a counter frequency of 15MHz. SystemCoreClock is 180MHz
  TIM_ClockConfigTypeDef sClockSourceConfig;
  TIM_SlaveConfigTypeDef sSlaveConfig;
  TIM_MasterConfigTypeDef sMasterConfig;
  TIM_OC_InitTypeDef sConfigOC;
  memset(&sConfigOC, 0, sizeof(sConfigOC));
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = uhPrescalerValue;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = PERIOD_VALUE; //660 in this case
  htim2.Init.ClockDivision = 0;

  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }

  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }

  if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }


  sSlaveConfig.SlaveMode = TIM_SLAVEMODE_DISABLE;
  sSlaveConfig.InputTrigger = TIM_TS_ITR0;
  if (HAL_TIM_SlaveConfigSynchronization(&htim2, &sSlaveConfig) != HAL_OK)
  {
    Error_Handler();
  }

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }

  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_ENABLE;//TIM_OCFAST_DISABLE;
  sConfigOC.OCNPolarity  = TIM_OCNPOLARITY_HIGH;
  //sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
  sConfigOC.OCIdleState  = TIM_OCNIDLESTATE_SET;//TIM_OCIDLESTATE_RESET;

  sConfigOC.Pulse = PULSE1_VALUE;
  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }

  sConfigOC.Pulse = PULSE2_VALUE;
  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  {
    Error_Handler();
  }
  /* Peripheral clock enable */

  HAL_TIM_MspPostInit(&htim2);
  //HAL_TIM_Base_Start(&htim2);

  /*##-3- Start PWM signals generation #######################################*/
   /* Start channel 1 */
   if (HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1) != HAL_OK)
   {
     /* PWM Generation Error */
     Error_Handler();
   }


   /* Start channel 2 */
   if (HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2) != HAL_OK)
   {
     /* PWM Generation Error */
     Error_Handler();
   }


}

Estoy pensando que podría ser algo con la forma en que estoy configurando el GPIO para los dos pines que quiero controlar en el archivo stm32f4xx_hal_msp.c pero he visto a otras personas configurarlo exactamente de la misma manera otros sitios: enlace

void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim)
{

  GPIO_InitTypeDef GPIO_InitStruct;
  if(htim->Instance==TIM2)
  {
  /* USER CODE BEGIN TIM2_MspPostInit 0 */

      /* TIMx Peripheral clock enable */
      //TIMx_CLK_ENABLE();
  /* USER CODE END TIM2_MspPostInit 0 */

    /**TIM2 GPIO Configuration    
    PA0-WKUP     ------> TIM2_CH1
    PA1     ------> TIM2_CH2 
    */
    GPIO_InitStruct.Pin = ext_LED_1_Pin|ext_LED_2_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* USER CODE BEGIN TIM2_MspPostInit 1 */

  /* USER CODE END TIM2_MspPostInit 1 */
  }

}
    
pregunta prontz

1 respuesta

0

No es HAL ya que no uso este software de relleno. Es para la serie F3 pero los temporizadores son casi idénticos. Puede cambiar la frecuencia y amp; PWM duty ön the fly: simplemente asigne las variables con los valores correctos y habilite el indicador de interrupción de desbordamiento (es decir, tim - > DIER | = TIM_DIER_UIE;)  :

Para cambiar los valores, puede usar el modo de ráfaga DMA con temporizador pero la lógica es un poco más complicada (normalmente lo hago de esta manera en mis proyectos)

void InitTimerPWM(TIM_TypeDef *tim int channel)
{
    if(!(tim -> CR1 & TIM_CR1_CEN)
    {
        tim -> CR1 |= TIM_CR1_ARPE;
        if(tim != TIM2 && tim != TIM3 && tim != TIM4) __SetVaueIfDifferent((void *)&tim -> BDTR , TIM_BDTR_MOE, TIM_BDTR_MOE);
    }

    switch(channel)
    {
    case CH1:
        __SetVaueIfDifferent((void *)&tim -> CCMR1, TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1PE, TIM_CCMR1_OC1M_Msk | TIM_CCMR1_OC1PE);
        __SetVaueIfDifferent((void *)&tim -> CCER, TIM_CCER_CC1E, TIM_CCER_CC1E);
        break;
    case CH2:
        __SetVaueIfDifferent((void *)&tim -> CCMR1, TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2PE, TIM_CCMR1_OC2M_Msk |  TIM_CCMR1_OC2PE);
        __SetVaueIfDifferent((void *)&tim -> CCER, TIM_CCER_CC2E, TIM_CCER_CC2E);
        break;
    case CH3:
        __SetVaueIfDifferent((void *)&tim -> CCMR2, TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3PE, TIM_CCMR2_OC3M_Msk |  TIM_CCMR2_OC3PE);
        __SetVaueIfDifferent((void *)&tim -> CCER, TIM_CCER_CC3E, TIM_CCER_CC3E);
        break;
    case CH4:
        __SetVaueIfDifferent((void *)&tim -> CCMR2, TIM_CCMR2_OC4M_1 | TIM_CCMR2_OC4M_2 | TIM_CCMR2_OC4PE, TIM_CCMR2_OC4M_Msk |  TIM_CCMR2_OC4PE);
        __SetVaueIfDifferent((void *)&tim -> CCER, TIM_CCER_CC4E, TIM_CCER_CC4E);
        break;
    default:
        break;

    }
}

void StartTimer(TIM_TypeDef *tim)
{
    if(!(tim -> CR1 & TIM_CR1_CEN))
    {
        tim -> CNT = 0;
        tim -> ARR = ARR;  // table with the reload values if you need t
        tim -> PSC = PSC;
        tim -> DIER |= TIM_DIER_UIE;
        tim -> EGR |= TIM_EGR_UG;
        tim -> CR1 |= TIM_CR1_CEN;
    }
}


void  __SetVaueIfDifferent(void *ptrx, uint32_t value, uint32_t mask) {
    uint32_t *ptr = ptrx;
    uint32_t target = *ptr;
    if(mask)
    {
        if((target & mask) == value)
            return;
        target &= ~mask;
        target |= value;
    }
    *ptr = target;
}

#define INLINE inline  __attribute__((always_inline))

static INLINE void PWMHandler(volatile TIM_TypeDef *tim)
{
    if(tim -> SR & TIM_SR_UIF & tim -> DIER)
    {
        tim -> SR &= ~(TIM_SR_UIF);
        tim -> DIER &= ~TIM_DIER_UIE;
        tim -> PSC = PSC;
        tim -> ARR = ARR;
        tim -> CCR1 = CCR1; //id timer has more or less channels just add couple of the lines and the if
        tim -> CCR2 = CCR2;
        tim -> CCR3 = CCR3;
        tim -> CCR4 = CCR4; 
    }
}

/* and example handler*/

void TIM3_IRQHandler(void)
{
    PWMHandler(TIM3);
}
    
respondido por el P__J__

Lea otras preguntas en las etiquetas