Get Adobe Flash player
FacebookTwitterGoogle+
English Arabic French German Italian Portuguese Russian Spanish

Did you know?

Many idle electronics TVs, VCRs, DVD and CD players, cordless phones, microwaves use energy even when switched off to keep display clocks lit and memory chips and remote controls working. Nationally, these energy "vampires" use 5 percent of our domestic energy and cost consumers more than $3 billion annually
 

Help us stay online:

small donate

 

AVR Memory MapConstants definition for AVR in CODEVISION

 

When writing firmware for microcontroller often there is need to have constants or constant arrays. For example, to have fixed value to compare with measurement from ADC. If this value changes during program execution then it must be defined as variable and placed in RAM or EEPROM, but if it is fixed then it is better to place it in FLASH memory. Main reason why it is better to place it in FLASH is because it is biggest memory space in microcontroller and often we do not have enough RAM for project. Also, when writing predefined strings for sending to UART as messages for user, it is best to declare these strings as constants.

 

 

 

Here is explained how to do this and code example with complete project source code is provided for download.

Integer or long integer constants may be written in decimal form  (e.g. 1234), in binary form with 0b prefix (e.g. 0b101001), in hexadecimal form with 0x prefix  (e.g. 0xff) or in octal form with 0-prefix (e.g. 0777).
Unsigned integer constants may have the suffix U (e.g. 10000U).
Long integer constants may have the suffix L (e.g. 99L).
Unsigned long integer constants may have the suffix UL (e.g. 99UL).
Floating point constants may have the suffix F (e.g. 1.234F).
Character constants must be enclosed in single quotation marks.  E.g.  'a'.
Literal string constants must be enclosed in double quotation marks. E.g. "Hello world".

Constant expressions are automatically evaluated during compilation.

Program constants can be declared as global (accessible to all the functions in the program) or local (accessible only inside the function they are declared).
The constant declarations syntax is similar to that of variables, but preceded by the const keyword:

const <type definition> <identifier> = constant expression;

Example:

/* Global constants declaration */
const char char_constant='a';
const int b=1234+5;
const long long_int_constant1=99L;
const long long_int_constant2=0x10000000;
const float pi=3.14;
void main(void) {
/* Local constants declaration */ 
const long f=22222222;
const float x=1.5;
}

Constants can be grouped in arrays, which can have up to 64 dimensions.
The first element of an array has always the index 0.
Example:

const char string_constant2[]="This is a string constant";
const int abc[3]={1,2,3};
/* The first two elements will be 1 and 2,
   the rest will be 0 */
const int  integer_array2[10]={1,2};
/* multidimensional array */
const int  multidim_array[2][3]={{1,2,3},{4,5,6}};

If the Project|Configure|C Compiler|Code Generation|Store Global Constants in FLASH Memory option is enabled, global constants that were declared using the const keyword will be placed by the compiler in FLASH memory.
If the above option is not enabled, global constants declared using the const keyword will be located in RAM memory.
Local constants will be always placed in RAM memory.

The flash or __flash keywords can be used to specify that a constant must be placed in FLASH memory, no matter what is the state of the Store Global Constants in FLASH Memory option:

flash <type definition> <identifier> = constant expression;
__flash <type definition> <identifier> = constant expression;

Example:

flash int  integer_constant=1234+5;
flash char char_constant='a';
flash long long_int_constant1=99L;
flash long long_int_constant2=0x10000000;
flash int  integer_array1[]={1,2,3};
flash char string_constant1[]="This is a string constant located in FLASH";

Now we will use this in Codevision Project for ATmega8535.

In order to understand better importance of keeping constants in FLASH we will make one example:
Let’s say you have system that will respond to characters received on UART with predefined sentences.
For example, when received character is:
Received: 1
Sends back: I have received first command and will execute first task that is appropriate for this command
Received: 2
Sends back: I have received second command and will execute second task that is appropriate for this command
Received: 3
Sends back: I have received third command and will execute third task that is appropriate for this command

We will implement this program in two ways:
- Answers placed in RAM memory
- Answers placed in FLASH memory

From this we can see what will be results concerning optimization and memory space usage.

Here is the first case where we will store answers in RAM memory: 

Complete Codevision project for this example with source code can be downloaded from this link.

