XMega uint32_t calculation

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

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;
uint32_t av_ADC = 0;

int main( void )
{ 
   ...

   while(1) {
      ADC_value = readADC();
      av_ADC = av_ADC + ((ADC_value - av_ADC) / 512);

      ...
   }

   return 1;
}

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

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

What did you expect?

What did you get?

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

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?

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

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; 
uint32_t av_ADC = 0; 

int main( void ) 
{ 
   ... 

   while(1) { 
      ADC_value = readADC(); // returns 511
      // (ADC_value - av_ADC) is 511
      // (511/512) is 0
      // 0 + 0 is 0
      av_ADC = av_ADC + ((ADC_value - av_ADC) / 512); 

      ... 
   } 

   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.

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

I would re-arrange the parentheses in your calculations.

A simple way of doing an average is:

for (count = 0; count < 512; count++)
    total += read_ADC();
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.

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

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

Now it works fine :D

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

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...

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

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

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

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

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

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.

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

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.

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

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?

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

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.

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

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?

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

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).

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

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.

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

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

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

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

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

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...

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

AVR32-GCC requires "-mpart" rather than "-mmcu" if I remember correctly.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

What is an AVR32 thread doing in the Xmega forum? (which is what misled my advice above and possibly that of others). Shoudl I move this to an AVR32 forum?