input capture interrupts starts late - TCNT1 is reset to late.

Go To Last Post
19 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have a problem:

 

Since the interrupt for the input capture starts to late, i can only reset TNCT1 to 0 after a certain time. So there are some counts that are lost. This equals to 2-4us.

 

Shouldnt the interrupt start right away? Or is there a solution to have TCNT1 set to 0 as there is a input edge?

 


#define NANOSECONDS_PER_TIC  500
#define MICROS_TO_TICS(mics)( mics * (unsigned long) 1000 / NANOSECONDS_PER_TIC)
#define TICS_TO_MICROS(tics)( tics * (unsigned long) NANOSECONDS_PER_TIC / 1000)

void setup(){

  Serial.begin(57600);
  delay(300);

  Serial.println(__DATE__);
  Serial.println(__TIME__);

  //all on pin 4 on ProMicro (ICP1)
  DDRB &= ~(1 << PB0);

  //testpin 6
  DDRD |= (1 << PD7);

  //testpin 2
  DDRD |= (1 << PD1);

  //testpin 3
  DDRD |= (1 << PD0);

  TCCR1A = 0;
  TCCR1B = 0;
  TIMSK1 = 0;
  TCCR1A = 0;

  //bit to one, raising edge!
  TCCR1B |= (1 << ICES1);

  //enable interrupt
  TIMSK1 |= (1 << ICIE1);

  //Timer overflow interrupt enable
  TIMSK1 |= (1 << TOIE1);

  TCCR1B |= (1 << CS11);  // full counter to FFFF / 8 prescaler, so 1 tic is 500ns
}

int difference = 0;

void loop(){
    Serial.println(difference);
    delay(100);
}

/*
 * ca. 3us 10.01.2019
 * starts about 2us after edge change
 * ca. 10us 14.01.2019 0:36 (ohne delay(); welches zur Besseren Sichtbarkeit fürs oszi ist!)
 * ca. 8us 19.01.2019 21:51
 */
ISR(TIMER1_CAPT_vect){
  byte oldSREG = SREG;

  PORTD |= (1 << PD7);

  unsigned int tcnt1 = TCNT1;

  TCNT1 = 0;    //reset count from this edge on

  //get counter value
  unsigned int currICP = ICR1;

  difference = tcnt1 - currICP;

  // toggle interrupt: next time with the other edge
  TCCR1B ^= (1 << ICES1);

  SREG = oldSREG;
  PORTD &= ~(1 << PD7);
}

ISR(TIMER1_OVF_vect){
  byte oldSREG = SREG;
  SREG = oldSREG;
}

 

Yes i use Google, but there is no search enginge within Google to search through those many useless results...

Last Edited: Tue. Jan 22, 2019 - 12:12 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why are you playing around with sreg in the isrs? The compiler manages this for you.
With input capture you don’t touch tcnt1. To read the capture value use icr1. Store this value. Next capture subtract the previous capture value from the current capture value - this gives you the period.

The isr has some overhead - registers need to be saved.this is what you are measuring.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Still i get wrong values: those are now bigger (57 instead of 50us)...

 

Bloody h*** there are wrong pulses in the beginning. And it prints those to 99% WTF...


#define NANOSECONDS_PER_TIC  500
#define MICROS_TO_TICS(mics)( mics * (unsigned long) 1000 / NANOSECONDS_PER_TIC)
#define TICS_TO_MICROS(tics)( tics * (unsigned long) NANOSECONDS_PER_TIC / 1000)

void setup(){

  Serial.begin(57600);
  delay(300);

  Serial.println(__DATE__);
  Serial.println(__TIME__);

  //all on pin 4 on ProMicro (ICP1)
  DDRB &= ~(1 << PB0);

  //testpin 6
  DDRD |= (1 << PD7);

  //testpin 2
  DDRD |= (1 << PD1);

  //testpin 3
  DDRD |= (1 << PD0);

  TCCR1A = 0;
  TCCR1B = 0;
  TIMSK1 = 0;
  TCCR1A = 0;

  //bit to one, raising edge!
  TCCR1B |= (1 << ICES1);

  //enable interrupt
  TIMSK1 |= (1 << ICIE1);

  //Timer overflow interrupt enable
  TIMSK1 |= (1 << TOIE1);

  TCCR1B |= (1 << CS11);  // full counter to FFFF / 8 prescaler, so 1 tic is 500ns
}

