Creating a big volatile 16-bit array on an Attiny85

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

 

Hello folks,

In an attempt to debug a true RMS voltage measurement routine that uses ADC, interrupts and zero crossing detection, I am trying to create a HUGE array of 16-bit integers. What I would need is to create it with 100 elements, but, if I give it a size greater than 55, the Tiny85 (8KB) freezes as soon as it is turned on.

 

This array would keep for a while the ~95 ADC conversions that happen within an AC half cycle for further analysis. It would be filled through the ADC ISR.

 

It probably will not be included in the final version of the firmware, but now I need it to "see" how the voltage is being converted, work with low pass filters, etc.

The size of the complete code (which also includes I2C and timers) that I am flashing to Tiny85 is:

 

With a 100 elements array:

   text    data     bss     dec     hex    filename
   2558     258     280    3096     c18    adc_01.elf

 

With a 50 elements array:

   text    data     bss     dec     hex    filename
   2558     258     180    2996     bb4    adc_01.elf

 

Is there a dread obvious mistake at first sight?
Thank you very much!

// Includes ...

// Defines ...
#define ADCBUFFERSIZE	50

// Global variables ...
volatile uint16_t adcBuffer[ADCBUFFERSIZE] = { 0 };

// Prototypes ...

// Main
int main() {
	// Setup: fill the array with some data ...
	for (uint8_t i = 0; i < ADCBUFFERSIZE; i++) {
		adcBuffer[i] = 1023 - i;
	}
    // Loop
	for (;;) {
		// ...
	}
	return 0;
}

 

This topic has a solution.
Last Edited: Mon. Nov 27, 2017 - 05:15 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

The thing you are going to run out of first is RAM not ROM. Your avr-size output shows 2996/3096 bytes of flash. Given that the tin85 has 8192 bytes in total I wouldn't have thought a code size around the 3K out of 8K would be a concern.

 

Of more concern is the RAM. The device page on microchip.com says 512 bytes of RAM. You have:

 

data     bss
258     280

 

Add those together and you get 538 bytes but this is a device that only has 512 bytes to start with. What's more you can't use it ALL for .data and .bss as there has to be some stack space (usually about 20%+) so of 512 bytes you can only use about 410 bytes.

 

With 50 elements your BSS figure drops from 280 to 180. So overall it drops from 538 to 438. That is still "tight" but you might get away with it.

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

PS that 258 in .data....

 

That sounds a lot like it might be a 256 element look up table and then a couple more bytes elsewhere. If so, or if the 258 are all fixed data (like debug strings), then perhaps you want to look at putting those into __flash not RAM to leave more RAM free for your buffer in .bss?

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

Hello clawson,

 

Obviously, I was misinterpreting the result of avr-size. With respect to 256 elements lookup table, you also hit the nail, I have one to calculate CRC:

 

uint8_t crcTable [256] = {
     0x00, 0x9c, 0xa4, 0x38, 0xd4, 0x48, 0x70, 0xec, 0x34, 0xa8,
     .......

}

 

Though these are just tests, and I'm not trying to optimize the code yet, I think the time has come to leave laziness aside and start moving things to free some RAM, as you suggest.

 

Thank you very much for your help!

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

Just make that:

const __flash uint8_t crcTable [256] = {
     0x00, 0x9c, 0xa4, 0x38, 0xd4, 0x48, 0x70, 0xec, 0x34, 0xa8,
     .......

}

and you should find that your RAM usage immediately drops by 256 bytes which gives plenty for the ADC buffer then.

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

Rather than accumulating multiple measurements, then processing, do it "on the fly". In other words, use a single variable to sum the measurements, and add to that sum after every measurement. Then after N sums, compute sum/N. This should markedly reduce your RAM requirements. You may need to make the sum variable as 32 bit so that there is no overflow after 100 sums.

 

You could also reduce executing code size and executing time by summing 128 measurements. This allows the use of shifts rather than a true division to compute sum/N. To do this, you would need to increase your sample rate so that you get 128 samples into a full cycle of the observed signal. 

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

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

clawson wrote:
Just make that: const __flash uint8_t crcTable [256] = { 0x00, 0x9c, 0xa4, 0x38, 0xd4, 0x48, 0x70, 0xec, 0x34, 0xa8, ....... } and you should find that your RAM usage immediately drops by 256 bytes which gives plenty for the ADC buffer then.

 

I've got this:

 

