Author Topic: ATmega32 for loop takes forever.  (Read 4066 times)

0 Members and 1 Guest are viewing this topic.

Offline georgianTopic starter

  • Regular Contributor
  • *
  • Posts: 61
  • Country: at
ATmega32 for loop takes forever.
« on: December 17, 2018, 05:15:40 pm »
Hello,
The project I'm working on is an oscilloscope clock. I want to make two 8bit or 16 bit DAC using resistors and OP AMPs, so I can write a 16 bit integer on 2 ports from the ATmega. For example lower 8 Bits on PORTD and upper 8 bits on PORTB (for x axis)

So far I made a simple code using atmel studio 7.0 and it's not working.  :scared:
So, this code should go thorugh all bits up to maximum of 2^16-1 (65535). I have a LED connected to PORTB.7  and one to PORTD.0. To my understang the LEDs should turn off after the for loop ends but it looks like it never ends. The PORTB.7 keeps blinking at about 6.6 Hz. If i have 30000 in the for loop it works. If I have 40000 it dosen't work. There must be something wrong or mabe the µC is to slow. (Atmega32 8Mhz internal)

Anybody knows why it's not working? Thank you.
Here is the code:
Code: [Select]
#ifndef F_CPU
#define F_CPU 8000000UL
#endif

#include <avr/io.h>
#include <util/delay.h>

int value = 32768;
uint8_t lowerBits = 0;
uint8_t upperBits = 0;


int main(void)
{
DDRD = 0xff;
DDRA = 0xff;
DDRB = 0xff;
DDRC = 0xff;

    while (1)
    {

for (int i = 0; i < 65534; i++) {
lowerBits = i & 0xff;
upperBits = (i >> 8);

PORTB = upperBits;
PORTD = lowerBits;
PORTA = upperBits;
PORTC = lowerBits;
}
PORTA = 0;
PORTB = 0;
PORTC = 0;
PORTD = 0;

for (;;);
//PORTD = 0b01110000;
//_delay_ms(50);
//PORTD = 0b00000000;
//_delay_ms(1000);
    }

}

Here is the schematic I want to use for DAC. Not sure if its corect to connect 2 OP AMPs like that but i'll see.
 

Offline free_electron

  • Super Contributor
  • ***
  • Posts: 9053
  • Country: us
    • SiliconValleyGarage
Re: ATmega32 for loop takes forever.
« Reply #1 on: December 17, 2018, 05:34:00 pm »
use uint (unsigned integer. a normal int rolls over at 32768 ... )  . stupidity in the C language.
Professional Electron Wrangler.
Any comments, or points of view expressed, are my own and not endorsed , induced or compensated by my employer(s).
 
The following users thanked this post: georgian

Offline IanB

  • Super Contributor
  • ***
  • Posts: 13125
  • Country: us
Re: ATmega32 for loop takes forever.
« Reply #2 on: December 17, 2018, 05:39:47 pm »
Code: [Select]
for (int i = 0; i < 65534; i++) {

As noted above, the "int" type has a range from -32768 to +32767. So "i" will always have a value less than 65534 and the loop will never end.

You need to use "unsigned int" that has a range from 0 to 65535.

(Why did you put 65534 in your code? Also, why "<" instead of "<="?)
 
The following users thanked this post: georgian

Offline georgianTopic starter

  • Regular Contributor
  • *
  • Posts: 61
  • Country: at
Re: ATmega32 for loop takes forever.
« Reply #3 on: December 17, 2018, 05:44:50 pm »
Thank you sir :) Seconds ago, tring to find the maximal number that works i fund that 32767 works but 32768 dosen't work anymore. I used uint16_t and it works. Awesome! Thanks again.
If anybody have to say anything about the schematic or maybe a value for the R10, R11 / R30,R31 is more than welcome to post.

Quote
(Why did you put 65534 in your code? Also, why "<" instead of "<="?)
it was 65535 before. And yes it should be <= or i < 65536.
Will it be a waste of time and resources to use the power of function? i < pow(2, 16) ?
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 17818
  • Country: fr
Re: ATmega32 for loop takes forever.
« Reply #4 on: December 17, 2018, 06:23:26 pm »
If anybody have to say anything about the schematic or maybe a value for the R10, R11 / R30,R31 is more than welcome to post.

