M328 FLASH "Almost" Full SOLVED

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

Greetings -

 

I have a ATmega28P that I use in a commercial application. It was close to 92% flash usage in its normal form.

 

I need to add a small bit of code, temporarily, to monitor battery voltage. What with the state machine to manage the combination of ADC and sleep, the added write to the uSD to store the value, the new terminal menu category, and such, I am now at 99.4% (about 200 bytes remaining).

 

BOOTRST is unprogrammed and both both BOOTSZ bits programmed (default in all these cases).

 

Just beginning to debug the changes, so memory used might increase or decrease by a few bytes. I CAN rip out some of the menu strings that provide error messages for this special temporary case. Could get back several hundred bytes, there, probably.

 

Am I in trouble? Is there anything special I need to watch out for?

 

Thanks

Jim

This topic has a solution.

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

Last Edited: Fri. Oct 27, 2017 - 06:02 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Will your newly added code also require an increase in Stack allocation?

 

JC

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

RAM usage went from 65% to 66% at 1355 bytes. 1 local variable added. I think that is still a reasonable margin. EEROM is just a few percent, no change.

 

Jim

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

Last Edited: Fri. Oct 27, 2017 - 01:44 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If it is only temporary code, then as long as you have room in RAM for the stack I would say you are ok as there is nothing written to flash (unless you are doing something there too).

 

JMO

 

East Side Jim

If you want a career with a known path - become an undertaker. Dead people don't sue! - Kartman

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user

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

I was afraid of something like a codeblock that begins in normal application space not being able to execute into bootload space. Or const __flash strings in the bootload space not being accessible. Or something else, obtuse, like that. Something odd that the hardware might  do but the compiler ignores. After all, it seems to know nothing about boot flash.

 

Jim

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

Last Edited: Fri. Oct 27, 2017 - 02:44 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You could always run the code in the simulator and see what happens....or if you have an ICE run the debugger on the actual hardware.

 

Cliff should be up in a few hours and probably has the definitive answer for you  wink

 

Cheerio!

If you want a career with a known path - become an undertaker. Dead people don't sue! - Kartman

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user

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

On the Xmega, at least, I believe one has to program the Bootloader space differently, (different commands), but if the Bootlaoder isn't being used then that space is indistinguishable from the main program memory.

 

Not sure that helps with the Mega...

 

JC

 

Edit:Typo

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

I think that is true for Mega but with nothing written (that I can find), it is hard to say, definitively.

 

Jim

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

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

Just make sure your lock bits are set to permit LPM everywhere.  BLB0 mode 2 and BLB1 mode 2 seem most appropriate, but mode 1 (for both) would also work.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

Thanks - I had not looked at those bits!

 

Jim

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

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

ka7ehk wrote:
... It was close to 92% flash usage in its normal form.

...

the new terminal menu category,

...

I CAN rip out some of the menu strings that provide error messages for this special temporary case. Could get back several hundred bytes, there, probably.

Continue on for more.

Consider that an MCU contain the minimal essential functions with other functions in the operator interface PC or Mac (ie printf and scanf there)

ka7ehk wrote:
Am I in trouble?
No for it's "grow or die" wink

Glad you're having to deal with increased functionality and ideally an increased number of customers or operators.

 

Edit: second quote

 

"Dare to be naïve." - Buckminster Fuller

Last Edited: Fri. Oct 27, 2017 - 02:07 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Got any EEPROM spare?

 

Nothing to stop you putting any text strings in there.

'This forum helps those who help themselves.'

 

pragmatic  adjective dealing with things sensibly and realistically in a way that is based on practical rather than theoretical consideration.

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

You can use every last byte of Flash. The Compiler will tell you if you have run out.
And if you are using the Arduino IDE, it will tell you if you have run out of App space. e.g. Optiboot only needs 512 bytes which means you have 32256 bytes for your App. A more profligate bootloader leaves less room for your App. e.g. the Duemilanove bootloader.
.
As long as your code fits, you are fine. Of course, one day your client will ask for an extra feature.
Sometimes a new compiler version increases the code size.
.
SRAM is more difficult. With GCC you just have to guess. 80% usage is generally a good safety margin. But you have to follow simple rules e.g. avoid large local arrays, recursive code, and things like malloc().
.
If you are not using all the EEPROM, you can store data there. With only minimal code to access from EEPROM instead of Flash.
.
David.

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

DocJC wrote:
Not sure that helps with the Mega...
It doesn't. Xmega have something like 32K+2K of flash - the bootloader space really is "extra". In a mega the bootloader is an optoinal part of the main flash so for a 32K chip there really only is 32K and if you use 2K for a bootloader then you only have 30K left for the app.

 

It's actually one of the few things about Xmega I think is attractive! ;-)

 

My left of field suggestion would be to consider moving to the 164/324/644/1284 range just for temporary development. I think there's enough similar about the 48/88/168/328 and 164/324/644/1284 ranges that most of the peripheral code will just "slot in". But now you can grow up to 128K flash if you need to. Obviously there is the small detail of the fact it's a switch from 28 to 40 pins though!

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

