Hello, I am trying to get my head around how the Timer0 interrupts work.
I am not posting my code because after many tries it is not quite tidy, but I can post if needed. What I am trying to do is count the RPM of a motor, for this I get an external interrupt that will be activated each time the motor does one revolution. This part is working ok.
I get the time it took to do that revolution with the timer checking TA0R and also checking a counter that will increase each time the timer overflows. This way I can run at high cpu clock for the pwm on H bridge but still measure if the RPM are low. Later, based on the position of the wheel (calculated with how much time it takes to reach that position I toggle an output).
But I am having problems with the timer interrupt. When I debug I can see that TAIFG never gets set, I can see on TA0IV that it has overflowed and I can calculate RPM correctly with this, but my problems come later with toggling the output when the motor reaches desired position.
For this I am trying to enable CCIE on TA0CCTL1 and 2 after an X amount of overflows have occured. For example, my motor took 30 timer overflows to reach one rpm and I want my output to turn on slightly after it has done 180deg. So the TA0CCR interrupt should only happen when Noverflow = 15 and from then on start counting with the timer.
So how can I make CCR interrupts happen only after certain amount of overflows and not always. on TA0IV it would look like each time the timer reaches the CCR value it will activate independently if the TA0CCTL CCIE is set or not.
I feel like my explanation isn't very clear, so if there is something that you do not understand ask and I will try to elaborate more.
for reference, this is my code. In the timer interrupt there are alot of things commented because of what I have been trying to do.
#include <SourceCode/ECU_Motor.h>
#include "gpio.h"
/******************************
******* Definitions **********
*****************************/
#define INTERRUPT_PIN 0x13 //(P1.3)
#define INTERRUPT_BIT (1<<3)
#define SPARK_PIN 0x14 // (P1.4)
/****************************************
******* Variables definition ***********
****************************************/
// Variables for tachometer
// Timer A0 is working at 2MHz
unsigned long int TimeRevolution=0; // Max = 4.294967 seconds (2^32 nanoseconds)
const unsigned long int TimeOverflow = 32768000; // Time in nanooseconds (32.768 miliseconds)
unsigned long int TimerOverflowCounter = 0;
unsigned long int LastTimerOverflowCounter = 0;
unsigned long int N1 = 0; // Overflow counter for Phi 1
unsigned long int N2 = 0; // Overflow counter for Phi 2
unsigned long long int TimePhi1 = 0; // Time at which crankshaft reaches phi1
unsigned long long int TimePhi2 = 0;
const unsigned long int TimePerClock = 500; // Time in nanooseconds (original value 500)
unsigned long long int rpm = 0;
// Variables for Spark Plug
unsigned int phi1 = 230;
unsigned int deltaPhi = 30;
unsigned int phi2 = 260;
/****************************************
******* Functions definition ***********
****************************************/
void Tachometer_Init(void){
gpioMode(INTERRUPT_PIN,INPUT_PULLDOWN); // ver si necesita pullup o pulldown
P1IE |= INTERRUPT_BIT; // Enable external interrupt on pin P1.3
P1IES |= INTERRUPT_BIT;
//Tachometer uses timer A0
// Setup Timer
TA0CTL |= TACLR; //Reset TA0
//TA0CTL |= MC_1; // Set TA0 un UP mode
TA0CTL |= MC_2; // Set TA0 un CONTINOUS mode
TA0CTL |= TASSEL_2 | ID_3; // Select SMCLK and divider /8 -----> (results in 2MHz)
//TA0CCR0 = 65535; // Set period to maximum (0.004096 seconds)
//TA0CCTL0 = CCIE; //Enable timer overflow interrupts for CCR0
TA0CTL |= TAIE;
TA0CTL &= ~TAIFG; // Clear pending interrupt overflow
//_BIS_SR_(GIE); //General interrupt enable
__enable_interrupt(); //General interrupt enable
//TA0CCTL0 &= ~CCIFG; // Clear pending interrupt flag for CCR0
P1IFG &= ~INTERRUPT_BIT; // Clear pending interrupt flag
}
void SparkPlugInit(void){
gpioMode(SPARK_PIN,OUTPUT);
gpioWrite(SPARK_PIN,LOW);
TA0CCTL1 &= ~CCIFG; // Clear pending flag TA0CCR1/2
TA0CCTL1 &= ~CCIFG;
}
void SparkTime(void){ // TimePerRevolution is in nanoseconds
unsigned long int T1 = 0; // Time to set in TA0CCR1
unsigned long int T2 = 0; // Time to set in TA0CCR2
TimePhi1 = (TimeRevolution/360)*phi1; // Time at which crankshaft reaches phi1
TimePhi2 = (TimeRevolution/360)*phi2;
N1 = TimePhi1/TimeOverflow; // Amount of times Timer will overflow before reaching TimePhi1
N2 = TimePhi2/TimeOverflow; // Amount of times Timer will overflow before reaching TimePhi2
T1 = TimePhi1 - N1*TimeOverflow; // Since N1 is an int, here we calculate how much time after final overflow interrupt should happen
T2 = TimePhi2 - N2*TimeOverflow;
TA0CCR1 = T1/TimePerClock; //Each clock pulse are 500 nanoseconds. TA0CCR1 counts clock cycles
TA0CCR2 = T2/TimePerClock;
}
void CheckTimerOverflow (void){
if (TimerOverflowCounter == N1){
TA0CCTL1 &= ~CCIFG;
TA0CCTL1 |= CCIE; // Once correct amount of overflow have occurred, we enable interruptions to count remaining time
}
if (TimerOverflowCounter == N2){
TA0CCTL2 &= ~CCIFG;
TA0CCTL2 |= CCIE; // Once correct amount of overflow have occurred, we enable interruptions to count remaining time
}
}
#pragma vector = PORT1_VECTOR
__interrupt void ISR_External(void){
static int cont=0;
P1IFG &= ~INTERRUPT_BIT; // Clear interrupt flag
/*****************************************************
* Calculation time for 1 revolution. Each time timer overflows (every 0.00005 seconds) TimerOverflowCounter is incremented.
* We use this variable to calculate the time for one revolution
*/
TimeRevolution = TimeOverflow*TimerOverflowCounter + TA0R*TimePerClock; //Time in nanoseconds
TA0CTL |= TACLR;
LastTimerOverflowCounter = TimerOverflowCounter; //We save the last overflow counter for the ignition time of sparkler
TimerOverflowCounter = 0;
rpm=(60000000000)/TimeRevolution; // top is 60 * 1e9 to go from nanoseconds to seconds and revolutions per minute
cont++;
if(cont==1){
rpm++;
cont = 0;
}
SparkTime(); // Calculate ignition times
}
#pragma vector = TIMER0_A0_VECTOR
__interrupt void ISR_TA0_CCR0(void){
//TA0CCTL0 &= ~CCIFG; // Clear interrupt flag CCR0
TA0CTL &= ~TAIFG; // Clear interrupt flag
TimerOverflowCounter++;
}
#pragma vector = TIMER0_A1_VECTOR
__interrupt void ISR_TA0_CCRx(void){
// We have to check if the interrupt occurred because of TA0CCR1 or TA0CCR2 (phi1 or phi2)
//unsigned int TIMER = TA0IV;
if (TA0CTL & TAIFG){
TA0CTL &= ~TAIFG;
TimerOverflowCounter++;
}
/*
switch (__even_in_range(TA0IV, TA0IV_TAIFG)){
case 2:
if (TA0CCTL1 & 0x10){
TA0CCTL1 &= ~CCIE;
P1OUT |= 0x10;
}
break;
case 4:
if (TA0CCTL2 & 0x10){
TA0CCTL2 &= ~CCIE;
P1OUT &= 0x10;
}
break;
case 10:
TimerOverflowCounter++;
break;
}*/
/*
if (TA0CCTL1 == 0x0011){ // I check if the interrupt occurred because of CCR1 (CCIE and CCIFG)
TA0CCTL1 &= ~CCIFG; // Remove interrupt flag
TA0CCTL1 &= ~CCIE; // We have to turn off interruptions (whould only occure when correct ammount of overlfow have occured)
// Turn on spark plug plug (1.4)
P1OUT |= 0x10;
}
if (TA0CCTL2 == 0x0011){ // I check if the interrupt occurred because of CCR2
TA0CCTL2 &= ~CCIFG; // Remove interrupt flag
TA0CCTL2 &= ~CCIE; // Turn off Interriptions
//Turn off spark plug
P1OUT &= ~0x10;
}
if (TIMER & 0x08){
TimerOverflowCounter++;
}*/
}