2024-01-05 04:32 PM
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);
}
Solved! Go to Solution.
2024-01-05 06:01 PM
Set the MOE bit in TIM15_BDTR.
2024-01-05 06:01 PM
Set the MOE bit in TIM15_BDTR.