Microseconds?

I dont have a lot of time to go digging around today so I will just ask

Last night I was tinkering with my attiny84 @ 16MHZ, and in the main loop I have

PORTA &= ~(1<<7);
delayMicroseconds(3);
PORTA |= (1<<7);

and it was way too short, I needed to bump the delay up to 6 uS to result in just over 3 uS, is this normal? or am I missing something?

edit: also to get a 30 uS time I needed a delay of ~41

thanks

Osgeld:
tinkering with my attiny84 @ 16MHZ

What's the clock source for your attiny? Is it a resonator or crystal? Resonators are not very accurate and could easily account for the discrepancy you're seeing.

There will be the delayMicroseconds() call overhead (although I think they allow for that), but also some of the PORTA code will add to the time I would think because all the << 7 stuff has to be done before the pin can be written to.

I'd have a look at the generated assembly to see exactly when the pin is changed.

PS. I doubt that would account for the 30/41 difference though, and even 3uS is a long time for a few instructions.


Rob

its a crystal, and I would think over head would cause the delay to be longer, not shorter

Are you using this core...

http://code.google.com/p/arduino-tiny

Maybe the core you're using is designed for the 8Mhz internal resonator?

yes coding, and yea its probably the core and 16MHZ cause unless I am mistaken thats for 1 and 8

SO! what should I be changing (I am at work and working late tonight so any pointers are appreciated as I wont have much time tonight, not that this is a OMG I NEED THIS DONE BY 9PM TONIGHT OR I WILL DIE!!! situation or anything, just would like to move on)

thanks

For things like delayMicroseconds, the behaviour should be identical to Arduino 0021 with standard Arduino boards. If it works on an Arduinoi at 16 MHz it should work exactly the same on a Tiny. I think the code is actually unmodified from the 0021 core. But that doesn't help solve the problem.

First, check the fuses. This can be done with AVRDUDE and no commands. Something like this modified for your programmer...

avrdude -v -v -v -pattiny85 -cavrispv2 -P\\.\COM8

Second, on that tight of a loop it probably won't matter but test with interrupts disabled. Maybe the timer 0 / millis interrupt (or some other interrupt) is interfering.

Third, test with a longer delay (like 20000). It is possible that delayMicroseconds does not behave well for very short delays.

Finally, I will try to spend some time testing here. If I find anything suspicious, I'll let you know.

and I would think over head would cause the delay to be longer, not shorter

Doh, I read it that the delay was longer than expected.


Rob

Worst case, you just use a simple "nop" based delay command.

First time I have had a chance to get back with this ...
fuses

>>> dump lfuse
0000  ff

avrdude> dump hfuse
>>> dump hfuse
0000  df

avrdude> dump efuse
>>> dump efuse
0000  ff

full sketch just cause

void setup()
{
  DDRA  = B11110000; // set pins PA7, PA6, PA5 PA4 to output (chip pins 6,7,8,9)
  PORTA = B11110000; // set same pins as high
}

void loop()
{
  PORTA &= ~(1<<7);
  delayMicroseconds(6);
  PORTA |= (1<<7);
  delayMicroseconds(42);
}

and that is all I can do now, i cleared the interrupts and now nothing is happening at all

I worked on it last night and I should be able to finish up tonight. As soon as I know something I'll let you know. Thanks for the follow-up.

From the Arduino reference:

Caveats and Known Issues
This function works very accurately in the range 3 microseconds and up. We cannot assure that delayMicroseconds will perform precisely for smaller delay-times.

handy since I want a 3 microsecond delay :slight_smile:

the way its sitting now (well if I can get it working again) its very easy to get a stable sub 3 microsecodnds, which is the problem, its too short

The fuse settings look good. The delayMicroseconds code in the Tiny Core is identical to the delayMicroseconds that comes with Arduino 0022.

My test Sketch...

void setup( void )
{
  DDRA |= (1<<7);
  PORTA |= (1<<7);
}

void loop( void )
{
  PORTA &= ~(1<<7);
  delayMicroseconds( 3 );
  PORTA |= (1<<7);
  delay( 1000 );

  PORTA &= ~(1<<7);
  delayMicroseconds( 6 );
  PORTA |= (1<<7);
  delay( 1000 );

  PORTA &= ~(1<<7);
  delayMicroseconds( 41 );
  PORTA |= (1<<7);
  delay( 1000 );
}

I used a 168 processor (16 MHz crystal) running this Sketch to time the delayMicroseconds calls (some of it is dead code)...

ISR(TIMER1_CAPT_vect)
{
}

void setup( void )
{
  Serial.begin( 38400 );
  pinMode( 8, INPUT );

  // Turn off Timer 1
  TCCR1B &= ~ ( ( 1 << CS12 ) | ( 1 << CS11 ) | ( 1 << CS10 ) );
  
  // Normal mode; OC1x disconnected
  TCCR1A = 
      ( 0 << COM1A1 ) | ( 0 << COM1A0 ) |
      ( 0 << COM1B1 ) | ( 0 << COM1B0 ) |
      ( 0 << WGM11 ) | ( 0 << WGM10);

  cli();
  
  TCCR1B = 
      ( 0 << ICNC1 ) |
      ( 0 << ICES1 ) |
      ( 0 << WGM13 ) | ( 0 << WGM12 ) |
      ( 0 << CS12 ) | ( 0 << CS11 ) | ( 1 << CS10 );

/*
  TIMSK1 =
      ( 1 << ICIE1 ) | ( 0 << OCIE1B ) | ( 0 << OCIE1A ) | ( 0 << TOIE1 );
*/      
  TIMSK1 =
      ( 1 << ICIE1 ) | ( 0 << OCIE1B ) | ( 0 << OCIE1A ) | ( 0 << TOIE1 );
      
  TIFR1 |= ( 1 << ICF1 );
  
  sei();
}

void loop( void )
{
  static uint16_t CaptureStart;
  static uint16_t CaptureStop;

  cli();

  TCCR1B &= ~(1<<ICES1);
  TIFR1 |= ( 1 << ICF1 );
  while ( (TIFR1 & (1<<ICF1)) == 0 );
  CaptureStart = ICR1;

  TCCR1B |= (1<<ICES1);
  TIFR1 |= ( 1 << ICF1 );
  while ( (TIFR1 & (1<<ICF1)) == 0 );
  CaptureStop = ICR1;

  sei();

  Serial.println( CaptureStop - CaptureStart, DEC );
}

The results...

43 = 43/16000000*1000000 = 2.69 uS (expected value is slightly over 3.00 uS)

91 = 91/16000000*1000000 = 5.69 uS (expected value is slightly over 6.00 uS)

651 = 651/16000000*1000000 = 40.69 uS (expected value is slightly over 41.00 uS)

So...

While my results are not perfect, they are much better than what you're seeing.

How are you measuring the delay?

Have you tried a different crystal?

Have you tried a one second blink (delay(1000) + blink LED)? Does it appear to be about one second?

Have you tried delay_us? (It's part of AVR-LIB)