avr-gcc -Os -g -std=gnu99 -Wall -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums  -ffunction-sections -fdata-sections  -DF_CPU=8000000UL  -DBAUD=9600UL -I. -I./nb-libs -mmcu=attiny85 -c -o adc_01.o adc_01.c
adc_01.c:95: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'uint8_t'
adc_01.c: In function 'CalculateCRC':
adc_01.c:484: error: 'crcTable' undeclared (first use in this function)
adc_01.c:484: error: (Each undeclared identifier is reported only once
adc_01.c:484: error: for each function it appears in.)
make: *** [adc_01.o] Error 1

 

Do I need something else in the Makefile?

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

Hello Jim, thanks for the comment

 

Yes, I'm doing that. The point is that the readings I get, while not so bad, do not have the accuracy that I would like.

When the oscilloscope shows, for example, 1.2 V RMS, I get 1.114 V in the AVR, when it shows 0.404 V, I get 0.372 and so on.

 

I would like to be able to "see" what values are really adding up in order to have conclusions.

One of the things I suspect is a displacement of the sampled signal with respect to the zero crossing, but I can not know it now.

 

main() {

    for(;;) {

        vRMS = (uint16_t)(Sqrt32(holdSqrVi / holdViSpl - ADCCYCLESADJ));

        calculated = true;

    }

}

 

// Pin change ISR (Zero Cross Detector)

ISR(PCINT0_vect) {

    if(ZCD_INP & (1 << ZCD_PIN)) {                    /* If it was triggered by a rising edge, run ISR code */

        if (phaseControl == true) {                   /* If it's trying to control the triac triggering delay, start Timer1 */

            TCNT1 = 0;                                /* Reset Timer1 counter */

            TCCR1 |= ((1 << CS13) | (1 << CS11));     /* Start Timer1 with prescaler 512 (I/O clock / 512) */

            TCCR1 |= ((1 << COM1A1) | (1 << COM1A0)); /* Enable Timer1 OC1A output pin toggling */

        }

        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        if (calculated == true) {             /* >>> If the hold variables were already used by the main  <<< */

            holdSqrVi = sumSqrVi;             /* >>> loop to calculate the squared root of sumSqrVi, then <<< */

            holdViSpl = adcConversions;       /* >>> they are loaded with fresh data and the "calculated" <<< */

            calculated = false;               /* >>> flag is released waiting for a new calculation.      <<< */

        }

        sumSqrVi = 0;

        adcConversions = 0;

        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    }

}

 

// ADC ISR (Runs over an AC half-cycle)

ISR(ADC_vect) {

    analogValue = ADC - ADCOFFSET;

    sumSqrVi += ((uint32_t)analogValue * (uint32_t)analogValue); /* TAKE A LOOK AT CALCULATION TIME HERE !!! */

    adcConversions++;

}

Last Edited: Tue. Nov 28, 2017 - 09:35 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

casanovg wrote:
I've got this:   avr-gcc -Os -g -std=gnu99 -Wall -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums  -ffunction-sections -fdata-sections  -DF_CPU=8000000UL  -DBAUD=9600UL -I. -I./nb-libs -mmcu=attiny85 -c -o adc_01.o adc_01.c adc_01.c:95: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'uint8_t'

What version of the avr-gcc toolchain are you using?

 

Doing

avr-gcc --version

on a command prompt will give you the answer. Copy the complete output of that command into a post here and we will also know and can give further advice.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Is this one ...

 

>avr-gcc --version

avr-gcc (WinAVR 20100110) 4.3.3
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

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

OK, that's an old compiler. The trick clawson showed will not work. (Do you have a specific reason to use an almost 8 year old compiler?)

 

In that compiler version you will need to use a combination of the PROGMEM "attribute" and functions like pgm_read_xxx(). There is a tutorial in the Tutorials forum on the subject.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Thank you Johan,

No special reason, I'm using it 'cause is the one mentioned in the book I started with, and its Windows installation is a no-brainer.

What one should I be using?

 

Last Edited: Mon. Nov 27, 2017 - 08:06 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

casanovg wrote:
What one should I be using?

There's no definitive "should", but if you install Atmel Studio you have a decent IDE with decent project handling, and you'll get a new and shiny compiler with it. No AVRDUDE though, so if you're using that then keep the WinAVR installation for running AVRDUDE.)

 

If you don't want Atmel Studio, but prefer another editor etc then the plot thickens:

- There is no later version of WinAVR than the one you're using

- Atmel has a standalone toolchain distrivbution, but it lacks some of the tools you have in WinAVR (e.g. AVRDUDE, GNU tools like GNU Make etc).

 

