avoid copying an array of const data to the RAM

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

Hello,

The ATmega328 has 32 KBytes of Flash memory, and 2 KBytes of RAM (and 1 KByte of EEPROM).
I have a program with contains 8000 bytes of const data.

I have the data defined as follows:
const unsigned char data[8000] = {0x1, 0x2, 0x3, 0x4, 0x5...};

The problem is that the C compiler tries to copy this data at RAM,
and there is not enough RAM for these 8000 bytes.

However, I don't really need to copy the data at RAM,
because I don't need to modify this data, just to read it.

How can I prevent the compiler to copy the data to RAM?
Or how can I read 8000 bytes from the Flash?
(I shouldn't be using the RAM nor the EEPROM)

Regards,
David

void initSerial() {
  Serial.begin(9600);  // debug to the PC.

  // waits until the PC is ready to get data.
  while (Serial.available() <= 0) {
    Serial.println("press a key...\n");   // send an initial string
    delay(300);
  }
}

//I only write until 5 examples bytes, but here there would be the 10 or 8000 bytes.
const unsigned char data[10] = {0x1, 0x2, 0x3, 0x4, 0x5};   // this works.

//const unsigned char data[8000] = {0x1, 0x2, 0x3, 0x4, 0x5};  // this does not work., because there is not enough RAM to fit all this, and then the program does just strange things


void setup() {
  initSerial();

  Serial.print("START.\n");

  for (int i=0; i < 5; i++) {
    Serial.print("test >>"); Serial.print(data[i], DEC); Serial.print("<<\n");
  }

  Serial.print("END.\n");  
}

void loop() {
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You might have said which C compiler. But that fact that it looks like C++ rather than C suggests it's got to be either IAR or GCC. If it happens to be GCC then the "magic" you are looking for is "PROGMEM" - start with the article in the Tutorial Forum. In IAR I think they have a "__flash" keyword or something similar?

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

Hello Clawson,

Thanks, this tutorial you said solved my question:
https://www.avrfreaks.net/index.p...

In case anyone is interested, here it is the corrected code:
(it is written using the Arduino prototyping board/programming language)

#include 

void initSerial() { 
  Serial.begin(9600);  // debug to the PC. 

  // waits until the PC is ready to get data. 
  while (Serial.available() <= 0) { 
    Serial.println("press a key...\n");   // send an initial string 
    delay(300); 
  } 
} 

//I only write until 5 examples bytes, but here there would be the 8000 bytes. 
const unsigned char data[8000] PROGMEM = {0x1, 0x2, 0x3, 0x4, 0x5};


void setup() { 
  initSerial(); 

  Serial.print("START.\n"); 

  for (int i=0; i < 5; i++) { 
    Serial.print("test >>"); Serial.print(pgm_read_byte(&data[i]), DEC); Serial.print("<<\n"); 
  } 

  Serial.print("END.\n");  
} 

void loop() { 
} 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I must be blind. I missed the setup() and loop() completely - so this is actually an Arduino "sketch" then? In that case I should have known it was avr-gcc

At some point you may want to explore:

\arduino-nnnn\hardware\cores\arduino\

and look at the C/C++ files there. You may be interested to know that they are using PROGMEM themselves:

D:\arduino-0015\hardware\cores\arduino>grep PROGMEM *
pins_arduino.c:const uint16_t PROGMEM port_to_mode_PGM[] = {
pins_arduino.c:const uint16_t PROGMEM port_to_output_PGM[] = {
pins_arduino.c:const uint16_t PROGMEM port_to_input_PGM[] = {
pins_arduino.c:const uint8_t PROGMEM digital_pin_to_port_PGM[] = {
pins_arduino.c:const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = {
pins_arduino.c:const uint8_t PROGMEM digital_pin_to_timer_PGM[] = {
pins_arduino.c:const uint16_t PROGMEM port_to_mode_PGM[] = {
pins_arduino.c:const uint16_t PROGMEM port_to_output_PGM[] = {
pins_arduino.c:const uint16_t PROGMEM port_to_input_PGM[] = {
pins_arduino.c:const uint8_t PROGMEM digital_pin_to_port_PGM[] = {
pins_arduino.c:const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = {
pins_arduino.c:const uint8_t PROGMEM digital_pin_to_timer_PGM[] = {
pins_arduino.h:extern const uint16_t PROGMEM port_to_mode_PGM[];
pins_arduino.h:extern const uint16_t PROGMEM port_to_input_PGM[];
pins_arduino.h:extern const uint16_t PROGMEM port_to_output_PGM[];
pins_arduino.h:extern const uint8_t PROGMEM digital_pin_to_port_PGM[];
pins_arduino.h:// extern const uint8_t PROGMEM digital_pin_to_bit_PGM[];
pins_arduino.h:extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[];
pins_arduino.h:extern const uint8_t PROGMEM digital_pin_to_timer_PGM[];

these are the look up tables for digitalRead() and digitalWrite() that are kept in code flash.

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

Why write an array of constants with incrementing values when this can be created with a for loop in real time driving the print function? If the data was something like a stored image file It would make sense.

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

Quote:
Why write an array of constants with incrementing
Quote:
values//I only write until 5 examples bytes
Quote:
Serial.print("test >>");
I think that it is pretty obvious that this was just test data.

Regards,
Steve A.

The Board helps those that help themselves.