cattledog,
Thanks for the heads up; I missed that in the datasheet. At your suggestion, I'm thinking of how to implement using CTC or fast PWM mode.
Robin2,
Normal mode, 8x multiplier, using only 1 interrupt.
The grand scheme was to use the timer to orchestrate the entire process during a single cycle; from 0x0000 to 0xFFFF. The entire test takes less than 3ms; with a 8x multiplier yeilding a 32ms cycle time, I expected it could be easily done in one cycle. The test starts at 0x0000 setting the first output and the comparator interrupt to trigger the next state approximately 1ms later. In the full code, while waiting for the interrupt I'm checking an input for a test value. After the interrupt the next output state is activated and the next comparator interrupt is set. The three pulses are produced using this technique. In the sample code I stripped out the measurement to make sure that wasn't the problem.
From that last paragraph, you can see testTime is not changed during the timer cycle. testTime is only changed after the last measurement is made (no where near the end of the timer cycle ~3/32ms). See below for the static value example; this version of the code runs the exact same three pulses over and over.
volatile int pgrmState = 0;
int ledPin0 = 11;
int ledPin1 = 12;
int ledPin2 = 13;
byte testTime = 0x0060;
ISR(TIMER1_OVF_vect) {
pgrmState = 0;
OCR1A = 0x0000;
TCNT1 = 0x0000;
}
ISR(TIMER1_COMPA_vect) {
pgrmState++;
}
void setup() {
TCCR1A = B00000000;
TCCR1B = B00000010;
OCR1A = 0x0000;
TCNT1 = 0x0000;
TIMSK1 = 0x03;
pinMode(ledPin0, OUTPUT);
pinMode(ledPin1, OUTPUT);
pinMode(ledPin2, OUTPUT);
digitalWrite(ledPin0, LOW);
digitalWrite(ledPin1, LOW);
digitalWrite(ledPin2, LOW);
sei();
}
void loop() {
if (pgrmState == 0) {
digitalWrite(ledPin0, HIGH);
cli();
TCNT1 = 0x0000;
OCR1A = 0x0030;
sei();
pgrmState++;
} else if (pgrmState == 1) {
// do nothing
} else if (pgrmState == 2) {
digitalWrite(ledPin0, LOW);
digitalWrite(ledPin1, HIGH);
cli();
OCR1A += 0x0045; //0x0045 ~= 34uS; 0x0038 ~= 25uS; 0x0018 about minimum @ 12u
sei();
pgrmState++;
} else if (pgrmState == 3) {
// do nothing
} else if (pgrmState == 4) {
digitalWrite(ledPin1, LOW);
digitalWrite(ledPin2, HIGH);
cli();
OCR1A += 0x0030;
sei();
pgrmState++;
} else if (pgrmState == 5) {
// do nothing
} else if (pgrmState == 6) {
digitalWrite(ledPin2, LOW);
cli();
OCR1A += 0x0030;
sei();
pgrmState++;
} else if (pgrmState == 7) {
// do nothing
} else if (pgrmState == 8) {
//testTime -= 0x0001;
pgrmState = 0;
}
//unnecessary with a fixed value of testTime
if (testTime <= 0x0020) {
testTime = 0x0060;
}
}
MarkT,
In the full code, timer0 is used to generate a 50khz pulse. See below for the function written to start that. Since the 50kHz wave is 50% duty cycle with a period of 20us, I didn't expect this to be a contributing factor. The 50kHz signal is used in the first few states but if testing confirms it is a problem, it can be disabled after it's no longer needed.
void start50kHzSignal() {
cli();
//Setup 50kHz signal
// TC0 Control Register A, Sets up output mode and waveform generation mode
TCCR0A = B01000010;
// TC0 Control Regsiter B, disables input capture settings, finishes waveform generation mode, sets prescaler value
TCCR0B = B00101010;
OCR0A = 0x13; //0001 0011 Time necessary for 50kHz
DDRD |= 0x40; //0100 0000 Enable pin output
sei();
}
(When I wrote this, I was still getting into the idea of manipulating registers; I should probably clean it up and standardize my format.)
Having said all that, I think it is the structure of the code that is the problem. I've had it in my head to try but DKWatson's reply inspired me to do it. If I replace the huge while loop and switch case with a more straight-forward one-by-one execution scheme with small while loops when I need to wait, I seem to be getting the results I expected. This includes changing the pins by port manipulation instead of using the digitalWrite command. See below.
volatile bool nextState = false;
int testTime = 495;
ISR(TIMER1_COMPA_vect) {
nextState = true;
}
void setup() {
TCCR1A = B00000000;
TCCR1B = B00000001;
// 0x01E0 = 30us with no scaling
OCR1A = 0x0000;
TCNT1 = 0x0000;
TIMSK1 = 0x03;
DDRB = 0x38;
PORTB = 0x00;
sei();
}
// 0x01E0 = 30us with no scaling
void loop() {
nextState = false;
PORTB = 0x08;
cli();
TCNT1 = 0x0000;
OCR1A = 0x0200;
sei();
while (!nextState) {
}
nextState = false;
PORTB = 0x10;
cli();
OCR1A += testTime;//testTime; //0x0045 ~= 34uS; 0x0038 ~= 25uS; 0x0018 about minimum @ 12u
sei();
while (!nextState) {
}
nextState = false;
PORTB = 0x20;
cli();
OCR1A += 0x0200;
sei();
while (!nextState) {
}
nextState = false;
PORTB = 0x00;
cli();
OCR1A += 0x0200;
sei();
while (!nextState) {
}
nextState = false;
cli();
//testTime -= 0x0010;
testTime -= 16;
if (testTime <= 256) {
testTime = 495;
}
sei();
}
I'll updated the full code and report back the results. If anyone has an further thoughts, please post them!