I'm going to fix a few things up such that changing the prescaler for the timer doesn't affect operation (other than max pulsewidth).
Secondly, I realised that the table for timer prescalers in the manual is just an example. not a full table. So we can pick and choose our time base down to the finest grain.
Thirdly, I have some very basic code that piggy backs output compares on top of each other by giving a count and final period.
This can be further optimised by using divide and modulus to ensure that the last time period is not too small.
Then you just take a time count in (arbitrarily large) figure out how many periods fit within it and what the left over is, and find a main period and final period that are all in the large region that is safe.
if a pulse is timeperiod - 1, you use it (or similar)
if it is time period + 1, you cut in half, and add the left over on to one of them ensuring that it doesn't exceed max.
currently I'm doing 7 second periods with 1000 interrupts and 7ms chunks.
Additionally, the output compare code can watch the timer overflow variable and by careful examination of the interrupt flags when it is triggered know exactly where it is at absolute time wise. This only works till the final pulse as these interrupts are generated while trying to switch an On injector On again. Once you set it to switch off, its off... so knowing where you are is useless. However on the second to last you could fine tune the pulsewidth to the latest measurement/calculation if done right.
here is the uber basic code that does this (took far too long to write with a handful of errors here and there) :
Code: Select all
void Injector6ISR(void){
TFLG1 = MAIN6ON; // clear flag
PORTK++; // blink k7 if we are still interrupting despite edge being already high
PORTS_BA = periodCount;
PORTM = MAIN6CTL;
if(timerTestFlag){
if(periodCount == 0){
// configure count variable from spare on Jim
periodCount = ATD0DR7 + 1;
// configure final pulse variable
trimLength = (ATD0DR3 << 6) + 1000;
}else if(periodCount == 1){
// set next time to be trimlength from now
MAIN6TIME += trimLength;
if(MAIN6CTL & MAIN6GOHIGH){ // invert direction prior last edge
MAIN6CTL &= MAIN6GOLOW; // change to go low
}else{
MAIN6CTL |= MAIN6GOHIGH; // change to go high
}
}
periodCount--; // decrement counter
}else{
// turn int off
TIE &= 0x7F;
// disable switching
MAIN6CTL &= MAIN6DISABLE;
// turn of pin(s) lazy...
PORTT = ZEROS;
}
}
misc_isrs.c :
Code: Select all
case 0x08 : // Trigger timed pulse
if(!timerTestFlag){
PORTK = ONES; // set k
// set flag
timerTestFlag = TRUE;
// configure count variable from spare on Jim
periodCount = ATD0DR7 + 1;
// configure final pulse variable
trimLength = (ATD0DR3 << 6) + 1000;
// configure timer to switch on
MAIN6CTL |= MAIN1ENABLE;
// configure time to be (short-max/2 +tcnt later)
MAIN6TIME = TCNT + 1000; // start very soon for now (could use force too)
// configure the interrupt to be on
TIE |= 0x80;
}else{
PORTK = ZEROS; // clear k
// unset flag
timerTestFlag = FALSE;
// turn the interrupt off
TIE &= 0x7F;
// switch off channel
PORTT = ZEROS;
// disable compare
MAIN6CTL &= MAIN6DISABLE;
}
break;
some of each is probably superfluous/wrong, but it works as it is and I dont want to do a release for it (there are more changes to some variables and flags in init.c too and commenting out of stuff in enginepos.c
see :
/* section 10.3.5 page 290 68hc11 reference manual e.g. groups.csail.mit.edu/drl/courses/cs54-2001s/pdf/M68HC11RM.pdf */
for timer extension implementation details.