## XMega uint32_t calculation

21 posts / 0 new
Author
Message

Hi guys,

I'm reading a 20bit ADC value and I would like to apply an averaging filter on it. That's my code:

```uint32_t ADC_value = 0;

int main( void )
{
...

while(1) {

...
}

return 1;
}```

But the output is not like assumed. Do I have to take care about something, when working with uint32_t values?

What did you expect?

What did you get?

You should be able to add at least 4000 20bit numbers in a 32bit variable before encountering problems but just one question for you - since when has the Xmega had a 20bit ADC? Or is this external?

btw, why would you use a 20-bit ADC, only to throw away the 9 least significant bits?

I commented in an example.

```uint32_t ADC_value = 0;

int main( void )
{
...

while(1) {
// (511/512) is 0
// 0 + 0 is 0

...
}

return 1;
}```

I could suspect that subtraction of two unsigned integers can't give a negative result. So maybe you should try using int32_t instead.

I would re-arrange the parentheses in your calculations.

A simple way of doing an average is:

```for (count = 0; count < 512; count++)
average = total / count;
```

A running average can be calculated by:

`average = (total + read_ADC() - average) / count;`

Note that you don't increment count after you have got your first 512 samples.

In practice, any averaging only needs 8 or 10 samples. 512 seems a bit over the top !

Integer math is both fast and accurate. If you use floating point then you need not worry too much about fractional results from division.

David.

Thanks guys for your suggestions. I changed the uint32_t varibles to int32_t, like lagger told me...

Now it works fine :D

Well, now I have a new problem...

I extended an int16_t FIR low pass filter to int32_t. Input samples are 0 - 1048575 (20bit).

```static const int32_t coeffs[12] =
{
688,
1283,
2316,
3709,
5439,
7431,
9561,
11666,
13563,
15074,
16047,
16384
};

int32_t LPfilter(int32_t sample) {
static int32_t buf[32];
static int offset = 0;
int64_t z;
int i;

// Filter hard above a few Hertz, using a symmetric FIR.
// This has benign phase characteristics
buf[offset] = sample;
z = ((int64_t)coeffs[11] * (int64_t)buf[(offset - 11) & 0x1F]);

for (i = 0;  i < 11;  i++)
z += ((int64_t)coeffs[i]) * ((int64_t)buf[(offset - i) & 0x1F] + (int64_t)buf[(offset - 22 + i) & 0x1F]);

offset = (offset + 1) & 0x1F;
return  (int32_t) z;
}
```

If the input values are small, the filter works fine. But if the input values are bigger then int16_t it fails...

Fails HOW ?? How do you expect anybody to know what to do with that sentence ?! Sounds like overflow...

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

Why didn't you post the int16_t FIR low pass filter code so that we could compare it to the int32_t FIR low pass filter code above?

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

Presumably it's how you get sample, i.e. you do 16-bit arithmetik to get it and miss at some place or extend it to 32 bits too late so that the calculation is performed at 16 bits too long.

avrfreaks does not support Opera. Profile inactive.

Just a tip but when you have a problem like this take a compound statement such as:

`        z += ((int64_t)coeffs[i]) * ((int64_t)buf[(offset - i) & 0x1F] + (int64_t)buf[(offset - 22 + i) & 0x1F]); `

and break it into small steps assigning each step to a volatile (so watchable) variable then see what the intermediate values are and where precision/range may be getting lost.

Quote:
Fails HOW ?? How do you expect anybody to know what to do with that sentence ?! Sounds like overflow...

Yes, it produces an overflow.

Quote:
Why didn't you post the int16_t FIR low pass filter code so that we could compare it to the int32_t FIR low pass filter code above?

Here is the original code:

```static const int32_t coeffs[12] =
{
688,
1283,
2316,
3709,
5439,
7431,
9561,
11666,
13563,
15074,
16047,
16384
};

int16_t LPfilter(int16_t sample) {
static int16_t buf[32];
static int offset = 0;
int32_t z;
int i;

// Filter hard above a few Hertz, using a symmetric FIR.
// This has benign phase characteristics
buf[offset] = sample;
z = ((int32_t)coeffs[11] * (int32_t)buf[(offset - 11) & 0x1F]);

for (i = 0;  i < 11;  i++)
z += ((int32_t)coeffs[i]) * ((int32_t)buf[(offset - i) & 0x1F] + (int32_t)buf[(offset - 22 + i) & 0x1F]);

offset = (offset + 1) & 0x1F;
return  z >> 15;
}```

Is it maybe related to the filter coefficents?

The articact might also be related to PR39633. Check your compiler version against the versions that come with PR39633 fixed.

You can show the compiler version with

`gcc --version`

avrfreaks does not support Opera. Profile inactive.

Well my compiler version is 4.3.3. So it is possible, that this version will cause the problem. But I have already installed the newest version of WinAVR (WinAVR-20100110).

How can I change the compiler version in Windows?

Quote:

How can I change the compiler version in Windows?

Get AS6 (or just the "AVR Toolchain" separate installer) which will give you a 4.6 version of GCC.

(previously I woudn't have advised this but Atmel's latest release seems more stable - but look for posts from SprinterSB where he lists things that Atmel still have got wrong in their build of it).

To see if you actually hit that bug, you can scan the generated assembly for 3-instruction sequences like

```lsl
sbc
brne```

where the last instruction is a branch on Z-flag.

avrfreaks does not support Opera. Profile inactive.

I have installed AS6 now. It seams to be quite heavy. Is it also possible to use the new Atmel Toolchain now in AS4?

Quote:

Is it also possible to use the new Atmel Toolchain now in AS4?

Yes just point the project settings to:

```avr-gcc: C:\Program Files\Atmel\Atmel Studio 6.0\extensions\Atmel\AVRGCC\3.4.0.65\AVRToolchain\bin\avr-gcc.exe

make: C:\Program Files\Atmel\Atmel Studio 6.0\extensions\Atmel\AVRGCC\3.4.0.65\AVRToolchain\bin\make.exe```

Well, I can point to the new compiler, but it seams that it is not compatible:

```Build started 5.6.2012 at 18:36:48
avr32-gcc -I"xxx"  -mmcu=atxmega128a1 -Wall -gdwarf-2 -Os -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -MD -MP -MT main.o -MF dep/main.o.d  -c  ../main.c
cc1.exe: error: unrecognized command line option "-mmcu=atxmega128a1"
make: *** [main.o] Fehler 1
Build failed with 1 errors and 0 warnings...

```

I will build my project in AS6...