Local array problem

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

Hi,
I have a theoretical question.
I declare an initialised local array in main() and then display all bytes on Lcd.

// Avrstudio 4.14.589
// Winavr 20071221
// Attiny2313
// 1 MHz

#include              
#include            
#include "lcd.h"            

int main(void)
{
uint8_t i;
uint8_t array[64]=  
{  
   0,  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, 34, 35, 36, 37, 38, 39,
   40, 41, 42, 43, 44, 45, 46, 47, 
   48, 49, 50, 51, 52, 53, 54, 55,
   56, 57, 58, 59, 60, 61, 62, 63  
};
   
   lcd_init();

   for(;;) 
   {	
      for(i=0;i<64;i++)
      {
         lcd_clr();
         lcd_byt(array[i]);
        _delay_ms(400);
      }
   }
}

But the display shows only numbers 0 to 56, then again 0 to 6.

When I increase space for array
uint8_t array[65]=

Or declare it static
static uint8_t array[64]=

then display shows correctly numbers 0 to 63.

What is wrong with the first declaration?

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

Visovian wrote:

What is wrong with the first declaration?
Nothing; it's perfectly valid C. I think you've probably run out of RAM. A 2313 has only 128 bytes, so your array uses up half of it.

If this theory is right, then it is pure luck that your code seems to work when you alter it. You need to look at the map file to see whether I am right or not.

Christopher Hicks
==

Last Edited: Thu. Sep 17, 2009 - 09:58 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Have you simulated it?

Charles Darwin, Lord Kelvin & Murphy are always lurking about!
Lee -.-
Riddle me this...How did the serpent move around before the fall?

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

Quote:
so your array uses up half of it.
Actually, probably all of it. The array initialization values are stored both in program memory and in ram. The initial values are copied from flash to ram in the c startup code, and are copied from ram to the 'stack' area set aside for that local array (frame pointer points to this). You hit a triple. I would want a double (static) or a single (progmem) instead.

Initialized non-static local arrays not a great idea if you want to conserve ram.

(Your local array set aside on the stack I assume was overlapping the initialized data in ram, and you were ending up with the array initializing with part of its own data 0-6. Or something.)

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

curtvm wrote:
The initial values are copied from flash to ram in the c startup code, and are copied from ram to the 'stack' area set aside for that local array (frame pointer points to this). You hit a triple.
I thought that was probably the case, but didn't want to say so without checking. I was particularly surprised that the code was reported to work with a local array of 65 bytes, but not with a local array of 64 bytes, so I didn't want to be too unequivocal about my conclusions.

CH
==

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

cmhicks wrote:
Visovian wrote:

What is wrong with the first declaration?
Nothing; it's perfectly valid C. I think you've probably run out of RAM. A 2313 has only 128 bytes, so your array uses up half of it.

The point of my question is:
When I want to initialise 64 bytes of local array
why I have to declare larger space than needed.
Why this declaration works
uint8_t array[65]= { 64 bytes }

and this one does not
uint8_t array[64]= { 64 bytes }

I think it cannot be little sram, even 80 bytes work when I declare
uint8_t array[81]= { 80 bytes }

LDEVRIES:
In simulator it worked right.

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

Quote:
Why this declaration works
uint8_t array[65]= { 64 bytes }
Well, if you look at the lss listing, you would figure it out. When you moved from 64 to 65, the compiler decided to do something different. Instead of copying from ram to frame (stack), it decided to just 'manually' put all those initialization values in the frame instead of copying them. You are still overwriting that ram data, but now it doesn't matter because its not being copied.

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

curtvm,
just a small correction: there is no data to be overwritten then.

Stefan Ernst

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

You are right. Missed that.

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

Visovian wrote:
Why this declaration works
uint8_t array[65]= { 64 bytes }
and this one does not
uint8_t array[64]= { 64 bytes }
It's luck, basically. The compiler has chosen to do something differently for the larger size array, and this has resulted in a different (possibly benign) behaviour, probably due to a different layout of variables in memory and/or different ways of initialising them. To figure out exactly what's going on you'd have to look at the map file and the disassembled code, but basically you're out of (or close to being out of) memory.

CH
==

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

Dear friends,
Thank you all for your replays.

I did not realise that the array is copied from RAM to stack, so that two sets of array data must fit into RAM. Then the size of array has to be less than a half of RAM. In my example I found the critical size was 56 bytes. (RAM=128)
The trick with declaring bigger array is still not quite clear, but I will investigate it no more.

I would not use this code in my program.
I only wandered how things were and I learned it.

Thanks

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

As no one seems to have mentioned it, I will. If those bytes in that array are constant then you want to be using PROGMEM and pgm_read_byte() to access it. This will save your precious SRAM

Cliff

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

Find out about the PROGMEM stuff in [TUT] [C] GCC and the PROGMEM Attribute

Stu

Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

Newbie? Be sure to read the thread Newbie? Start here!

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

Clawson:
stu_san:

Yes, I use flash tables for constants.
My question was only academic one.

When I declare

int main(void)
{
uint8_t array[8]= { 0,  1,  2,  3,  4,  5,  6, 7 };

there are two copies of array in RAM (see ram1.gif). It is ok, just as curtvm described.

But when I fill only a part of array

uint8_t array[8]= { 0,  1,  2,  3,  4,  5,  6 };

then only one copy is in RAM (ram2.gif).
That is what confused me.

Attachment(s): 

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

Visovian wrote:
That is what confuses me.
The compiler chooses different strategies for filling the array (whysoever). If the initialization data has the same size than the array, he generates a loop which copies the data from the .data section. If the initialization data is smaller than the array, he generates a long chain of ldi/store command pairs.

Stefan Ernst

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

I really don't know, but I suspect that a local array which is sized bigger than the initialized data provided, ends up clearing the array before the data in the local array is initialized. This probably is the reason (and the trigger) for the different approaches the compiler uses.

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

Quote:

I really don't know, but I suspect that a local array which is sized bigger than the initialized data provided, ends up clearing the array before the data in the local array is initialized. This probably is the reason (and the trigger) for the different approaches the compiler uses.

But... Local (ie. automatic) variables are not cleared (zeroed) as opposed to statically allocated variables.

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:
But... Local (ie. automatic) variables are not cleared (zeroed) as opposed to statically allocated variables.
Yes, but the initialization {} includes implicit zeros for the not explicitly given values.

So the strategy of the compiler is to first fill the whole array with the implicit zeros and then insert the explicitly given values. Keep in mind that something like this is possible:

int a[20] = { [3]=1, [15]=1 };

Stefan Ernst

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

Got it!

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

So the compiler uses different methods for fully and partly initialised array.

What a pity it does not use the method with one copy of array in ram also for full initialisation.

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

Visovian wrote:
What a pity it does not use the method with one copy of array in ram also for full initialisation.
So obviously you haven't noticed so far that this method consumes much more Flash. If you want a solution with low Flash and low RAM usage, use PROGMEM (as already mentioned multiple times).

Stefan Ernst

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

And note that PROGMEM data arrays need to be global, not local.