#include #include //..... #define LED_OUTPUT_PIN BIT0 #define HALL_INPUT BIT2 //CCI1A #define TEST_OUT BIT3 #define LED_2_PIN BIT6 #define SPARK_DRIVE BIT1 #define SPARK_DRIVE_DIR P2DIR #define SPARK_DRIVE_SEL P2SEL #define PIN1_4 BIT4 //timer interrupt flags #define TAFCC1 0x02 #define TACOV 0x0a //Convenience #define TOGGLE_LED_RED (P1OUT^= LED_OUTPUT_PIN); #define SET_LED_RED (P1OUT|= LED_OUTPUT_PIN); #define CLEAR_LED_RED (P1OUT&= ~LED_OUTPUT_PIN); #define TOGGLE_LED_GREEN (P1OUT^= LED_2_PIN); #define SET_LED_GREEN (P1OUT|= LED_2_PIN); #define CLEAR_LED_GREEN (P1OUT&= ~LED_2_PIN); #define TOGGLE_TEST_PIN_1_3 (P1OUT^= TEST_OUT); #define SET_TEST_PIN_1_3 (P1OUT|= TEST_OUT); #define CLEAR_TEST_PIN_1_3 (P1OUT&= ~TEST_OUT); //state #define STATE_NULL 0x0000 #define STATE_MODE_MASK 0x000f #define STATE_DWELL_CALC 0x0001 #define STATE_TIMEOUT 0x0002 //none pump flags #define STATE_TIMEOUT2 0x0010 #define STATE_ADD_SPARK 0x0020 //now into timing and need spark now; Two sparks/cycle #define STATE_PENDNING 0x0040 //a spark has been scheduled #define STATE_TRIGGERED 0x0080 // #define STATE_IN_SPARK 0x0100 //currently charging the coil //variables uint16_t usi_watchdog; uint16_t state; uint16_t test; uint32_t last_dwell; uint16_t dwell_time; uint16_t dwell_time_calc; uint16_t ta0iv_val; uint32_t adjust; uint16_t green_flash; //constants #define CHARGE_TIME ( 3000 / 2 )// ID_1 #define MIN_DWELL 30//so as a few counts before TA1TCR hits // ..................................................... //#define NO_WATCHDOG //#define WD_AS_TIMER // ..................................................... int main(void) { #ifdef NO_WATCHDOG WDTCTL = WDTPW | WDTHOLD; #elif defined( WD_AS_TIMER ) WDTCTL = WDTPW | WDTHOLD; WDTCTL= WDT_MDLY_0_5; //.5ms smclk #else //One second interrupts using watch crystal. WDTCTL= WDT_ADLY_250; //WDTCTL= WDTHOLD; usi_watchdog= 0; //enable the watchdog interrupt IE1= WDTIE; #endif state= STATE_NULL; //16Mhz clock BCSCTL1 = CALBC1_1MHZ; // Set range DCOCTL = CALDCO_1MHZ; // SMCLK = DCO = 1MHz //LED and TEST_OUT, etc..... P1DIR|= LED_OUTPUT_PIN | TEST_OUT | LED_2_PIN | PIN1_4; SET_LED_GREEN //Hall input P1SEL|= HALL_INPUT; //also capture Hall on edge P1IES= HALL_INPUT; //using red to catch false interrupts CLEAR_LED_RED; CLEAR_LED_GREEN //Output for the spark connect to T1TCC1; P2.1 SPARK_DRIVE_DIR|= SPARK_DRIVE; SPARK_DRIVE_SEL|= SPARK_DRIVE; //timer to capture Hall input on P1.1 // SMCLK div/2 cnt_up clear interrupt enabled TA0CTL= TASSEL_2 | ID_1 | MC_2 | TACLR | TAIE; //capture hall trigger TA0CCTL1= CM_2 | CCIS_0 | SCS | SCCI | CAP | CCIE; //using timer 1 delay to fire and 3 millisecond spark charge // SMCLK div/2 halt _ clear timer TA1CTL= TASSEL_2 | ID_1 | MC_0 | TACLR; // coil has fired, interrupt TA1CCTL0= CCIE;//CCIE->TIMER1_A0_ISR // TACCR1 3 millisecond pulse on output TA1CCTL1|= CCIS_0 | OUTMOD_3 | CCIE; //CCIE->TIMER1_A1_ISR //state pump state= STATE_TIMEOUT; //so dwell is set TDC to start //Timers will start on the first Hall pulse _enable_interrupt( ); for( ; ; ) { switch( state & STATE_MODE_MASK ) { case STATE_DWELL_CALC: state&= ~STATE_DWELL_CALC; adjust= last_dwell >> 4; dwell_time_calc= last_dwell - adjust - CHARGE_TIME; //should be safe to do an update here //closest reset is 3 milliseconds out //if STATE_PENDNING hit will be updated fine. if( !( state & STATE_PENDNING ) ) { TA1CCR1= dwell_time_calc; TA1CCR0= dwell_time_calc + CHARGE_TIME; } break; //this is unnecessary but doesn't get in the way for now. case STATE_TIMEOUT: dwell_time= MIN_DWELL; break; default: break; } } } // ..................................................... #pragma vector=TIMER0_A1_VECTOR __interrupt void TIMER0_A1_ISR( ) { ta0iv_val= TA0IV; switch( ta0iv_val ) { case TACOV: state|= STATE_TIMEOUT; state&= ~STATE_TIMEOUT2; return; case TAFCC1: last_dwell= TA0CCR1; TA0CTL|= TACLR; //always clear here if( state & STATE_TIMEOUT ) { state&= ~STATE_TIMEOUT; state|= STATE_TIMEOUT2; dwell_time= MIN_DWELL; } else if( state & STATE_TIMEOUT2 ) { state&= ~STATE_TIMEOUT2; //coming off of TDC state|= STATE_ADD_SPARK; dwell_time= MIN_DWELL; } else dwell_time= dwell_time_calc; state|= STATE_DWELL_CALC; if( state & STATE_PENDNING )//has the last spark gone off? { TOGGLE_LED_RED TA1CTL= TASSEL_2 | ID_1 | MC_0;// stop T1 counter, no racing __no_operation( );//cause __no_operation( );//cause if( state & STATE_IN_SPARK )//just let it finish, we're ok { TA1CTL= TASSEL_2 | ID_1 | MC_1; //start T1 back up state|= STATE_ADD_SPARK;// and next scheduled spark return; } dwell_time= MIN_DWELL;//was behind schedule, do it now state|= STATE_ADD_SPARK;// and next scheduled spark } break; default: { //should not ever get here SET_LED_RED; for( ; ; ); } }//switch(....) //TA1CTL may not be stopped, just start fresh for missed spark on delay TA1CTL|= MC_1 | TACLR; if( state & ( STATE_TIMEOUT | STATE_TIMEOUT2 ) )//need to set off a spark now { //delay TA1CCR1= dwell_time; //pulse TA1CCR0= dwell_time + CHARGE_TIME; //start timer, dwell time can be updated with timer running..... //reset dwell_time } // else scheduled spark will be update in the state pump state|= STATE_PENDNING; } // ..................................................... //when TA1CCR0 hit #pragma vector=TIMER1_A0_VECTOR __interrupt void TIMER1_A0_ISR( ) { if( state & STATE_ADD_SPARK ) { //pull the timing back as there was a TDC firing. TA1CTL|= MC_1 | TACLR; TA1CCR1= dwell_time_calc - CHARGE_TIME; TA1CCR0= dwell_time_calc; dwell_time= MIN_DWELL; state|= STATE_PENDNING; state&= ~STATE_ADD_SPARK; return; } //else kill timer, done this cycle. TA1CTL&= ~( MC_1 | TAIFG ); TA1CCTL0&= ~CCIFG; state&= ~( STATE_IN_SPARK | STATE_PENDNING ); } // ..................................................... //when TA1CCR1 hit #pragma vector=TIMER1_A1_VECTOR __interrupt void TIMER1_A1_ISR( ) { state|= STATE_IN_SPARK; TA1CCTL1&= ~CCIFG; } // ..................................................... #pragma vector=WDT_VECTOR __interrupt void wdt_interrupt( ) { if( ++green_flash > 1 ) CLEAR_LED_GREEN if( +green_flash > 3 ) { SET_LED_GREEN; green_flash= 0; } } // ..................................................... // DUMMY catch alls // ..................................................... #pragma vector=TIMER0_A0_VECTOR __interrupt void TIMER0_A0_ISR( ) { SET_LED_RED; for( ; ; ); }