Keeping the WinAVR installation for the GNU tools but installing the Atmel toolchain for a recent compiler is an option. The devil is in the details.. (Ask if you want more details!)

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

Last Edited: Mon. Nov 27, 2017 - 08:20 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JohanEkdahl wrote:
Ask if you want more details!

 

I'm not sure I'm ready for the red pill yet :)

 

I tried Atmel Studio 7 for a few days at first, but considering that I do not know how to use the debugger, or any other of the "amenities" it offers, I was using it as a "super notepad".

 

Also, although I've written some lines of code in my life, I'm still a newbie with the AVR and its "macro" jargon, so I preferred to use a simple editor that does not magically assemble the environment without me knowing which header to include, etc. If I forgot to include something, at this point, I prefer a plain error.

 

Now I'm using Notepad++ and WinAVR, and yes, I need AVRDUDE.

I think I'll keep WinAVR, but I'll update it by following this recipe (https://www.insidegadgets.com/20...), with the latest toolchain I find ... (maybe this one? http://blog.zakkemble.co.uk/avr-...)

 

Thanks again!

Last Edited: Mon. Nov 27, 2017 - 09:33 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, I've updated the toolchain:

 

>avr-gcc --version
avr-gcc (GCC) 7.2.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

 

Now clawson's trick works like a charm ...

 

50-element array:

   text    data     bss     dec     hex filename
   2718       2     180    2900     b54 adc_01.elf

 

100-element array:

   text    data     bss     dec     hex filename
   2718       2     280    3000     bb8 adc_01.elf

 

There I go ... Thank you, guys!

 

Last Edited: Mon. Nov 27, 2017 - 09:42 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

casanovg wrote:
a simple editor that does not magically assemble the environment without me knowing which header to include, etc. If I forgot to include something, at this point, I prefer a plain error.

What on earth are you talking about?

 

Unless you start dealing with ASF/Start (and IMO you shouldn't, if you're using a plain 8-bit AVR) then Studio will not perform any magic like including files "magically". If you fail to include a ffile you'll get the same error in Studio as in your current development environment.

 

What Studio does give you is e.g. help with names of things. Start typing and Studio suggests alternative endings. That, IMO, is often (but not always) a help when learning. (Not to mention a speedup for any seasoned coder..)

 

RE "macro jargon" I suppose you're talking about predefined symbols for ports, pin numbers etc?

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

JohanEkdahl wrote:
Unless you start dealing with ASF/Start

Unfortunately, that is exactly what I did. When I started with AVR (around August) I was looking for a fast I2C slave solution for the Tiny85, so I found the AVR312 application note and I thought Ahaa! I downloaded the Start project in Studio and started trying to adapt it to the tiny, confident on that my no-so-vast C skills and past uP experience (Z80, 6809, a long time ago ...) would be enough. Short story ... I was wrong, after three days of frustration with the includes, macros, etc. I dropped everything, I got a book for beginners (E. Williams) and I started with UsiTwiSlave lib by Don Blake using Notepad ++ and WinAVR. By the way, the book suggests the environment I'm using, discouraging Studio, but maybe it's because it's aimed at beginners. Anyway, I'll follow your advice and I'll take the time to learn it when I finish the project I'm working on.

 

Regarding the "macro jargon", it's not a complaint nor criticism (is not my intention and I'm not in position for that), it's just an impression on how everything (in C) appears to be solved in the 8-bit AVR world from a platform newcomer's perspective.

 

Regards and thanks for your patience!

Last Edited: Tue. Nov 28, 2017 - 03:03 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

casanovg wrote:
The point is that the readings I get, while not so bad, do not have the accuracy that I would like. When the oscilloscope shows, for example, 1.2 mV RMS, I get 1.114 mv in the AVR, when it shows 0.404 mV, I get 0.372 and so on.

I'm very confused.  Signal levels "in the mud" like with the numbers given need near-perfect analog subsystems.  Your example readings are within a few percent.  Is the 'scope fully calibrated, with perfect probes?  Is an AVR8 the best tool to try to make a lab-quality instrument?

 

[in our industrial apps we use external circuity to do the "RMS", and the result is a single level read by an ADC channel.  It is "close enough" for nearly all work, and agrees well with Fluke meter readings.  Zero is zero, so if needed I do a single-point cal at a known level.]

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

theusch wrote:
Signal levels "in the mud" like with the numbers given need near-perfect analog subsystems