I'm wondering why you are doubling each "DAC" and summing them? This summing could be done at the software level. Adding one bit of resolution will not make you lose anything and it's much simpler?
Are you really going to implement DACs this way instead of using true DACs? If so, implementing an R/2R ladder will be again much simpler (no need for switches).
Additionally, depending on the accuracy you're targetting, using true DACs may be cheaper than using precision resistors. If accuracy is not an issue, implement R-2R ladders.

Quote
Will it be a waste of time and resources to use the power of function? i < pow(2, 16) ?

pow() is a math function from the std C lib acting on doubles and returning a double. Don't use it here (you could but it would need proper casting AND rounding, if not, you'll probably get a warning AND the result will be floor'ed, most likely getting you 65535 instead of 65536...). Integer powers of two are best expressed as this in C: 1 << 16

Either way, it won't waste anything as these are operations on constants that are going to be evaluated at compile-time.
« Last Edit: December 17, 2018, 06:25:40 pm by SiliconWizard »
 
The following users thanked this post: georgian

Offline ejeffrey

  • Super Contributor
  • ***
  • Posts: 4849
  • Country: us
Re: ATmega32 for loop takes forever.
« Reply #5 on: December 17, 2018, 06:35:56 pm »
Code: [Select]
for (int i = 0; i < 65534; i++) {

As noted above, the "int" type has a range from -32768 to +32767. So "i" will always have a value less than 65534 and the loop will never end.

You need to use "unsigned int" that has a range from 0 to 65535.

(Why did you put 65534 in your code? Also, why "<" instead of "<="?)

Note that gcc -Wextra will warn about this by enabling the -Wtype-limits flag.  This checks comparisons that can never be true (or never false) because of the data type ranges.  This also includes comparing an unsigned value to >= 0.  I honestly don't know why it isn't enabled by -Wall.  Possibly it generates too many extra warnings when such comparisons come up in macro expansions.

It's always good to use the highest warning level you can tolerate and at least understand where each warning is coming from.
 

Offline Twoflower

  • Frequent Contributor
  • **
  • Posts: 745
  • Country: de
Re: ATmega32 for loop takes forever.
« Reply #6 on: December 17, 2018, 06:49:08 pm »
Maybe you should also consider using the sized types like you did on the ports (uint8_t instead of char). For the loop variable you can use uint16_t. This makes a bit clearer to identify the actual value-range of a given variable.

Edit: And just now I noticed that you actually did exactly that.  :-[
« Last Edit: December 17, 2018, 06:52:12 pm by Twoflower »
 
The following users thanked this post: georgian

Offline georgianTopic starter

  • Regular Contributor
  • *
  • Posts: 61
  • Country: at
Re: ATmega32 for loop takes forever.
« Reply #7 on: December 17, 2018, 07:18:17 pm »
If anybody have to say anything about the schematic or maybe a value for the R10, R11 / R30,R31 is more than welcome to post.

I'm wondering why you are doubling each "DAC" and summing them? This summing could be done at the software level. Adding one bit of resolution will not make you lose anything and it's much simpler?
Are you really going to implement DACs this way instead of using true DACs? If so, implementing an R/2R ladder will be again much simpler (no need for switches).
Additionally, depending on the accuracy you're targetting, using true DACs may be cheaper than using precision resistors. If accuracy is not an issue, implement R-2R ladders.

Quote
Will it be a waste of time and resources to use the power of function? i < pow(2, 16) ?

pow() is a math function from the std C lib acting on doubles and returning a double. Don't use it here (you could but it would need proper casting AND rounding, if not, you'll probably get a warning AND the result will be floor'ed, most likely getting you 65535 instead of 65536...). Integer powers of two are best expressed as this in C: 1 << 16

Either way, it won't waste anything as these are operations on constants that are going to be evaluated at compile-time.

Well, in order to have an 16 bit DAC i could go for one OP amp and 16 resistors. The value of each would go too high and i think it will require to many resistor (series and parallel). One teacher told me that i could add the outputs like this and i'm not sure how to calculate the resistors. He said something that the lower resistor(R11) should be 256 times bigger then the upper one(R10). I did some small tests with LTspice but i was not happy with the resuslts.
Honestly I don't know wich is better. This way or using R-2R ledder.
By true DAC i think you mean some SPI /I²C DAC? If yes, then there is not much to learn by using tham. I did some prototypes using arduino DUE and Teensy 3.6. They both have internal DAC. Makeing everything from scratch make a lot more fun than using using already made ICs.
 

Offline IanB

  • Super Contributor
  • ***
  • Posts: 13125
  • Country: us
Re: ATmega32 for loop takes forever.
« Reply #8 on: December 17, 2018, 07:35:25 pm »
it was 65535 before. And yes it should be <= or i < 65536.

Be careful with this. If the type has a range of 0 to 65535, then 65536 is outside the range of values that can be represented by the type. The code may not do what you intend it to do.
 
The following users thanked this post: georgian

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 17818
  • Country: fr
Re: ATmega32 for loop takes forever.
« Reply #9 on: December 17, 2018, 07:48:18 pm »
it was 65535 before. And yes it should be <= or i < 65536.

Be careful with this. If the type has a range of 0 to 65535, then 65536 is outside the range of values that can be represented by the type. The code may not do what you intend it to do.

Yep. If i is 16-bit unsigned, it will never be 65536. So the condition i < 65536 will still be always true (infinite loop). Note that the same holds for i <= 65535. Always true.
You can't get out of such a loop this way. You have to use a different condition. Or use a larger int, but that's wasteful.

 
The following users thanked this post: georgian

Offline ejeffrey

  • Super Contributor
  • ***
  • Posts: 4849
  • Country: us
Re: ATmega32 for loop takes forever.
« Reply #10 on: December 17, 2018, 07:53:36 pm »
Yes, this is a more fundamental issue.  There is no way in C for a standard(*) for loop to execute over every legal value of the iteration variable.  The test is done on entry to the loop body, and at least one value must fail or the loop will never terminate.  So a for loop with a 16 bit integer can't execute more than 2^16-1 times.  You need to either change the index variable to a larger size or use an alternate construction.  One way is to change to a do/while loop:

Code: [Select]
uint16_t i=0;
do {
  // code goes here
  i++;
} while (i != 0);

This will execute once for every value of i, then terminate when it wraps back to zero.  This is not idiomatic C, so I would prefer to use a 32 bit loop counter if possible.

Another way is to unroll a single iteration of the loop by replicating the body before or after the loop.  I don't like this as much as it is unnecessary code duplication and possibly error prone, but it will work.  Example would be:

Code: [Select]
uint16_t i;
for (i=0; i<65535; i++) {
  // loop body
}
// loop body (executes with i=65535)

(*) by standard I mean a single loop variable that is incremented or decremented and tested against a constant value where the loop index is not modified within the body of the loop.  Since C places no such restrictions on the use of for statements so you can always cheat.
 
The following users thanked this post: georgian

Online iMo

  • Super Contributor
  • ***
  • Posts: 6948
  • Country: li
Re: ATmega32 for loop takes forever.
« Reply #11 on: December 17, 2018, 08:33:38 pm »
Quote
One teacher told me that i could add the outputs like this and i'm not sure how to calculate the resistors. He said something that the lower resistor(R11) should be 256 times bigger then the upper one(R10). I did some small tests with LTspice but i was not happy with the resuslts.
You have to add a third inverting opamp (with 1k in feedback) connected to X or Y making the "sum".
Take R11=256k and R10=1k.
The output will be (doublecheck!)

X_sum = ( (-1 * 5V * (1k/Rbinary_sum) / 256k) + (-1 * 5V * (1k/Rbinary_sum) / 1k) ) * (-1 * 1k)

« Last Edit: December 17, 2018, 08:44:29 pm by imo »
Readers discretion is advised..
 
The following users thanked this post: georgian

Offline georgianTopic starter

  • Regular Contributor
  • *
  • Posts: 61
  • Country: at
Re: ATmega32 for loop takes forever.
« Reply #12 on: December 17, 2018, 09:37:16 pm »
Quote
One teacher told me that i could add the outputs like this and i'm not sure how to calculate the resistors. He said something that the lower resistor(R11) should be 256 times bigger then the upper one(R10). I did some small tests with LTspice but i was not happy with the resuslts.
You have to add a third inverting opamp (with 1k in feedback) connected to X or Y making the "sum".
Take R11=256k and R10=1k.
The output will be (doublecheck!)

X_sum = ( (-1 * 5V * (1k/Rbinary_sum) / 256k) + (-1 * 5V * (1k/Rbinary_sum) / 1k) ) * (-1 * 1k)

Thank you! Great community!
I don't mind have negative Voltage on the output. I can set the Oscilloscope in XY mode and the start point top right. That will be my 0,0 coords.

Now with this formula:
I assume that the X_sum is the highest I will get wenn al the bits are 1, right? (All switches closed)
I think I understand your formula. You did it all in one go. Attached you can see my calculations so far. I will try to use your formula to calculate the X_sum. Thank you one again.
 

Online iMo

  • Super Contributor
  • ***
  • Posts: 6948
  • Country: li
Re: ATmega32 for loop takes forever.
« Reply #13 on: December 17, 2018, 09:51:02 pm »
The "1/Rbinary_sum" in my equation above is a parallel combination of the binary resistor weights:

1/Rbinary_sum = 1 / (1/1k + 1/2k + 1/4k ......), based on which binary weights are switched on..

So if I were you I would first calculate the parallel combination of switched on resistors, for example:

Rpar = 1/(1/1k + 1/8k + 1/32k..)

and the Vout of the first opamp will be

Vout = -1 * 5V * 1k / Rpar
« Last Edit: December 17, 2018, 09:59:05 pm by imo »
Readers discretion is advised..
 

Offline georgianTopic starter

  • Regular Contributor
  • *
  • Posts: 61
  • Country: at
Re: ATmega32 for loop takes forever.
« Reply #14 on: December 17, 2018, 09:58:53 pm »
I just check and the voltage when all the bits are set is: 9.99mV, acording to your formula.
(Vout upper OP AMP / 256K) + (Vout lower OP AMP / 1K) * - 1 for Vout I took 9.960V. Is something i have done wrong?
***EDIT: Total resistence is 501.960 Ohm
« Last Edit: December 17, 2018, 10:01:20 pm by georgian »
 

Offline georgianTopic starter

  • Regular Contributor
  • *
  • Posts: 61
  • Country: at
Re: ATmega32 for loop takes forever.
« Reply #15 on: December 17, 2018, 10:28:52 pm »
I did some more tests.
Let's say I write 2048 to PortB un PortD 0
PortB(Upper Bits) = 8  0b1000 -> PortB.3 = 1
PortD(lower Bits) = 0
Now for the Upper OP AMP I have the 16K and for the lower OP AMP i have nothing.
So the Upper OP AMP Voltage is -1  * 5V * (1K / 16K) = -312.5mV
The lower OP AMP is 0V
(-312.5mV / 1K) + (0V / 256K) =  -625µV I made a quick sketch in LT spice and it something different.
 

Online iMo

  • Super Contributor
  • ***
  • Posts: 6948
  • Country: li
Re: ATmega32 for loop takes forever.
« Reply #16 on: December 17, 2018, 10:36:34 pm »
I've prepared quickly a small excel for you.. Double check..
Yellow, Orange - inputs
Green - results

EDIT: fixed a bug in excel
« Last Edit: December 17, 2018, 10:49:06 pm by imo »
Readers discretion is advised..
 
The following users thanked this post: georgian

Offline georgianTopic starter

  • Regular Contributor
  • *
  • Posts: 61
  • Country: at
Re: ATmega32 for loop takes forever.
« Reply #17 on: December 17, 2018, 10:52:08 pm »
Well thanks a lot for your patience and help. I got it now. Great tool you made in excel.
The problem was with the two resistors.
Quote
You have to add a third inverting opamp (with 1k in feedback) connected to X or Y making the "sum".
Take R11=256k and R10=1k.
The output will be (doublecheck!)

X_sum = ( (-1 * 5V * (1k/Rbinary_sum) / 256k) + (-1 * 5V * (1k/Rbinary_sum) / 1k) ) * (-1 * 1k)

R10 should be 256K and R11 should be 1K. A did it with LT spice and its just like in the excel. I got it wrong before becouse i swapped the Two values.
Now i have to buy a lot of resistors and combine them, and hope to get a 0V from an OP AMP when no input is connected.

Topic considered to be closed and the issue fully solved. Thank you guys.
 

Online iMo

  • Super Contributor
  • ***
  • Posts: 6948
  • Country: li
Re: ATmega32 for loop takes forever.
« Reply #18 on: December 17, 2018, 10:54:17 pm »
I fixed a bug in the excel, so download the latest one above.

PS: below 1LSB value = 10V/65536
« Last Edit: December 17, 2018, 11:10:24 pm by imo »
Readers discretion is advised..
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf

 

-->