1

2.2 THE BASICS OF C PROGRAMMING LANGUAGE book is has like this,

CONSTANTS

A constant is a number or a character having fixed value that cannot be changed during program execution. Unlike variables, constants are stored in the flash program memory of the microcontroller for the purpose of saving valuable space of RAM. The compiler recognizes them by their name and prefix const.

And Arduino references has not said where is constant variables are stored either program memory or RAM.

My questions are, where is the saving location of Arduino constant variables? Is it same to Microchip PIC? Those two compilers are same or not in this case?

3
  • Welcome to Arduino SE. Be sure to take the tur at arduino.stackexchange.com/Tour
    – SDsolar
    Apr 17, 2017 at 4:42
  • I believe when you #DEFINE a constant in the Arduino IDE it is used only in the compiler and not stored in RAM - the defined value is directly inserted into the compiled code.
    – SDsolar
    Apr 17, 2017 at 4:43
  • @SDsolar Thank you about your information about this site. I am always trying to do my best. Yes...#define is the preprocessor directive.It tells compilers to replaceing while compiling. So,, it it using Program memory instead of RAM.
    – user119o
    Apr 17, 2017 at 10:44

3 Answers 3

6

const means different things in different contexts as far as storage goes.

For a simple numeric value the compiler will generally replace the constant with the literal value. Any mathematics using purely constants or literals will be replaced at compile time with the result.

For instance, the code:

const int a = 3;
const int b = 4;

void setup() {
    int c = a + b;
    Serial.println(c);
}

void loop() {

}

results in the AVR assembly:

be: 4a e0           ldi r20, 0x0A   ; 10
c0: 50 e0           ldi r21, 0x00   ; 0

c2: 67 e0           ldi r22, 0x07   ; 7
c4: 70 e0           ldi r23, 0x00   ; 0

c6: 80 e2           ldi r24, 0x20   ; 32
c8: 91 e0           ldi r25, 0x01   ; 1
ca: 0c 94 4a 01     jmp 0x294   ; 0x294 <_ZN5Print7printlnEii>

Registers r22 and r23 store the second integer parameter to the Serial.println() - the actual function call generated is _ZN5Print7printlnEii(&Serial, 7, 10).

So you see that the literal value 7 has replaced both the sum of the constants and the variable it is placed in.

However it is very different when more complex values are called for - such as arrays (either numeric or character arrays, AKA "C Strings"). In this case yes the values are stored in Flash, however the startup code crt0.o copies that data into SRAM so that the software can access it easily.

Generally flash is hard for software to read from. In some architectures it requires special instructions to be executed. In others it requires setting values in SFRs (Special Function Registers) and reading from other SFRs to get the data. In other words it's far harder than just reading from a memory location (a limitation of Harvard Architecture). So it's copied at boot time into SRAM so that it then becomes easy to access, as it's just now accessing a memory location.

However that then defeats one of the objectives of using a constant value - reduction of SRAM usage by placing the data in Flash. So the Arduino has a specific macro PROGRMEM, which sets attributes on the variable to say "Never copy this data to SRAM".

More specifically it's actually provided by the file avr/pgmspace.h in the avr-gcc compiler:

#define __ATTR_PROGMEM__ __attribute__((__progmem__))
#define PROGMEM __ATTR_PROGMEM__

But now of course you can't access the data using simple memory accesses, so there are special functions to allow it to be done. Some are alternate versions of standard C library routines, for instance strcmp_P() shadows strcmp() with the second parameter being a PROGMEM variable. Others are special functions for reading bytes or words from locations in flash, such as pgm_read_byte_near().

The Arduino API also provides an extra little trick, called the __FlashStringHelper which is an empty class used to identify strings held in flash for the purpose of function overloading so that the F() macro can be used to call the right variant of a function to use the flash reading functions instead of assuming the string is in SRAM.

So as you can see it's not as straight forward as "consts are in Flash, non-consts are in RAM".


Highlighting the differences between how the AVR accesses Flash and how the various PIC sub-families access Flash:

  • The AVR has one single instruction that can read Flash - LPM:

There is only one instruction for the read access to the program storage space. It is defined for the pointer pair Z and it is named LPM (Load from Program Memory). The instruction copies the byte at program flash address Z to the register R0. As the program memory is organized word-wise (one instruction on one address consists of 16 bits or two bytes or one word) the least significant bit selects the lower or upper byte (0=lower byte, 1= upper byte). Because of this the original address must be multiplied by 2 and access is limited to 15-bit or 32 kB program memory. Like this:

