cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H747 fails to generate PWM using some timers

Pepijn
Associate II

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);
}

 

 

 

 

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Guru

Set the MOE bit in TIM15_BDTR.

If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

1 REPLY 1
TDK
Guru

Set the MOE bit in TIM15_BDTR.

If you feel a post has answered your question, please click "Accept as Solution".