1

I bought an ATmega32 IC recently, but now I found out the program I wrote in Atmel Studio reports an error due to an overflow of memory. It is 134.1% over the recommended memory of this chip. Are there alternatives that exist?

I don't want to go and buy another chip as they are quite expensive.

Peter Mortensen
  • 1,676
  • 3
  • 17
  • 23
JoeyB
  • 1,804
  • 13
  • 34
  • 14
    If you insist on using that chip then your only option is to improve your code. – Transistor Aug 21 '18 at 11:49
  • 8
    32KB is a lot of program memory, which suggests either you have a very complex application or you should be able to find a lot of ways of reducing size. Are you using any add-on libraries or an RTOS, if so can you try rewriting without them? If you're using floating point, can you rewrite to only use integer arithmetic? – Jules Aug 21 '18 at 11:52
  • 5
    Do you have -Os optimisations turned on? – Jon Aug 21 '18 at 11:59
  • It is important to factorize your code when space is important, this means that if you have some piece of code (a couple of lines) that is repeated more than once, then make a function of it and call it. – Harry Svensson Aug 21 '18 at 12:02
  • 2
    It's also handy to minimize the amount of strings you (say) would want to print over the serial. Those can get pretty large fast. Also, you could also store some large, not too often accessed constants in the EEPROM, if you have any space left there. – Richard the Spacecat Aug 21 '18 at 12:04
  • 4
    Program memory or RAM? The latter is a lot smaller and easier to fill with e.g. constant data, which the compiler has to arrange to appear in RAM, since you can't access the program memory with the same instructions as RAM. – ilkkachu Aug 21 '18 at 15:26
  • You should share a lot more information about your code (the question is ***way*** too broad as it is now). For starters, how many lines of code are there and in what language (C?)? What libraries, if any, are used (e.g. post the #include lines)? – Peter Mortensen Aug 21 '18 at 21:05

3 Answers3

10

Global variables/types

  • Changing the type of global variables (e.g. use uint8_t or a similar 1 byte instead of long), or use bits to store boolean arrays.
  • Remove static variables and replace them by dynamic (local) variables if possible. Passing them as arguments might be used to keep the scope longer.

Data/precalculated tables

  • In case you now keep (fixed) data structures in your code (e.g. for pre calculated tables), than put these in external Flash. Executable code is hard to put in external Flash, but tables/data is not. Of course this comes with a performance loss. Another way is to calculate it on the fly (no calculated table needed at all).
  • Instead of using pre calculated data tables at all, calculate them; this might cause a performance loss.
  • In case you are using a lot of stored texts or data, 'compress' them if possible. The decompression code will cost some Flash, but if you have a lot of text, it might be worthwhile.

Executable code

  • Using for loops instead of calling functions one by one.
  • Check for repeated code and create functions of them, use parameters to differ between small changes; this will cause a (small) performance loss.
  • Prevent 'inline' or long #define statements/code, these are substituted (copied) wherever used.

Logging/tracing

logging strings can consume many bytes (e.g. for one log string like: "The current temperature is: " cost 29 bytes). Having many log strings can add up a lot. To prevent this you can:

  • Use shorter strings ("CurTemp: " is only 9 bytes).
  • Print an integer (cost 1 or 2 bytes, depending on the int size).
  • Send this integer to another microcontroller which converts it to human readable text. It cost a bit of overhead/peripheral overhead.
  • When debugging, put all logging in #ifdefs, and save Flash by reducing functionality you don't need for testing. When not debugging, all logging statements will not cost any bytes.

Libraries

  • Finding alternative libraries which are implemented differently but with the functionality you need.

Compiler options

  • Check compiler options to see if the code can be compiled in a different way; mostly it will be a trade off against performance.

What you should NOT do

  • Make your code a few bytes smaller by using obscure code implementation. This will bite you later when you maintain your application.
  • Removing unused functions does not help (the compiler is smart enough to do this for you).
Michel Keijzers
  • 13,867
  • 18
  • 69
  • 139
  • 1
    Remember to differentiate between data and program size. The question probably refers to program size (though it does not actually say which). Things like buffers won't really figure into that, but various ways of handling data can cost more program size. – Chris Stratton Aug 21 '18 at 13:00
  • 1
    First point can be misleading: there's no guarantee (in general) that changing to a smaller variable size leads to savings. In this case, it should as it's an 8bit device. I would also avoid "char" for variables - use actual integer types like uint8_t, for example, rather than something that happens to be 8bits wide. – awjlogan Aug 21 '18 at 13:01
  • @ChrisStratton I know the difference, but indeed, buffers are typically not initialized and thus not placed in Flash. I adapted the answer, thanks for the notification. – Michel Keijzers Aug 21 '18 at 13:48
  • 1
    @awjlogan uint8_t is indeed better, and with int I meant a bigger type, I adapted my answer, thanks for the notification. – Michel Keijzers Aug 21 '18 at 13:49
  • 2
    @awjlogan `uint8_t` is not "actual integer type": it's a `typedef`, and most likely to `unsigned char` (dunno what types ATmega actually has). – Ruslan Aug 21 '18 at 15:34
  • @Ruslan Yes, it is a typedef (arguably all variables are), but the difference is it's defined as part of the language spec as of C99. It may well map on to `char`, see https://stackoverflow.com/questions/11698535/is-char-a-special-type-of-integer-variable – awjlogan Aug 21 '18 at 15:54
  • 1
    @awjlogan I only use (u)int8/16/32t types for integer (like) types, to prevent microprocessor related issued. and char for characters like 'a'. For booleans I normally make an own type (bool_t which is defined as unsigned char_t). – Michel Keijzers Aug 21 '18 at 15:56
  • @MichelKeijzers Yep - that's what I was driving at. Also a note, that if this were say a 16bit micro, forcing it to use 8bit values may not result in improvements. – awjlogan Aug 21 '18 at 16:14
  • @awjlogan you mean because of 16 bit alignment? For separate variables it would not matter, but for an array it will. – Michel Keijzers Aug 21 '18 at 16:34
  • 1
    @MichelKeijzers Yes - there's no guarantee that naively changing to a narrower variable will lead to a reduction in code size if it's smaller than the processor's native size. – awjlogan Aug 21 '18 at 20:18
  • @awjlogan also not if you declar an array of 4 'int8_t' or chars ... I am under the assumption it will be always 4 bytes. However, if you declare only one variable of int8_t/char than it will be one byte, but 1 or 3 bytes might be added to align to 16 or 32 bits. – Michel Keijzers Aug 21 '18 at 20:22
  • 1
    @MichelKeijzers On an 8bit system, yes, your array will be 4 bytes. However, `uint8_t array[4]` on a 32bit system, may compile to 16bytes. Alignment is different, but a bit off topic for this Q. Take home message: experiment and see, don't just do what people sometimes say you should! – awjlogan Aug 21 '18 at 21:10
  • @awjlogan Thanks for that ... I didn't know about the 16 bytes (and I'm born 'healthy stubborn' so I like to test before believing). – Michel Keijzers Aug 21 '18 at 21:32
  • 1
    The problem with kitchen sink answers like this is that they inevitably include conceptual errors. For example, no, "removing includes" will not generally reduce code size, both because that's not where things that take space are found, and because even if it were, any decent linker invoked with proper options will drop *unused* items and not include them in the final output. – Chris Stratton Aug 21 '18 at 21:43
  • @ChrisStratton You are right, at least if it is programmed well; normally only in .c files static data is reserved, and even than a compiler will ignore it, I will remove it from the answer. Thanks – Michel Keijzers Aug 21 '18 at 21:53
5

Unfortunately, adding external program memory is not usualy possible with this kind of chip. You could conceivably read and execute code from an external flash, but it would likely be slow and unstable.

You may be able to reduce the size of the compiled code, by eliminating static variables and removing unused libraries.

If you cannot find a way to to reduce the code size, you can look at MCUs of the same architecture here: https://www.microchip.com/design-centers/8-bit/avr-mcus

Tim Vrakas
  • 441
  • 3
  • 15
  • 1
    I wanted to add that an AVR controller can execute code only in its FLASH memory. Loading code from an external source would either require burning it into the internal flash, which is a stupid idea, or an emulator that parses the opcodes in software. A chip with more memory is the solution to go for if the code size cannot be reduced. – GNA Aug 21 '18 at 14:07
3

Atmega32 is like a stripped down Atmega644x or Atmega1284P. Change the chip to get a lot more memory, more SRAM (up to 16K bytes), and dual hardware serial ports.

CrossRoads
  • 3,453
  • 1
  • 6
  • 14
  • For some bizarre reason the atmega 1284 is priced alot cheaper than the atmega 32 but it has more memory. Wouldn't have expected that when I Google it. Thanks for the advice. This new chip does solve the whole problem – JoeyB Aug 25 '18 at 09:40