2024-04-16 12:51 AM
I have implemented a hallinterface (tim 1), to update my pwm timer (tim 8). But the delay i set is rather fluctuating.
Disabling interrupt inside of the tim 1 interrupt did not help. And i think, outside of the interrupt it should not matter, since this is only hardware that is not influenced by software really? At least i would not think that it should fluctuate in a scale of about 2us.
Init of interfacing timer 1:
/**
* Timer for hallsensors (Rotor speed for FOC later)
* Delayed execution of interrupt comes from filter!!!
*/
void initHallTim1AndDriverTim8(){
__disable_irq();
__HAL_RCC_TIM1_CLK_ENABLE();
SET_BIT( TIM1->CR2, TIM_CR2_TI1S); // config all 3 hall signals (PC0-2) via XOR to timer 1
WRITE_REG(TIM1->ARR, 0xFFFF); // Max value (is reset by input signal)
WRITE_REG(TIM1->PSC, TIM1_PRESC - 1); // Mind the 1 that is added in the uC !
SET_BIT( TIM1->CCMR1, TIM_CCMR1_CC1S_0);// |
// TIM_CCMR1_CC2S_0); // channel is configured as input, tim_ic1 is mapped on tim_ti1, etc...
// SET_BIT( TIM1->CCMR2, TIM_CCMR2_CC3S_0); // As above
SET_BIT( TIM1->CCMR1, TIM_CCMR1_OC2M_2 |
TIM_CCMR1_OC2M_1 |
TIM_CCMR1_OC2M_0); // PWM mode 2 - In upcounting, channel 1 is inactive as long as TIMx_CNT<TIMx_CCR1 else active.
SET_BIT( TIM1->CR1, TIM_CR1_CKD_0); // Prescaler (clk/2) for filter and deadtime
SET_BIT( TIM1->CCMR1, TIM_CCMR1_IC1F_1); // filter if needed
SET_BIT( TIM1->CR2, TIM_CR2_MMS_2 |
TIM_CR2_MMS_0); // tim_oc2refc signal is used as trigger output (tim_trgo -> itr0 for timer 8)
SET_BIT( TIM1->DIER, TIM_DIER_CC1IE); // enable interrupt on hall signal (is XOR with 2 and 3
SET_BIT( TIM1->CCER, TIM_CCER_CC1E |
TIM_CCER_CC1NP |
TIM_CCER_CC1P); // capture enable and Rising and falling edge
SET_BIT( TIM1->CR1, TIM_CR1_CEN); // enable counter timer 1
NVIC_SetPriority(TIM1_CC_IRQn, 1); // set highest priority
NVIC_EnableIRQ(TIM1_CC_IRQn); // enable interrupt
// OC1M is preploaded
// slave mod reset input bei tim_ti1f_ed
// capture/compare channel 1 is configured in capture mode, capture signal is tim_trc
initTimer8PWM();
startTimer8();
__enable_irq();
//SET_BIT(TIM1->EGR, TIM_EGR_CC1G); //force interrupt
}
Init of timer 8 for pwm:
void initTimer8PWM(){
__HAL_RCC_TIM8_CLK_ENABLE(); // Enable clock
CLEAR_REG(TIM8->AF1); // Disable BKIN input
CLEAR_REG(TIM8->AF2);
SET_BIT(TIM8->CR1, TIM_CR1_ARPE | // ARR register is bufferd
TIM_CR1_CMS_1 // center aligned up/down (interrupt on counting up - for ADC trigger only?)
);
//TODO: check entries again for pwm
SET_BIT(TIM8->CR2, TIM_CR2_MMS2_3 | TIM_CR2_MMS2_2 | // tim_oc4refc or tim_oc6refc rising edges generate pulses on tim_trgo2 for ADC trigger
TIM_CR2_CCPC | // Preload enable
TIM_CR2_CCUS);
//TIMx_ARR -1 ist max counter
WRITE_REG(TIM8->ARR, PWM_WIDTH); // Counter TOP
// TODO: Prescaler TIMx_PSC
WRITE_REG(TIM8->CCR1, DUTY_TO_PWM(99)); // compare value 1
WRITE_REG(TIM8->CCR2, DUTY_TO_PWM(99)); // compare value 2
WRITE_REG(TIM8->CCR3, DUTY_TO_PWM(99)); // compare value 3
WRITE_REG(TIM8->CCR4, PWM_WIDTH - ADC_TRIG_PRE_COUNT); // compare value 4 (ADC trigger)
SET_BIT(TIM8->CCMR1, TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 | // pwm output compare polarity channel 1 and 2 (pwm mode 1)
TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2M_1 |
TIM_CCMR1_OC1PE | TIM_CCMR1_OC2PE); // preload enable ccr 1 + 2
// Default is OUTPUT !!!
// CC1S = 0 > channel output (CC1 as OUTPUT)
SET_BIT(TIM8->CCMR2, TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3M_1 | // pwm output compare polarity channel 3 and 4 (pwm mode 1)
TIM_CCMR2_OC4M_2 | TIM_CCMR2_OC4M_1 |
TIM_CCMR2_OC3PE | TIM_CCMR2_OC4PE); // preload enable ccr 3 + 4
// Timer 1 trigger out comes in on itr0 (Only trgo is possible!)
//TIM8->SMCR itr0 is default 0!
SET_BIT(TIM8->BDTR, TIM_BDTR_OSSR); // inactive state high or low
CLEAR_BIT(TIM8->CCER, TIM_CCER_CC1P);// oc1 polarity active high
CLEAR_BIT(TIM8->CCER, TIM_CCER_CC2P);// oc2 polarity active high
CLEAR_BIT(TIM8->CCER, TIM_CCER_CC3P);// oc3 polarity active high
}
Timer 1 interrupt:
void TIM1_CC_IRQHandler(){
__disable_irq();
GPIOC->BSRR = (uint32_t) GPIO_PIN_3;
TIM1->CNT = 0;
//GPIOC->BSRR = (uint32_t) GPIO_PIN_3;
// read Capture register (resets interrupt flag)
unsigned long captValue = TIM1->CCR1;
// captValue = TIM1->CCR2;
// captValue = TIM1->CCR3;
lastHallIntervalTics = captValue - lastHallSignalTics; // calc interval
lastHallSignalTics = captValue;
// set (preload) new pwm
// set new CCR2 value (delay for COM -> timer 8)
// It does actually delay +(50-75ns)!
WRITE_REG(TIM1->CCR2, US_TO_TIM1_CLOCK(10));//lastHallIntervalTics)); // Delay value for PWM change trigger
//if(motorRunning)
switchNextState();
//SET_BIT(TIM8->EGR, TIM_EGR_COMG); // update
//printBin(0x48);
//print("TIM1_CC_IRQHandler");
//while(1);
// Tim8?? CLEAR_BIT(TIM8->SR, TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF); // Clear any int flags
// Interrupt flag is reset by reading CCR1 capture register!
GPIOC->BRR = (uint32_t) GPIO_PIN_3;
__enable_irq();
}
Timer 1 prescaler (APB2 85Mhz):
#define TIM1_PRESC 200 // - 1 is subtracted later!
#define NS_TO_TIM1_CLOCK(ns) (85*ns/TIM1_PRESC/1000)
#define US_TO_TIM1_CLOCK(us) (85*us/TIM1_PRESC)
Interrrupt timer 8 (should not matter in this case i tihnk):
void TIM8_TRG_COM_IRQHandler(){
GPIOC->BSRR = (uint32_t) GPIO_PIN_3;
if(! (TIM8->SR & TIM_SR_COMIF)){ // Return if no flag is set (prevents false triggers because of latency in the bus)
__ASM volatile ("NOP");
__ASM volatile ("NOP");
GPIOC->BRR = (uint32_t) GPIO_PIN_3;
return;
}
TIM8->SR = ~TIM_SR_COMIF; // DONT send "&=" ReadModifyWrite is bad!
__ASM volatile ("NOP");
__ASM volatile ("NOP");
GPIOC->BRR = (uint32_t) GPIO_PIN_3;
}
Please find attached the curves:
Yellow curve: First pulse is of timer 1 interrupt. Second + third is Interrupt of timer 8.
Red and blue curve: Outputs of timer 8
Green line: input of timer 1 input cpature
Solved! Go to Solution.
2024-04-16 12:52 AM
While writing this topic, i found the issue myself: The prescaler counter had to be reset too:
TIM1->EGR = TIM_EGR_UG; // reset prescaler counter (through update event)
2024-04-16 12:52 AM
While writing this topic, i found the issue myself: The prescaler counter had to be reset too:
TIM1->EGR = TIM_EGR_UG; // reset prescaler counter (through update event)