LDI ZH,HIGH(2*address)
LDI ZL,LOW(2*address)
LPM
  • PIC10, PIC12 and PIC16 chips have no way of reading the flash.

Instead a "lookup table" of "RETLW" calls is used. For instance the string "Hello" would be stored in flash as:

RETLW 72    ; H
RETLW 101   ; e
RETLW 108   ; l
RETLW 108   ; l
RETLW 111   ; o
RETLW 0     ; NULL

RETLW returns from a CALL with the W register set to the literal value in the instruction. The entire command, that is both the RETLW and the 8 bit literal value, fits into a single 14-bit opcode.

  • PIC18 uses SFRs to access the Flash memory. Set the three registers TBLPTRU, TBLPTRH and TBLPTRL to the three bytes of the address in flash you want to read, a TBLRD instruction is issued through the EECON1 register, then you can read the byte from TABLAT.

  • PIC24 / dsPIC33 uses PSV - Program Space Visibility. This gives you the ability to map a 32kB chunk of the flash memory into the upper 32kB portion of the data space. This allows direct reading of data from within that 32kB chunk as if it were in RAM.

  • PIC32 uses a Von Neumann architecture which means that Flash and SRAM both share the same 32-bit address space. There is no difference reading from Flash or SRAM, so no special instructions are needed.

The only chip from those above where const really means const is the PIC32 where there is no need to copy from Flash to SRAM during startup since all the Flash memory can be directly accessed with normal MIPS LW and LB etc instructions.

4
  • Is reading flash slower (electrically and/or programmatically)? Also I think if you set size optimization, the compiler is more likely to put a const in programmemory?
    – Paul
    Apr 17, 2017 at 8:51
  • @Paul On architectures without direct access in the memory map to the flash access is generally programmatically slower. The PIC18 is the slowest, but the others aren't great. Clever, but not great. With memory mapped access (PIC24/PIC32) the speed of the flash becomes more critical. Traditionally flash has been slower to read from than SRAM, however that is not so much the case now. Faster architectures (80MHz PIC32 for instance) insert wait states while reading from flash to allow the flash memory to do what it needs to. However newer architectures feature zero wait state flash.
    – Majenko
    Apr 17, 2017 at 9:00
  • @Paul this may go some way to explaining wait states: electronics.stackexchange.com/q/27241/4245
    – Majenko
    Apr 17, 2017 at 9:03
  • @Paul The compiler can't really make the choice of whether or not to copy data to SRAM. That is the job of the startup code. If the compiler made the choice it wouldn't be able to select the right library function to use, the _P or non _P version, since the compiler has little or no concept about that kind of thing. The PROGMEM attribute tells the compiler how to store the data so it is both separate from the data to copy into SRAM and stored in such a way that it is easy to access (in the lower 32kB of Flash, etc). If optimization changed the behaviour then many things would suddenly break.
    – Majenko
    Apr 17, 2017 at 9:11
1

Constants can still use RAM. The decision whether to store it or not in RAM is up to the compiler. It may, for example, put the constant into RAM and then reference that constant throughout the code. The main use of constants is to act as a remainder that you cannot change that value. My personal experience tells me that const occupy the same RAM that int type does.

Using const does not prevent the values to be stored in RAM. If you want to prevent this behavior you should use PROGMEM

Store data in flash (program) memory instead of SRAM. There's a description of the various types of memory available on an Arduino board. The PROGMEM keyword is a variable modifier, it should be used only with the datatypes defined in pgmspace.h. It tells the compiler "put this information into flash memory", instead of into SRAM, where it would normally go.

This link may also be useful.

0

My questions are, where is the saving location of Arduino constant variables? Is it same to Microchip PIC? Those two compilers are same or not in this case?

how compilers handle "const" declarations varies greatly. "const" does nothing but telling that compiler that no modification to that variable is possible.

in the embedded world, that's typically done by putting that variable in flash / rom.

however, that treatment isn't universal. gcc-avr (my winavr from 2009) for example treats "const" just as any other ram types, putting it in either data section or bss section, depending on their initialization (or lack of).

PROGMEM attributes can forcefully change that, however.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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