unsigned int lastICP = 0;
unsigned int currICP;
unsigned int pulseTics;

void loop(){
    cli();
    Serial.println(pulseTics);
    sei();
    delay(100);
}

/*
 * ca. 3us 10.01.2019
 * starts about 2us after edge change
 * ca. 10us 14.01.2019 0:36 (ohne delay(); welches zur Besseren Sichtbarkeit fürs oszi ist!)
 * ca. 8us 19.01.2019 21:51
 */
ISR(TIMER1_CAPT_vect){
 byte oldSREG = SREG;

  PORTD |= (1 << PD7);

  //get counter value
  currICP = ICR1;

  pulseTics = currICP - lastICP;

  lastICP = currICP;

  // toggle interrupt: next time with the other edge
  TCCR1B ^= (1 << ICES1);

  // if there was an uncaptured interrupt (a really short pulse < ~5us - there was only one interrupt for 2 edges), then edge select and current level will not correspond and there is no capture flag set.

  SREG = oldSREG;
  PORTD &= ~(1 << PD7);
}

ISR(TIMER1_OVF_vect){
  byte oldSREG = SREG;
  SREG = oldSREG;
}

 

Yes i use Google, but there is no search enginge within Google to search through those many useless results...

Last Edited: Tue. Jan 22, 2019 - 12:39 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

pulseTics needs to be volatile!!

 

Also do not cli/sei across the entire duration of Serial.println(). Instead take a local copy under interrupt protection then print that. That is:

volatile unsigned int pulseTics;

void loop(){
    unsigned int pulseCopy;
    cli();
    pulseCopy = puleseTics;
    sei();
    Serial.println(pulseCopy);
    delay(100);
}

(there is an argument to say ATOMIC_BLOCK is a better way to handle this than individual cli/sei)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Poor blind me... fixed those...

Still it gets almost only the bad pulses.

Well at least the values are correct now.

Thanks!

Yes i use Google, but there is no search enginge within Google to search through those many useless results...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

- what is the freuquency that the chip is running ?

- what is ur delay() implementation, show whats behind ?

 

Lg,

Moe

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Your loop code has a delay(100) and also Serial.println() itself will take a considerable time (in computing terms) so you are only going to be sampling/showing pulseTics rarely with this code.

 

Also why do you enable the overflow ISR when it does not apparently do anything useful?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

clawson wrote:

Also why do you enable the overflow ISR when it does not apparently do anything useful?

 

This is just a portion of my code.

 

I still get a 1503us reading, when there is a 1500us signal (checked with oscilloscope / Im using the COM1A toggle with CTC mode for creating the signal).

The interrupts are 1502us apart. How could that be?

 

Also the aditionally micros appear only with bigger delays between the edges. From about 400 on.

 

Yes i use Google, but there is no search enginge within Google to search through those many useless results...

Last Edited: Tue. Jan 22, 2019 - 01:56 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

how many times you edited ur last post ?. simply make another comment.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

and the chip frequency is ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Tobey wrote:
How could that be?

If it was like this still...