/*****************************************************
This program was produced by the
CodeWizardAVR V2.04.4a Advanced
Automatic Program Generator
© Copyright 1998-2009 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com
Project : 
Version : 
Date    : 12/8/2011
Author  : NeVaDa
Company : 
Comments:
Chip type               : ATmega8535
Program type            : Application
AVR Core Clock frequency: 8.000000 MHz
Memory model            : Small
External RAM size       : 0
Data Stack size         : 128
*****************************************************/
#include <mega8535.h>
#ifndef RXB8
#define RXB8 1
#endif
#ifndef TXB8
#define TXB8 0
#endif
#ifndef UPE
#define UPE 2
#endif
#ifndef DOR
#define DOR 3
#endif
#ifndef FE
#define FE 4
#endif
#ifndef UDRE
#define UDRE 5
#endif
#ifndef RXC
#define RXC 7
#endif
#define FRAMING_ERROR (1<<FE)
#define PARITY_ERROR (1<<UPE)
#define DATA_OVERRUN (1<<DOR)
#define DATA_REGISTER_EMPTY (1<<UDRE)
#define RX_COMPLETE (1<<RXC)
// USART Receiver buffer
#define RX_BUFFER_SIZE 8
char rx_buffer[RX_BUFFER_SIZE];
#if RX_BUFFER_SIZE<256
unsigned char rx_wr_index,rx_rd_index,rx_counter;
#else
unsigned int rx_wr_index,rx_rd_index,rx_counter;
#endif
// This flag is set on USART Receiver buffer overflow
bit rx_buffer_overflow;
// USART Receiver interrupt service routine
interrupt [USART_RXC] void usart_rx_isr(void)
{
char status,data;
status=UCSRA;
data=UDR;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
   {
   rx_buffer[rx_wr_index]=data;
   if (++rx_wr_index == RX_BUFFER_SIZE) rx_wr_index=0;
   if (++rx_counter == RX_BUFFER_SIZE)
      {
      rx_counter=0;
      rx_buffer_overflow=1;
      };
   };
}
#ifndef _DEBUG_TERMINAL_IO_
// Get a character from the USART Receiver buffer
#define _ALTERNATE_GETCHAR_
#pragma used+
char getchar(void)
{
char data;
while (rx_counter==0);
data=rx_buffer[rx_rd_index];
if (++rx_rd_index == RX_BUFFER_SIZE) rx_rd_index=0;
#asm("cli")
--rx_counter;
#asm("sei")
return data;
}
#pragma used-
#endif
// Standard Input/Output functions
#include <stdio.h>
// Declare your global variables here
unsigned char my_variable; //variable used for receiving data from UART
void main(void)
{
// Declare your local variables here
// Input/Output Ports initialization
// Port A initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTA=0x00;
DDRA=0x00;
// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTB=0x00;
DDRB=0x00;
// Port C initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTC=0x00;
DDRC=0x00;
// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTD=0x00;
DDRD=0x00;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0 output: Disconnected
TCCR0=0x00;
TCNT0=0x00;
OCR0=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer2 Stopped
// Mode: Normal top=FFh
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;
// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// INT2: Off
MCUCR=0x00;
MCUCSR=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x00;
// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: On
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud Rate: 9600
UCSRA=0x00;
UCSRB=0x98;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x33;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;
// Global enable interrupts
#asm("sei")
while (1)
      {
      // Place your code here
      my_variable=getchar();
//get one character from circular input bufer handled by interrupt
               
      switch (my_variable) 
        {
        case '1':
        puts("I have received first command and will execute first task that is appropriate for this command\n\r");
//outputs, using putchar, string that you write between quotes, located in RAM, 
        break;
        case '2':
        puts("I have received second command and will execute second task that is appropriate for this command\n\r");
//outputs, using putchar, string that you write between quotes, located in RAM,
        break;
        case '3':
        puts("I have received third command and will execute third task that is appropriate for this command\n\r");
//outputs, using putchar, string that you write between quotes, located in RAM,
        break;
        default:
        };
      };
} 

And here is a snapshot of Terminal development tool to see how program works 

Terminal strings in RAM example

Now we will make program with same functionality but with using FLASH memory for storing answers :

Complete Codevision project for this example with source code can be downloaded from this link.

