const arrays

Hello together,

I have a question about const arrays.

I used a lot of diferent compilers and the behaivior of the Arduino Compiler seems to be diferent:

Usually when I write:

const array_with_content = {0, 1, 2, 3, 4};

The Compiler writes it to the Flash only and does not load it to the RAM. In a Testproject it does.

Is this a issue due to the compiler? Or does it depent to the AVR architecture?
Or did I do a stupid mistake?

Here ist my Example Project: (Run on Arduino UNO)
It simply Puts a PWM Signal with 200Hz to the Output an the Arrays store Walue an length.
When I Compile it, Arduino says: “Wenig Speicher verfügbar, es können Stabilitätsprobleme auftreten.” which means: less RAM left, there may be lack of stability
HINT: The arrays had to be shortend due to the 9000 Characters of the forum. I attached the ino file.

#define sizeof_pwm_array 650
    void (*isrCallback)();
    
const uint16_t pwm_out_array[sizeof_pwm_array] { 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF5, 0xF6, 0xF7, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, ...};
const uint8_t pwm_out_rep[sizeof_pwm_array] { 0xB5, 0x14, 0x10, 0x06, 0x04, 0x06, 0x04, 0x06, 0x02, 0x02, 0x02, 0x02, 0x02, 0x06, 0x04, 0x06,...;}
 

void setup(){
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);

  
  TCCR1A = _BV(COM1A1) | _BV(COM1B1) ; // phase and frequency correct mode. NON-inverted mode
  //phase/frequency correct mode. SELECT THIS FOR INVERTED OUTPUTS.
  TCCR1B = _BV(WGM13) | _BV(CS11);
  // Select mode 8 and select divide by 8 on main clock.
  
  ICR1 = 5000;

}


void loop() {
    static uint8_t nr=0;

    delay(5); 
    change_pwm();
    
}


void change_pwm()
{
 
  static uint16_t pwm_value; // 0...5000
  static uint16_t index=0xFFF;
  static uint16_t sub_index;

  if(index >= sizeof_pwm_array)
  {
    index = 0;
    pwm_value = pwm_out_array[0] * 12,5;
    sub_index = pwm_out_rep[0];
  }

  sub_index--;
  
  OCR1B = pwm_value;
  OCR1A = pwm_value;

  if(sub_index == 0)
  {
    pwm_value = pwm_out_array[index] * 12,5;
    sub_index = pwm_out_rep[index];
    index++;
  }
  
}

PWM_Folge.ino (9.89 KB)

You need to use the PROGMEM keyword to tell it to put it into flash.

See Gammon Forum : Electronics : Microprocessors : Putting constant data into program memory (PROGMEM)

jr178: Is this a issue due to the compiler? Or does it depent to the AVR architecture?

It is a combination of the compiler and the AVR architecture, but mainly the AVR architecture. The C language only has the concept of a single address space. The AVR h/w uses multiple address spaces. Because of this you can't directly access flash through a memory pointer. To compensate for this, the compiler & linker puts the const data into the flash but then it also has startup code that copies it to RAM to ensure that there is direct access to the data using memory pointers.

The AVR proprietary PROGMEM stuff is a hack to tell the compiler not create this additional RAM space for the const data. This will keep the data only in flash and not duplicate it into RAM, but then you have no direct access to it either. You have to use access functions to get to the data since the data is stored in flash which is in execution address space which is not directly accessible.

While it is less complicated and results in fewer gates in silicon to implement it this way, IMO, this was a major oversight in the AVR architecture/design as it really wonks any C code that uses const data. It also means you can't directly use any existing C code that uses const data. To use const data you have to jump through hoops using the AVR proprietary progmem declarations and often create indirect mapping tables. IMO, it really sucks. It isn't the way C code is supposed to work.

This and the bit set/bit clear instructions vs having bit set/bit clear registers are two of the things that I really don't like about the AVR parts.

--- bill

It isn't the way C code is supposed to work.

But it is the way microcontrollers are supposed to work.

AWOL: But it is the way microcontrollers are supposed to work.

Not really. It is a design choice. It only applies to those chips that have chosen to use/keep a pure harvard architecture. Not all choose to do this, for example ARM, and PIC32/MIPs based microcontrollers. It is a design choice based on real-world tradeoffs. Harvard is simpler to design, uses fewer gates and in some cases can offer slightly higher performance. This can offer quicker time to market for a new design and potentially a lower production cost. However, at the end of the day, s/w must run on it and multiple address spaces tends to make that s/w more complex for certain applications as well as making using certain tools like C more difficult to use.

So while harvard is a win from a h/w perspective, it can be a loss on the s/w side, particularly when dealing with const type data using a language like C.

Even if using assembler, having to use access routines or even inline instructions to access data in flash there is a penalty of cycles and/or code space over what could have been done in h/w. i.e. extra h/w that either makes the address space look flat by syncing the data transfers across the multiple busses or through pipelining techniques, will always be faster than having to deal with it in s/w.

One positive benefit to the chip manufacture is that it can create lock in since the s/w to deal with const data in flash is typically proprietary. It can end up warping the application code to contain and depend on proprietary extensions. As such, even though the code may be using a portable language such as C, the code is no longer portable and becomes difficult to move to alternate chip.

--- bill