void loop(){
    cli();
    Serial.println(pulseTics);
    sei();

You leave the interrupts disabled for the entire duration of the Serial.println() so I could well believe that in that time some actual timer events are missed or delayed.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
You leave the interrupts disabled for the entire duration of the Serial.println() so I could well believe that in that time some actual timer events are missed or delayed.
What's more, this will fail if you ever try to print more than 64 bytes, as that's the size of the buffer used by Serial.print().  It will wait forever for room to appear in the buffer, but that will never happen since the buffer interrupt-driven.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Of course did i implement your valuable suggestions!

It runs with 16Mhz.

This is the current program:


#define NANOSECONDS_PER_TIC  500
#define MICROS_TO_TICS(mics)( mics * (unsigned long) 1000 / NANOSECONDS_PER_TIC)
#define TICS_TO_MICROS(tics)( tics * (unsigned long) NANOSECONDS_PER_TIC / 1000)


void setup(){

  Serial.begin(57600);
  delay(300);

  Serial.println(__DATE__);
  Serial.println(__TIME__);

  //all on pin 4 on ProMicro (ICP1)
  DDRB &= ~(1 << PB0);

  //testpin 6
  DDRD |= (1 << PD7);

  //testpin 2
  DDRD |= (1 << PD1);

  //testpin 3
  DDRD |= (1 << PD0);


  TCCR1A = 0;
  TCCR1B = 0;
  TIMSK1 = 0;
  TCCR1A = 0;

  //bit to one, raising edge!
  TCCR1B |= (1 << ICES1);

  //enable interrupt
  TIMSK1 |= (1 << ICIE1);

  //Timer overflow interrupt enable
  TIMSK1 |= (1 << TOIE1);

  TCCR1B |= (1 << CS11);  // full counter to FFFF / 8 prescaler, so 1 tic is 500ns
}


unsigned int lastICP = 0;
unsigned int currICP;
volatile unsigned int pulseTics;

void loop(){
    unsigned int pulseCopy;
    cli();
    pulseCopy = pulseTics;
    sei();
    Serial.println(TICS_TO_MICROS(pulseCopy));
    delay(100);
}


/*
 * ca. 3us 10.01.2019
 * starts about 2us after edge change
 * ca. 10us 14.01.2019 0:36 (ohne delay(); welches zur Besseren Sichtbarkeit fürs oszi ist!)
 * ca. 8us 19.01.2019 21:51
 */
ISR(TIMER1_CAPT_vect){
 byte oldSREG = SREG;

  PORTD |= (1 << PD7);
  
  //get counter value
  currICP = ICR1;

  pulseTics = currICP - lastICP;
  
  lastICP = currICP;

  // toggle interrupt: next time with the other edge
  TCCR1B ^= (1 << ICES1);

  // if there was an uncaptured interrupt (a really short pulse < ~5us - there was only one interrupt for 2 edges), then edge select and current level will not correspond and there is no capture flag set.
 
  SREG = oldSREG;
  PORTD &= ~(1 << PD7);
}


ISR(TIMER1_OVF_vect){
  byte oldSREG = SREG;
  SREG = oldSREG;
}

 

Yes i use Google, but there is no search enginge within Google to search through those many useless results...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1
/*
 * ca. 3us 10.01.2019
 * starts about 2us after edge change
 * ca. 10us 14.01.2019 0:36 (ohne delay(); welches zur Besseren Sichtbarkeit fürs oszi ist!)
 * ca. 8us 19.01.2019 21:51
 */
ISR(TIMER1_CAPT_vect){

  PORTD |= (1 << PD7);
  
  //get counter value
  currICP = ICR1;

  pulseTics = currICP - lastICP;
  
  lastICP = currICP;

  // toggle interrupt: next time with the other edge
  TCCR1B ^= (1 << ICES1);
  //you might need to clear the interrupt flag here as changing the level may cause another interrupt

  // if there was an uncaptured interrupt (a really short pulse < ~5us - there was only one interrupt for 2 edges), then edge select and current level will not correspond and there is no capture flag set.
 
  PORTD &= ~(1 << PD7);
}

again, no need to touch SREG.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:

again, no need to touch SREG.

 

Especially as this code sequence will change SREG AFTER you have carefully saved and restored it...

 

Tobey wrote:

 

...
  SREG = oldSREG;
  PORTD &= ~(1 << PD7);
}

 

 

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Brian Fairchild wrote:
Especially as this code sequence will change SREG AFTER you have carefully saved and restored it...
No it won't.

 

(At least I don't think CBI touches the flags??)

EDIT: confirmed...

 

Last Edited: Wed. Jan 23, 2019 - 09:43 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
No it won't. (At least I don't think CBI touches the flags??) EDIT: confirmed...

Yes -- >>IF<< CBI is generated.  Yes, if we know our code generation model for our toolchain, and do the double-checking, then it is cool.  But if you don't and then modify the statement slightly, like for a tempting toggle...

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But as already noted I think all C compiler ISRs already handle SREG preservation so it's all moot anyway.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes it is. I had a look at the assembler. I did not know about this. Hail to the compiler

Yes i use Google, but there is no search enginge within Google to search through those many useless results...