/*****************************************************
This program was produced by the
CodeWizardAVR V2.04.4a Advanced
Automatic Program Generator
© Copyright 1998-2009 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com
Project : 
Version : 
Date    : 12/8/2011
Author  : NeVaDa
Company : 
Comments:
Chip type               : ATmega8535
Program type            : Application
AVR Core Clock frequency: 8.000000 MHz
Memory model            : Small
External RAM size       : 0
Data Stack size         : 128
*****************************************************/
#include <mega8535.h>
#ifndef RXB8
#define RXB8 1
#endif
#ifndef TXB8
#define TXB8 0
#endif
#ifndef UPE
#define UPE 2
#endif
#ifndef DOR
#define DOR 3
#endif
#ifndef FE
#define FE 4
#endif
#ifndef UDRE
#define UDRE 5
#endif
#ifndef RXC
#define RXC 7
#endif
#define FRAMING_ERROR (1<<FE)
#define PARITY_ERROR (1<<UPE)
#define DATA_OVERRUN (1<<DOR)
#define DATA_REGISTER_EMPTY (1<<UDRE)
#define RX_COMPLETE (1<<RXC)
// USART Receiver buffer
#define RX_BUFFER_SIZE 8
char rx_buffer[RX_BUFFER_SIZE];
#if RX_BUFFER_SIZE<256
unsigned char rx_wr_index,rx_rd_index,rx_counter;
#else
unsigned int rx_wr_index,rx_rd_index,rx_counter;
#endif
// This flag is set on USART Receiver buffer overflow
bit rx_buffer_overflow;
// USART Receiver interrupt service routine
interrupt [USART_RXC] void usart_rx_isr(void)
{
char status,data;
status=UCSRA;
data=UDR;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
   {
   rx_buffer[rx_wr_index]=data;
   if (++rx_wr_index == RX_BUFFER_SIZE) rx_wr_index=0;
   if (++rx_counter == RX_BUFFER_SIZE)
      {
      rx_counter=0;
      rx_buffer_overflow=1;
      };
   };
}
#ifndef _DEBUG_TERMINAL_IO_
// Get a character from the USART Receiver buffer
#define _ALTERNATE_GETCHAR_
#pragma used+
char getchar(void)
{
char data;
while (rx_counter==0);
data=rx_buffer[rx_rd_index];
if (++rx_rd_index == RX_BUFFER_SIZE) rx_rd_index=0;
#asm("cli")
--rx_counter;
#asm("sei")
return data;
}
#pragma used-
#endif
// Standard Input/Output functions
#include <stdio.h>
// Declare your global variables here
unsigned char my_variable; //variable used for receiving data from UART
const char answer1[] ="I have received first command and will execute first task that is appropriate for this command\n\r";
//answer located in FLASH memory.
const char answer2[] ="I have received second command and will execute second task that is appropriate for this command\n\r";
//answer located in FLASH memory.
const char answer3[] ="I have received third command and will execute third task that is appropriate for this command\n\r";
//answer located in FLASH memory.
void main(void)
{
// Declare your local variables here
// Input/Output Ports initialization
// Port A initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTA=0x00;
DDRA=0x00;
// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTB=0x00;
DDRB=0x00;
// Port C initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTC=0x00;
DDRC=0x00;
// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTD=0x00;
DDRD=0x00;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0 output: Disconnected
TCCR0=0x00;
TCNT0=0x00;
OCR0=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer2 Stopped
// Mode: Normal top=FFh
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;
// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// INT2: Off
MCUCR=0x00;
MCUCSR=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x00;
// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: On
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud Rate: 9600
UCSRA=0x00;
UCSRB=0x98;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x33;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;
// Global enable interrupts
#asm("sei")
while (1)
      {
      // Place your code here
      my_variable=getchar();//get one character from circular input buffer handled by interrupt
               
      switch (my_variable) 
        {
        case '1':
        putsf(answer1);//outputs, using putchar, string that you write between quotes, located in RAM, 
        break;
        case '2':
        putsf(answer2);//outputs, using putchar, string that you write between quotes, located in RAM,
        break;
        case '3':
        putsf(answer3);//outputs, using putchar, string that you write between quotes, located in RAM,
        break;
        default:
        };
      };
}

And here is a snapshot of Terminal development tool to see that program has same functionality as previous example.

Terminal strings in RAM example

So now you wonder what is the difference and why this is important. Well, it happens very often that you need to memorise strings as in previous examples and thing is that FLASH memory is much bigger than RAM.
In next pictures you can see memory usage for previous examples. 

Memory usage of compiled program in case when answers are stored in RAM: 

strings in RAM example 

Memory usage of compiled program in case when answers are stored in FLASH:

strings in FLASH example

As you can see, in first case about 57% of RAM is used while in second case only 0.1% of FLASH memory is filled with answers.

This example showed advantages of using FLASH memory for constants storing and usage of functions for writing strings on UART.

Few more tips when declaring your own functions that work with data in different memory types are provided below.

The constant literal char strings, enclosed in double quotation marks, that are passed as function arguments, are stored in the memory type pointed by the pointer used as function parameter.
Example:

/* This function displays a string located in RAM. */
void display_ram(char *s) {
/* .......  */
}
/* This function displays a string located in FLASH. */
void display_flash(flash char *s) {
/* .......  */
}
/* This function displays a string located in EEPROM. */
void display_eeprom(eeprom char *s) {
/* .......  */
}
//names of the functions are taken random and are here only for example purpose
void main(void) {
/* The literal string "Hello world" will be placed
   by the compiler in FLASH memory and copied at program
   startup to RAM, so it can be accessed by the pointer
   to RAM used as function parameter.
   The code efficiency is low, because both FLASH and
   RAM memories are used for the string storage. */
display_ram("Hello world"); 
/* The literal string "Hello world" will be placed
   by the compiler in FLASH memory only, good code
   efficiency beeing achieved. */
display_flash("Hello world");
/* The literal string "Hello world" will be placed
   by the compiler in EEPROM memory only.
   The code efficiency is very good because no
   FLASH memory will be allocated for the string. */
display_eeprom("Hello world");
while (1);
}