Strange I/O access behavior Atmega16

Status
Not open for further replies.

chiragshetty

Newbie level 3
Joined
Jun 4, 2014
Messages
3
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Visit site
Activity points
26
The code below is to show a problem I encountered while working on a bigger program.
I'm using ATmega16 with 16MHz external crystal. I measure the frequency at which PIN7 of portD is toggling (i.e time taken per loop).
When I don't include the statement "PORTC = 0x00;" inside if (count>1000), the frequency of PIND7 is 27kHz.
But when I include the statement, it reduces to 16kHz.

This problem doesn't occur if count is an int variable. I don't understand how a statement that is executed once in 10000 loops affects the loop time.

Surprisingly, this frequency change occurs even if I change the if condition to if(count<0), which will never happen.

I experimented a lot, but found no way to fix this.


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include<math.h>
#define F_CPU 16000000UL
              
int main(void)
{
 
     DDRD = 0xFF;
     PORTD = 0b11000000;
     DDRC = 0xFF;
     PORTC = 0b00000000;
    float count =0.0;
     
   while (1)
   {
     
      count = count + 1.0;
      
     if (count > 10000.0)
     {
         //PORTC = 0x00;      //**********************************
         count = 0.0;
     }
     
         PORTD ^= 0x80;
      
     _delay_us(18);
     
   }
 
}

 
Last edited by a moderator:

Hi chiragshetty,

I don't understand how a statement that is executed once in 10000 loops affects the loop time.

I think the float-comparison "if (count > 10000.0)" eats up more time than you think.
You might want to check the lst-file with the assembler code to see what the compiler does with your c-code.

The reason why the loop runs faster when you don't include the "PortC = 0x00" statement:
Since there is nothing in that if-block that influences other variables, the compiler probably optimizes the code (omits that whole if-block).
Check the lst-file to find the "if (count > 10000.0)" Assembler-code... it's probably not there.

Besides:
1) You might want to check whether working with floats can be avoided, usually it's possible to use fixed point operations instead.
2) If you really need to use floats, use a uC with floating point hardware, like the LPC4088, etc...
3) What optimization-level are you running? Setting the optimization on level 2 or 3 can increase the speed dramatically, but you might run into weird compiler-errors like missing switch-statements or the like.


For further explanation, post the lst-files of the two variants if you like.

Cheers,

DBE
 

The reason is simple, the compiler is totally removing the for loop if there is nothing to do inside the loop. Generally compiler acts little bit smart on busy loops, gcc based compilers do this mostly. Now when you include the statement it is decreasing to 16KHz because the soft float implementation in AVR will take more cycles. There is no hardware floating point unit, so compiler implement the float in software. So if you use int (16 bit) or uint32_t instead of float, then the performance will increase.
Now, if you want the compiler not to optimize the loop, use volatile float count =0.0; (volatile will tell the compiler not to optimize any operation where count is involved).


Note:
Another example:
If you are waiting in main program for a flag to set or clear inside an ISR, compiler will not allow you to wait in the loop if the flag variable is not volatile, because compiler thinks the loop is useless. So be aware about usage of volatile in this kind of situation.
 
Last edited:

Status
Not open for further replies.

Similar threads

Cookies are required to use this site. You must accept them to continue using the site. Learn more…