Hi theusch,

The final application of this V RMS measuring is to read current sensed by an ACS722 (hall-effect current to voltage converter). This IC happen to be a hard-to-believe noise source so, to attack the problem in stages, at this point (get an accurate RMS AVR routine) I'm injecting well-formed sine and triangle signals from a waveform generator. Considering this, I would expect "near perfect" AVR readings since:

 

  • The amount of ADC conversions per half-cycle (~95) is controlled by a pin change ISR.
  • I've thoroughly checked that the waveform generator's 0v gets an ADC "0", and 3.3v gets "1023".
  • The signals injected to be measured are in sync with the zero crossing detector.
  • So, the less accurate part of this test setup is the zero cross detector circuit output which feeds the pin change interrupt.

 

Considering this, If I have a "misalignment" between the measured signal's "0" and the ZCD's "0" detected by the pin change interrupt, I would be catching (sampling) the signal half-cycle a little before or after than what's required. This could be the origin of this small differences, that's why I want to "see" the values of each sampled Vi.
When this is solved, I'll have to work on a low-pass filter for the real ACS722 signals, but that's another story.

Last Edited: Tue. Nov 28, 2017 - 04:47 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

casanovg wrote:
The amount of ADC conversions per half-cycle (~95) is controlled by a pin change ISR. I've thoroughly checked that the waveform generator's 0v gets an ADC "0", and 3.3v gets "1023". The signals injected to be measured are in sync with the zero crossing detector. So, the less accurate part of this test setup is the zero cross detector circuit output which feeds the pin change interrupt.

Admittedly my numerical analysis training is 40+ years ago...

 

With 10-bit ADC and 3.3V reference, then each ADC count is 3+ mV.  Does the RMS in effect do over-sampling or other useful "filtering" to get more resolution?  Your complaint was a mis-match between a 'scope (that has not been said/proven to be fully calibrated, nor do we know the specs of the 'scope) reading and RMS calculations.  If each ADC count is several mV then how can the result be good to some microvolts?

 

And that assumes the "perfect" analog subsystem.  Although you are nominating your setup to be in that category, is the reference perfect with absolutely no jitter and no deviance from nominal values?  [in practice, the answer is always "no"]  Extend to ground and Vcc and the signal itself.  And that AVR model does not have a separate analog supply/ground.

 

How does a pin-change interrupt assure equally-spaced ADC readings?  Someone in one of your other threads recommended "adaptive" measurement of the half-cycle or full-cycle time, and then using that and a timer to equally space the sampling the next time.

 

I don't know your app aims, or the "best" way to read an ACS sensor.  I've done it in the past in a "good enough" fashion by 1)  getting a reading of the null signal -- this may not be exactly mid-scale IME;  and 2) reading the signal as fast as possible for a period of at least one full cycle.  [this is one of the few times I've used free-running]  The max and min readings during that time are averaged and that number compared to the "null" reading to get my value.  But that was just me.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

theusch wrote:
Your complaint was a mis-match between a 'scope (that has not been said/proven to be fully calibrated, nor do we know the specs of the 'scope) reading and RMS calculations

You left me thinking and ... I'm afraid I can't see the forest through the trees: how can I have 1.200 V RMS on the 'scope when I'm supposedly injecting a "pure" 3.3V peak to peak sine wave? It should be closer to 1.167 V RMS max.

 

Now, with respect to the difference between the 'scope readout (1.200 V RMS) and the calculation that the AVR delivers (1.114 V RMS), if I am not wrong (again), an error / difference of 3.2mV in each of the 95 ADC conversions per half-cycle, assuming that the error is skewed towards the same direction in all of them, gives a difference of 0.12% in the final measurement of Vrms, right? "My difference" is around 7%, but honestly now I do not know. I have to review all the test setup.

 

Assuming that the difference is real, since the ACS resolution is 132 mV/A, with my readings: 1.200 V - 1.114 V = 86 mV => An estimation error of 0.65 A on the 220VAC line! That is why I have to improve it.

 

By the way, the 'scope is not calibrated, it is a Rigol DS1102E, the function generator is a Rigol DG1022.

Thanks for your valuable help!

 

EDIT: I wrote mV instead of V in post #8, sorry!

 

 

Last Edited: Tue. Nov 28, 2017 - 08:57 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

casanovg wrote:
with my readings: 1.200 V - 1.114 V = 86 mV
casanovg wrote:
EDIT: I wrote mV instead of V in post #8, sorry!

I'm out.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.