3
\$\begingroup\$

The setup is as follows:
I have a little program to drive single color 8x8 led matrix using 595 shift registers that are supplied with data by ATTiny85 through USI as SPI Master. I upload program to ATTiny85 using Arduino Uno. Program is compiled and uploaded using Visualmicro plugin for VS2010 or Arduino IDE (both with the same results). Compiled program is 2970 bytes long (36.3% of chip's memory)

The issues are:

  1. The Array Problem: I cannot declare array that is longer then 296 bytes.
    I have array that holds binary representation of a font to display characters on LED matrices. The desired size for this array is 760 bytes. It is declared as follows:

    byte font[] =
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Char 032 ( )
        0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00, // Char 033 (!)
        ...
        0xE0, 0x30, 0x30, 0x1C, 0x30, 0x30, 0xE0, 0x00, // Char 125 (})
        0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // Char 126 (~)
    }// 760 bytes total
    

    If I refer to first element of the array in the code, I receive 648th element [first byte of fonts character 113 (q)]. Whole array is messed up. Blocks of 8 bytes or more (n*8bytes) of the arrays content are mixed up with each other and with completely unrelated areas of memory. If I try to display any text on on the matrices I see completely different characters or some mess (I think what I actually see is the very program running in the memory - it's cool but useless). If I cut the array down to 296 bytes everything works fine.

  2. The Pointer Problem- to work around problem #1 I split the array into 3 smaller arrays(296 bytes max). I declared pointer to point to proper font array depending on character to "render". I cannot point this pointer to any array inside the "if" block

    char c1='a';  //character to display
    byte font1[]={...};  //binary font representation split in to 3 arrays
    byte font2[]={...};  
    byte font3[]={...};
    byte  ascii_offset1= 32,ascii_offset2= 69,ascii_offset3= 106;  //offset for each array
    byte * font_ptr1=font1; //This works fine. 
    font_ptr1=font3;        //This also worked fine in tests. 
    
    if(c1>=ascii_offset3)  
    {   
        font_ptr1=font3;  //This DOESN'T work at all
        c1-=ascii_offset3
    }
    else ...
    

In fact I think that line, commented as not working, is actually hanging up the ATTiny. I see nothing on matrices, except for few LEDs constantly lighten up.

In case of issue #1 I suspect that compiler or linker messes something up. But #2 is total mystery to me. I thought that maybe it's stack overflow, but according to documentation stack size is limited only by SRAM size, witch is plenty and additionally I don't allocate any memory dynamically.

\$\endgroup\$
7
\$\begingroup\$

Follow the steps in this post to check your RAM usage:

Checking memory footprint in Arduino

My guess is that you have gone over as the RAM size of the ATTiny85 is 512 bytes. In your sketch, font will be stored in RAM. You want to store it in the FLASH program memory. Follow these instructions to do so:

http://www.arduino.cc/en/Reference/PROGMEM

\$\endgroup\$
  • \$\begingroup\$ Thanks. That definitely worked. I'm a newbie in microcontrollers world. I got used to more uniform model of memory (Princeton architecture) while Attiny is harvard architecture. (I love Wikipedia :) ) \$\endgroup\$ – Tomek Jul 5 '13 at 20:49
  • \$\begingroup\$ Yes, it is a bit counter intuitive to start with. In the compiled c/c++ program global variables are initialised on start up. In your original code the values for font will therefore be copied from progmem into sram on startup. This means strings also go into sram. You can instead put them into progmem using the F() function, i.e. Serial.println(F("hello world!")); instead of Serial.println("hello world!"). \$\endgroup\$ – geometrikal Jul 5 '13 at 22:11
2
\$\begingroup\$

Now that geometrikal has answered your question, here's a tip to how you could have found out yourself: inspect the memory map (also sometimes called a 'listing'). Depending on which compiler you're using (I'm not familiar with the Arduino IDE, but avr-gcc/wingcc as the backend I'm guessing?) it usually just takes a command line parameter to get the compiler to output the memory map as well. On GCC front ends the option to pass is -Wl,-Map=filename.map

The memory map is a text file consisting of symbols, their start address, end address and how much of that space is used. The output will vary for different compilers, but usually it will contain at least this:

Memory Configuration

Name             Origin             Length             Attributes
text             0x0000000000000000 0x0000000000002000 xr
data             0x0000000000800060 0x000000000000ffa0 rw !x
eeprom           0x0000000000810000 0x0000000000010000 rw !x
fuse             0x0000000000820000 0x0000000000000400 rw !x
lock             0x0000000000830000 0x0000000000000400 rw !x
signature        0x0000000000840000 0x0000000000000400 rw !x
*default*        0x0000000000000000 0xffffffffffffffff

As an overview of each segment, and then a more detailed picture that will tell the size of each symbol - loosely meaning each variable or function used.

You had a hunch that your problem was memory related. My natural reaction to that is usually to inspect the memory map and see if something looks wrong :)

If you had known the memory limitation of the ATTiny, and you'd looked in the memory map and found that some array occupied 760 bytes in RAM instead of FLASH, you'd have known.

The size tool in the GNU-binutils suite will also output the size of each segment, but usually cannot output the size of each symbols, as that knowledge can be lost during compilation.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.