Are you putting your text strings in flash using the PSTR option?  You could get rid of that and store strings in RAM the usual way.  That would just shift memory usage from flash to data memory.  I guess putting the text strings in EEPROM as has been suggested saves on both.  I didn't know you have to leave space in RAM for the stack, but I guess it has to reside somewhere.

 

My understanding is if your program overruns into bootloader space it will continue on happily as long as you are not using a bootloader.  Is that right, Cliff?  So if the usage calculation is excluding the bootloader space, you have an additional 256 bytes if your fuse is set to the smallest bootloader.

 

I switched one of my projects from an ATmega328P to an ATmega1284P, and it was pretty painless.  It is a big chip, physically, and I am using the -PU PDIP version.  The pinout is a little different for things like SDA and SCL, and some of the register definitions change for timers and such, but if I had no trouble porting code from one to the other you should have an easier time, being more experienced.  I like the 1284P.  It has 2 UARTs and lots of memory.

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

Moving strings to ram does not save flash space as they are copied from flash to ram at C startup!

 

Jim

 

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

MarkThomas wrote:
You could get rid of that and store strings in RAM the usual way. That would just shift memory usage from flash to data memory.
Err no.

 

The options are strings in both flash and RAM (what you get if you don't do anything "special") or strings in only flash. There is no "strings only in RAM" possibility. (stop and think about that for a while and you will realise why!)

MarkThomas wrote:
Is that right, Cliff?
Yes. As I say in a 32K micro you can choose to have a "partition" at 31.5K, 31K, 30K, 28K (I think the options are) but this only really applies if you are using BOOTRST and you really do have "two programs" in the AVR. In that case you don't want one to "bump into" the other. But if you are only using the app and starting from 0x0000 it doesn't matter where BOOTSZ sets the "boundary" - it's only notional and the app can fill the entire 32K. It's not like the bootloader area is an unapproachable wasteland with a DMZ barrier between the two!

Last Edited: Fri. Oct 27, 2017 - 04:26 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't understand why strings are stored in both places, and thinking about it has done me no good.  I did a test.  I ran my code with a bunch of outputs like the following sending text out UART:

memset(OutBuffer, 0, BUF_SIZE);
strcpy_P(OutBuffer, PSTR(" n = Number of multiplexers to use\r\n"));
UART_Transmit_Buffer(OutBuffer);

Which I thought meant the string is stored in program memory, and looked at memory usage

 

Then I changed them to look like:

memset(OutBuffer, 0, BUF_SIZE);
strcpy(OutBuffer, (" n = Number of multiplexers to use\r\n"));
UART_Transmit_Buffer(OutBuffer);

Which I thought stored the string in data memory instead of flash, but indeed flash memory usage did not change appreciably and data memory usage went up by the number of characters in the text strings, so it looks like you are correct that in the first case the strings are stored in flash only, and in the second case they are stored in both.  But I still done understand why.  I thought doing the strcpy_P would copy the strings to OutBuffer in data memory so UART would have access to them.  I don't understand why the strings are saved in both places if I don't do the pgmspace stuff.

 

Again, confusion reigns.

 

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

MarkThomas wrote:

I don't understand why strings are stored in both places, and thinking about it has done me no good.

 

How do they get into RAM in the first place?

'This forum helps those who help themselves.'

 

pragmatic  adjective dealing with things sensibly and realistically in a way that is based on practical rather than theoretical consideration.

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

This is a temporary mod to test solar battery charging for the unit. It will be used in my shop and at one customer. If it (solar charging) is added, it will be part of a major rewrite that should result in smaller code space (no more terminal access, configured from a config file on the uSD card). But, right now, I need to know if the battery charge is being maintained adequately (under winter conditions in our grey climate), so I add an ADC read of the battery, data write to the CSV data going to the uSD card, and terminal access to that value. 

 

So, for the standard build, the code remains unchanged, but there will be two that have this mod. 

 

#17 is the critical answer. Thanks, Cliff.

 

Jim

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

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

Brian Fairchild wrote:
How do they get into RAM in the first place?

The compiler puts them there?

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

MarkThomas wrote:

Brian Fairchild wrote:
How do they get into RAM in the first place?

The compiler puts them there?

 

And how do they stay there when you turn the power off? We are talking about RAM remember.

'This forum helps those who help themselves.'

 

pragmatic  adjective dealing with things sensibly and realistically in a way that is based on practical rather than theoretical consideration.

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

Its my understanding that the compiler puts them in flash. On bootup, it then copies them into SRAM. Thus, TWO memories are occupied by the same material. General bummer, but thats the way it is.

 

Jim

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

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

Brian Fairchild wrote:
And how do they stay there when you turn the power off? We are talking about RAM remember.

Duh.  My turn to be the doofus today.  That's what Cliff meant by thinking about it and it would be clear.  And Jim's comment went right over the top of my head.  Now it seems pretty obvious.  Thanks guys.  

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

ka7ehk wrote:

Its my understanding that the compiler puts them in flash. On bootup, it then copies them into SRAM. Thus, TWO memories are occupied by the same material. General bummer, but thats the way it is.

 

Exactly that.

 

Between the reset vector and main() the compiler does a load of basic setup stuff like setting the hardware stack pointer for the call stack, setting up any software stacks for local storage and copying any constants from Flash to RAM.

 

Traditional C compilers ran with constants in RAM because that's all there was. Hence compilers for micros have keywords like 'flash' to tell them to leave the constant tagged that way in flash and not to copy it to RAM. CVAVR has a compiler tick box to tell it to leave all constants in the flash.

 

So on an AVR it makes little sense to use up precious RAM with your constants as you can quite happily run with them in flash.

 

But for this topic what is important is that every byte of a constant uses up a byte of flash and hence a byte of potential code space. Flash and code space are, after all, one and the same thing.

'This forum helps those who help themselves.'

 

pragmatic  adjective dealing with things sensibly and realistically in a way that is based on practical rather than theoretical consideration.

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

Brian Fairchild wrote:

Between the reset vector and main() the compiler does a load of basic setup stuff like setting the hardware stack pointer for the call stack, setting up any software stacks for local storage and copying any constants from Flash to RAM.

 

As I currently have a .lst file open you can see what happens under the hood...

 

__RESET:
	CLI
	CLR  R30
	OUT  EECR,R30

;INTERRUPT VECTORS ARE PLACED
;AT THE START OF FLASH
	LDI  R31,1
	OUT  MCUCR,R31
	OUT  MCUCR,R30

;CLEAR R2-R14
	LDI  R24,(14-2)+1
	LDI  R26,2
	CLR  R27
__CLEAR_REG:
	ST   X+,R30
	DEC  R24
	BRNE __CLEAR_REG

;CLEAR SRAM
	LDI  R24,LOW(__CLEAR_SRAM_SIZE)
	LDI  R25,HIGH(__CLEAR_SRAM_SIZE)
	LDI  R26,LOW(__SRAM_START)
	LDI  R27,HIGH(__SRAM_START)
__CLEAR_SRAM:
	ST   X+,R30
	SBIW R24,1
	BRNE __CLEAR_SRAM

;GLOBAL VARIABLES INITIALIZATION
	LDI  R30,LOW(__GLOBAL_INI_TBL*2)
	LDI  R31,HIGH(__GLOBAL_INI_TBL*2)
__GLOBAL_INI_NEXT:
	LPM  R24,Z+
	LPM  R25,Z+
	SBIW R24,0
	BREQ __GLOBAL_INI_END
	LPM  R26,Z+
	LPM  R27,Z+
	LPM  R0,Z+
	LPM  R1,Z+
	MOVW R22,R30
	MOVW R30,R0
__GLOBAL_INI_LOOP:
	LPM  R0,Z+
	ST   X+,R0
	SBIW R24,1
	BRNE __GLOBAL_INI_LOOP
	MOVW R30,R22
	RJMP __GLOBAL_INI_NEXT
__GLOBAL_INI_END:

;GPIOR0 INITIALIZATION
	LDI  R30,__GPIOR0_INIT
	OUT  GPIOR0,R30

;HARDWARE STACK POINTER INITIALIZATION
	LDI  R30,LOW(__SRAM_END-__HEAP_SIZE)
	OUT  SPL,R30
	LDI  R30,HIGH(__SRAM_END-__HEAP_SIZE)
	OUT  SPH,R30

;DATA STACK POINTER INITIALIZATION
	LDI  R28,LOW(__SRAM_START+__DSTACK_SIZE)
	LDI  R29,HIGH(__SRAM_START+__DSTACK_SIZE)

	JMP  _main

 

...all that between the reset vector and main(). (That's for CVAVR BTW).

'This forum helps those who help themselves.'

 

pragmatic  adjective dealing with things sensibly and realistically in a way that is based on practical rather than theoretical consideration.

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

ka7ehk wrote:
Its my understanding that the compiler puts them in flash. On bootup, it then copies them into SRAM. Thus, TWO memories are occupied by the same material. General bummer, but thats the way it is.

But you can store them in flash only using the stuff in <avr/pgmspace.h> in the libc documentation:  http://www.nongnu.org/avr-libc/u...  if you need to save on data memory.  PSTR creates a static pointer to a string in program space, and the string doesnt seem to be automatically copied to RAM on startup.  I copy the strings with a strcpy_P to a buffer in data space, and then send it out UART.  That way I only need one buffer in RAM to handle the communication and only one copy of the string.  Somewhere along the line I convinced myself I needed to send stuff out UART from data memory.  Not sure how I arrived at that conclusion, or if it is even true, but it is how I have been doing it.