Skip to main content
Explorer
January 6, 2024
Solved

STM32H747 fails to generate PWM using some timers

  • January 6, 2024
  • 1 reply
  • 1536 views

I have an Arduino Giga (STM32H7), and I'm trying to generate PWM's. I succeeded using alternate function AF9 of PA7 (digital pin 5), which uses TIM14_CH1. Now, using the exact same code (as far as I can see) but using PA2/PA3 (digital pins 3 and 2) and alternate function AF4 (which use TIM15_CH1/2) I don't get any output for those pins. TIM15 does turn on though, i.e., it starts counting and restarts at the appropriate time.

Even setting TIMx_CCMR1_OCxM to 0x5UL ("Force active level - OC1REF is forced high.") doesn't work for TIM15. I've also tried using TIM16 (which uses GPIOB), which I couldn't get to work either, which is weird because the functionality is identical to that of TIM14. I'm a bit new to this and I feel like I'm missing something obvious, so any help is greatly appreciated!

 

 

 

 

int VolRepTime = 11000; // Time to acquire one volume, in microseconds.
int Laser1UpTime = 8000; // Time Laser1 trigger should stay up, in microseconds.
int Laser2UpTime = 5000; // Time Laser2 trigger should stay up, in microseconds.
int Laser3UpTime = 4000; // Time Laser3 trigger should stay up, in microseconds.

void setup()
{
 Serial.begin(115200);
 while (!Serial);
 
 initTimers();
 initPins();

 Trigger1(Laser1UpTime, VolRepTime);
 Trigger2(Laser2UpTime, VolRepTime); 
 Trigger3(Laser3UpTime, VolRepTime);

}


void initTimers(){

 RCC->APB1LENR |= RCC_APB1LENR_TIM14EN; // Enable use of TIM14
 RCC->APB2ENR |= RCC_APB2ENR_TIM15EN; // Enable use of TIM15

 // Set PWM mode.
 TIM14->CCMR1 |= ( 0x6UL << TIM_CCMR1_OC1M_Pos ); // PWM mode 1 - Channel 1 is active as long as TIMx_CNT < TIMx_CCR1 else inactive.
 TIM15->CCMR1 |= ( 0x6UL << TIM_CCMR1_OC1M_Pos ); // PWM mode 1 - Channel 1 is active as long as TIMx_CNT < TIMx_CCR1 else inactive.
 TIM15->CCMR1 |= ( 0x6UL << TIM_CCMR1_OC2M_Pos ); // PWM mode 1 - Channel 2 is active as long as TIMx_CNT < TIMx_CCR1 else inactive.
 

 TIM14->CCER |= TIM_CCER_CC1E; // Enables Capture/Compare for Channel 1.
 TIM15->CCER |= TIM_CCER_CC1E; // Enables Capture/Compare for Channel 1.
 TIM15->CCER |= TIM_CCER_CC2E; // Enables Capture/Compare for Channel 2.

 TIM14->DIER |= ( TIM_DIER_CC1IE | TIM_DIER_UIE ); // Update and Capture/Compare interrupts enabled
 TIM14->SR &= ~( TIM_SR_CC1IF | TIM_SR_UIF ); // Clear the interrupts

 TIM15->DIER |= ( TIM_DIER_CC1IE | TIM_DIER_UIE ); 
 TIM15->SR &= ~( TIM_SR_CC1IF | TIM_SR_UIF ); 
 TIM15->DIER |= ( TIM_DIER_CC2IE | TIM_DIER_UIE ); 
 TIM15->SR &= ~( TIM_SR_CC2IF | TIM_SR_UIF ); 

}



void initPins(){
 // Enables GPIOA. Gives access to digital pins 2, 3 and 5.
 RCC->AHB4ENR |= RCC_AHB4ENR_GPIOAEN;

 // Digital port = microcontroller port - [ModeRegisterBits]:
 // D2 = PA3 - [6 7]
 // D3 = PA2 - [4 5]
 // D5 = PA7 - [14 15]
 
 // For Alternate function mode set bits to 10.
 // Set bits manually for now... (FIX ME)

 GPIOA->MODER = 0b10101011111111111011111110101111;
 


 // See page 89 of Datasheet.
 // Digital port = microcontroller port -> Alternate function - Corresponding timer
 // D2 = PA3-> AF4 - TIM15_CH2;
 // D3 = PA2-> AF4 - TIM15_CH1;
 // D5 = PA7-> AF9 - TIM14_CH1;

 // Set which alternate function each port should use.
 GPIOA->AFR[0] |= ( 0x4UL << 12); // AF4 at AFR3
 GPIOA->AFR[0] |= ( 0x4UL << 8); // AF4 at AFR2
 GPIOA->AFR[0] |= ( 0x9UL << 28); // AF9 at AFR7

}


void Trigger1(int UpTime, int VolRepTime){
 TIM14->PSC = 240-1; // Prescaler set so that 1 tick is 1 microsecond.
 TIM14->ARR = VolRepTime-1; // Counter resets after reaching this value.
 TIM14->CCR1 = UpTime; // Compare Register: Signal goes down after this time. 
}

void Trigger2(int UpTime, int VolRepTime){
 TIM15->PSC = 240-1; 
 TIM15->ARR = VolRepTime-1; 
 TIM15->CCR1 = UpTime; 
}

void Trigger3(int UpTime, int VolRepTime){
 TIM15->PSC = 240-1; 
 TIM15->ARR = VolRepTime-1; 
 TIM15->CCR2 = UpTime; 
}



void onoff(){
 // Turns TIM14/TIM15 on and off.
 TIM14->CR1 ^= TIM_CR1_CEN; 
 TIM15->CR1 ^= TIM_CR1_CEN;

}


void loop()
{
 delay(1000);
 
 if(Serial.read()!=-1){
 onoff();
 }
 Serial.println(TIM15->CNT);
}

 

 

 

 

    This topic has been closed for replies.
    Best answer by TDK

    Set the MOE bit in TIM15_BDTR.

    1 reply

    TDKAnswer
    Super User
    January 6, 2024

    Set the MOE bit in TIM15_BDTR.