Problem using PROGMEM

Hi all,

I seem to have issues using the PROGMEM declaration for a 2D array. My project has to do with intelligent lighting so in my code, I have a function called void calcRefLight() which calculates the reference light source for a given CCT(Correlated Color Temperature) of a test light source based on the equations within the function.

The input to void calcRefLight() is CCT and the final result is stored in the variable refLight[]. I have another function getMaxValue() which simply finds the maximum value of an array and returns it. This maximum value will be used to normalize the final refLight[] output.

I run the following code and get the corresponding output. Note that I have not declared D_vector[][] under PROGMEM.

#include <avr/pgmspace.h>

#define RES 81

//Daylight vector for calculating CIE Standard D Illuminant
double D_vector[][4] = {{380, 63.4, 38.5, 3},
  {385, 64.6, 36.75, 2.1},
  {390, 65.8, 35, 1.2},
  {395, 80.3, 39.2, 0.05},
  {400, 94.8, 43.4, -1.1},
  {405, 99.8, 44.85, -0.8},
  {410, 104.8, 46.3, -0.5},
  {415, 105.35, 45.1, -0.6},
  {420, 105.9, 43.9, -0.7},
  {425, 101.35, 40.5, -0.95},
  {430, 96.8, 37.1, -1.2},
  {435, 105.35, 36.9, -1.9},
  {440, 113.9 , 36.7, -2.6},
  {445, 119.75, 36.3, -2.75},
  {450, 125.6, 35.9, -2.9},
  {455, 125.55, 34.25, -2.85},
  {460, 125.5, 32.6, -2.8},
  {465, 123.4, 30.25, -2.7},
  {470, 121.3, 27.9, -2.6},
  {475, 121.3, 26.1, -2.6},
  {480, 121.3, 24.3, -2.6},
  {485, 117.4, 22.2, -2.2},
  {490, 113.5, 20.1, -1.8},
  {495, 113.3, 18.15, -1.65},
  {500, 113.1, 16.2, -1.5},
  {505, 111.95, 14.7, -1.4},
  {510, 110.8, 13.2, -1.3},
  {515, 108.65, 10.9, -1.25},
  {520, 106.5, 8.6, -1.2},
  {525, 107.65, 7.35, -1.1},
  {530, 108.8, 6.1, -1},
  {535, 107.05, 5.15, -0.75},
  {540, 105.3, 4.2, -0.5},
  {545, 104.85, 3.05, -0.4},
  {550, 104.4, 1.9, -0.3},
  {555, 102.2, 0.95, -0.15},
  {560, 100, 0, 0},
  {565, 98, -0.8, 0.1},
  {570, 96, -1.6, 0.2},
  {575, 95.55, -2.55, 0.35},
  {580, 95.1, -3.5, 0.5},
  {585, 92.1, -3.5, 1.3},
  {590, 89.1, -3.5, 2.1},
  {595, 89.8, -4.65, 2.65},
  {600, 90.5, -5.8, 3.2},
  {605, 90.4, -6.5, 3.65},
  {610, 90.3, -7.2, 4.1},
  {615, 89.35, -7.9, 4.4},
  {620, 88.4, -8.6, 4.7},
  {625, 86.2, -9.05, 4.9},
  {630, 84, -9.5, 5.1},
  {635, 84.55, -10.2, 5.9},
  {640, 85.1, -10.9, 6.7},
  {645, 83.5, -10.8, 7},
  {650, 81.9, -10.7, 7.3},
  {655, 82.25, -11.35, 7.95},
  {660, 82.6, -12, 8.6},
  {665, 83.75, -13, 9.2},
  {670, 84.9, -14, 9.8},
  {675, 83.1, -13.8, 10},
  {680, 81.3, -13.6, 10.2},
  {685, 76.6, -12.8, 9.25},
  {690, 71.9, -12, 8.3},
  {695, 73.1, -12.65, 8.95},
  {700, 74.3, -13.3, 9.6},
  {705, 75.35, -13.1, 9.05},
  {710, 76.4, -12.9, 8.5},
  {715, 69.85, -11.75, 7.75},
  {720, 63.3, -10.6, 7},
  {725, 67.5, -11.1, 7.3},
  {730, 71.7, -11.6, 7.6},
  {735, 74.35, -11.9, 7.8},
  {740, 77, -12.2, 8},
  {745, 71.1, -11.2, 7.35},
  {750, 65.2, -10.2, 6.7},
  {755, 56.45, -9, 5.95},
  {760, 47.7, -7.8, 5.2},
  {765, 58.15, -9.5, 6.3},
  {770, 68.6, -11.2, 7.4},
  {775, 66.8, -10.8, 7.1},
  {780, 65, -10.4, 6.8}
};

//Global variables
double refLight[RES];
double CCT;
int i;

void setup()
{
  Serial.begin(9600);
  Serial.println("Initializing...");
  CCT = 3500;
  calcRefLight(CCT, refLight);
}

void loop()
{

}

//This function calculates the reference source light based on the CCT of the test source
void calcRefLight(double CCT, double refLight[])
{
  double xD, yD;
  double M1, M2;
  double tempMax;

  //if CCT < 5000 --> Planckian radiator used as reference source
  //if 5000>CCT<7000 --> Daylight used as reference source

  if (CCT < 5000)
  {
    Serial.println("Planckian radiator used as reference source");
    for (i = 0; i < RES; i++)
    {
      refLight[i] = (pow((D_vector[i][0] * 1e-9), -5)) / exp((0.014388 / ((D_vector[i][0] * 1e-9) * CCT)) - 1);
      //Serial.print(PlanckLaw[i]);
    }
    tempMax = getMaxValue(refLight, RES);
    Serial.println("Normalized Reference source");
    for (i = 0; i < RES; i++)
    {
      refLight[i] = refLight[i] / tempMax;  //normalized reference light
      Serial.println(refLight[i]);
    }
  }
  else if (CCT <= 7000)
  {
    Serial.println("Daylight used as reference");

    xD = (-4.6070e9 / (pow(CCT, 3))) + (2.9678e6 / (pow(CCT, 2))) + (0.9911e3 / CCT) + 0.244063;
    yD = (-3.000 * (pow(xD, 2))) + (2.870 * xD) - 0.275;

    M1 = (-1.3515 - 1.7703 * xD + 5.9114 * yD) / (0.0241 + 0.2562 * xD - 0.7341 * yD);
    M2 = (0.03 - 31.4424 * xD + 30.0717 * yD) / (0.0241 + 0.2562 * xD - 0.7341 * yD);

    for (i = 0; i < RES; i++)
    {
      refLight[i] = D_vector[i][1] + (M1 * D_vector[i][2]) + (M2 * D_vector[i][3]);
      //Serial.println(dayLight[i]);
    }
    
    tempMax = getMaxValue(refLight, RES);
    Serial.println("Normalized Reference source");
    for (i = 0; i < RES; i++)
    {
      refLight[i] = refLight[i] / tempMax;
      Serial.println(refLight[i]);
    }
  }
  else  //7000<CCT<25000
  {
    xD = (-2.0064e9 / (pow(CCT, 3))) + (1.9018e6 / (pow(CCT, 2))) + (0.24748e3 / CCT) + 0.237040;
    yD = (-3.000 * (pow(xD, 2))) + (2.870 * xD) - 0.275;

    M1 = (-1.3515 - 1.7703 * xD + 5.9114 * yD) / (0.0241 + 0.2562 * xD - 0.7341 * yD);
    M2 = (0.03 - 31.4424 * xD + 30.0717 * yD) / (0.0241 + 0.2562 * xD - 0.7341 * yD);

    Serial.println("Daylight used as reference");
    for (i = 0; i < RES; i++)
    {
      refLight[i] = D_vector[i][1] + (M1 * D_vector[i][2]) + (M2 * D_vector[i][3]);
      //Serial.println(dayLight[i]);
    }
    tempMax = getMaxValue(refLight, RES);
    Serial.println("Normalized Reference source");
    for (i = 0; i < RES; i++)
    {
      refLight[i] = refLight[i] / tempMax;
      Serial.println(refLight[i]);
    }
  }
}


//find max value and its index of an array
double getMaxValue(double array[], int n)
{
  int maxIndex = 0;
  double maxValue = array[maxIndex];
  for (int i = 0; i < n; i++)
  {
    if (maxValue < array[i])
    {
      maxValue = array[i];
      maxIndex = i;
    }
  }
  return maxValue;
}

OUTPUT:Initializing...
Planckian radiator used as reference source
Normalized Reference source
0.14
0.15
0.16
0.18
0.19
0.20
0.21
0.23
0.24
0.26
0.27
0.28
0.30
0.31
0.33
0.34
0.36
0.37
0.39
0.40
0.42
0.44
0.45
0.47
0.48
0.50
0.51
0.53
0.54
0.56
0.57
0.59
0.60
0.62
0.63
0.65
0.66
0.67
0.69
0.70
0.71
0.73
0.74
0.75
0.76
0.78
0.79
0.80
0.81
0.82
0.83
0.84
0.85
0.86
0.87
0.88
0.88
0.89
0.90
0.91
0.91
0.92
0.93
0.93
0.94
0.95
0.95
0.96
0.96
0.97
0.97
0.97
0.98
0.98
0.99
0.99
0.99
0.99
1.00
1.00
1.00

Result of output is as expected. Now, the only change I have made is the declaration of D_vector[][] under PROGMEM and get the following output.

const double D_vector[][4] PROGMEM ={};

OUTPUT:
Initializing...
Planckian radiator used as reference source
Normalized Reference source
inf
inf
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan
inf
inf
nan
nan
inf
inf
inf
nan
nan
nan
inf
nan
inf
nan
nan
nan
inf
inf
inf
nan
nan
inf
inf
nan
nan
inf
inf
inf

Can anyone explain this behavior when using PROGMEM? I need to use PROGMEM due to memory issues. Am I going wrong somewhere?

I'm using Arduino IDE 1.6.5 with Arduino MEGA 2560. Any help is much appreciated.

Cheers

You need to use a different method of accessing variables stored in flash program memory.
This might help you get started:-

const byte numArrays = 3;
const byte numElements = 4;
const float valTable[numArrays][numElements] PROGMEM =
{
    {12.1, 13.2, 14.0, 15.4},
    {16.3, 17.8, 18.92, 19.1},
    {20.0, 21.65, 22.4, 23.9}
};

void setup()
{
    Serial.begin(115200);
    for (byte bArray = 0; bArray < numArrays; bArray++)
    {
        for (byte bElement = 0; bElement < numElements; bElement++)
        {
            float fVal = pgm_read_float_near(valTable[bArray] + bElement);
            Serial.println(fVal);
        }
    }
}

void loop() {}

Thank you for your quick reply OldSteve, I read the documentation for avr/pgmspace.h library and the addressing of the pgm space is in bytes. Now I'm able to access the variables stored on flash memory properly.

Cheers

sraj50:
Thank you for your quick reply OldSteve, I read the documentation for avr/pgmspace.h library and the addressing of the pgm space is in bytes. Now I'm able to access the variables stored on flash memory properly.

Cheers

You're not directly 'byte addressing' when using the macros provided in "pgmspace.h". For instance, in the following, when adding 'bElement', the address steps forward by the size of a 'float', not by a 'byte'. :-

float fVal = pgm_read_float_near(valTable[bArray] + bElement);

I see but now I have another problem, I run the sketch below and I get the following error message.

#include <avr/pgmspace.h>

#define RES 81

const byte row = 81;
const byte col = 4;

//Daylight vector for calculating CIE Standard D Illuminant
const PROGMEM double D_vector[row][col] = {{380, 63.4, 38.5, 3},
  {385, 64.6, 36.75, 2.1},
  {390, 65.8, 35, 1.2},
  {395, 80.3, 39.2, 0.05},
  {400, 94.8, 43.4, -1.1},
  {405, 99.8, 44.85, -0.8},
  {410, 104.8, 46.3, -0.5},
  {415, 105.35, 45.1, -0.6},
  {420, 105.9, 43.9, -0.7},
  {425, 101.35, 40.5, -0.95},
  {430, 96.8, 37.1, -1.2},
  {435, 105.35, 36.9, -1.9},
  {440, 113.9 , 36.7, -2.6},
  {445, 119.75, 36.3, -2.75},
  {450, 125.6, 35.9, -2.9},
  {455, 125.55, 34.25, -2.85},
  {460, 125.5, 32.6, -2.8},
  {465, 123.4, 30.25, -2.7},
  {470, 121.3, 27.9, -2.6},
  {475, 121.3, 26.1, -2.6},
  {480, 121.3, 24.3, -2.6},
  {485, 117.4, 22.2, -2.2},
  {490, 113.5, 20.1, -1.8},
  {495, 113.3, 18.15, -1.65},
  {500, 113.1, 16.2, -1.5},
  {505, 111.95, 14.7, -1.4},
  {510, 110.8, 13.2, -1.3},
  {515, 108.65, 10.9, -1.25},
  {520, 106.5, 8.6, -1.2},
  {525, 107.65, 7.35, -1.1},
  {530, 108.8, 6.1, -1},
  {535, 107.05, 5.15, -0.75},
  {540, 105.3, 4.2, -0.5},
  {545, 104.85, 3.05, -0.4},
  {550, 104.4, 1.9, -0.3},
  {555, 102.2, 0.95, -0.15},
  {560, 100, 0, 0},
  {565, 98, -0.8, 0.1},
  {570, 96, -1.6, 0.2},
  {575, 95.55, -2.55, 0.35},
  {580, 95.1, -3.5, 0.5},
  {585, 92.1, -3.5, 1.3},
  {590, 89.1, -3.5, 2.1},
  {595, 89.8, -4.65, 2.65},
  {600, 90.5, -5.8, 3.2},
  {605, 90.4, -6.5, 3.65},
  {610, 90.3, -7.2, 4.1},
  {615, 89.35, -7.9, 4.4},
  {620, 88.4, -8.6, 4.7},
  {625, 86.2, -9.05, 4.9},
  {630, 84, -9.5, 5.1},
  {635, 84.55, -10.2, 5.9},
  {640, 85.1, -10.9, 6.7},
  {645, 83.5, -10.8, 7},
  {650, 81.9, -10.7, 7.3},
  {655, 82.25, -11.35, 7.95},
  {660, 82.6, -12, 8.6},
  {665, 83.75, -13, 9.2},
  {670, 84.9, -14, 9.8},
  {675, 83.1, -13.8, 10},
  {680, 81.3, -13.6, 10.2},
  {685, 76.6, -12.8, 9.25},
  {690, 71.9, -12, 8.3},
  {695, 73.1, -12.65, 8.95},
  {700, 74.3, -13.3, 9.6},
  {705, 75.35, -13.1, 9.05},
  {710, 76.4, -12.9, 8.5},
  {715, 69.85, -11.75, 7.75},
  {720, 63.3, -10.6, 7},
  {725, 67.5, -11.1, 7.3},
  {730, 71.7, -11.6, 7.6},
  {735, 74.35, -11.9, 7.8},
  {740, 77, -12.2, 8},
  {745, 71.1, -11.2, 7.35},
  {750, 65.2, -10.2, 6.7},
  {755, 56.45, -9, 5.95},
  {760, 47.7, -7.8, 5.2},
  {765, 58.15, -9.5, 6.3},
  {770, 68.6, -11.2, 7.4},
  {775, 66.8, -10.8, 7.1},
  {780, 65, -10.4, 6.8}
};




void setup()
{
  Serial.begin(115200);
  Serial.println("Initializing...");

  byte colElement = 0;
  double S0[row], S1[row], S2[row], lambda[row];
  for (byte bArray = 0; bArray < row; bArray++)
  {
    lambda[bArray] = pgm_read_float_near(D_vector[bArray] + colElement);
    S0[bArray] = pgm_read_float_near(D_vector[bArray] + (colElement + 1));
    S1[bArray] = pgm_read_float_near(D_vector[bArray] + (colElement + 2));
    S2[bArray] = pgm_read_float_near(D_vector[bArray] + (colElement + 3);
    Serial.println(S0[bArray]);
  }

/*
  double fVal[row];
  byte bElement = 0;
  for (byte bArray = 0; bArray < row; bArray++)
  {
    fVal[bArray] = pgm_read_float_near(D_vector[bArray] + (bElement + 1));
    Serial.println(fVal[bArray]);
  }
*/
}

void loop()
{

}

ERROR MESSAGE:

Arduino: 1.6.5 (Windows 8.1), Board: "Arduino/Genuino Mega or Mega 2560, ATmega2560 (Mega 2560)"

C:\Program Files (x86)\Arduino\hardware\tools\avr/bin/avr-g++ -c -g -Os -Wall -Wextra -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD -mmcu=atmega2560 -DF_CPU=16000000L -DARDUINO=10605 -DARDUINO_AVR_MEGA2560 -DARDUINO_ARCH_AVR -IC:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino -IC:\Program Files (x86)\Arduino\hardware\arduino\avr\variants\mega C:\Users\SIDDHA~1\AppData\Local\Temp\build3197406458514010890.tmp\sketch_aug17a.cpp -o C:\Users\SIDDHA~1\AppData\Local\Temp\build3197406458514010890.tmp\sketch_aug17a.cpp.o

sketch_aug17a.ino:127:0: error: unterminated argument list invoking macro "pgm_read_float_near"
sketch_aug17a.ino: In function 'void setup()':
sketch_aug17a.ino:107:18: error: 'pgm_read_float_near' was not declared in this scope
sketch_aug17a.ino:107:18: error: expected ';' at end of input
sketch_aug17a.ino:107:18: error: expected '}' at end of input
sketch_aug17a.ino:107:18: error: expected '}' at end of input
unterminated argument list invoking macro "pgm_read_float_near"

I'm unable to compile the program at all.

Something is missing here (compare to the previous line):

   S2[bArray] = pgm_read_float_near(D_vector[bArray] + (colElement + 3);

If you had hit Ctrl-T or ">Tools >Auto format" in the IDE, the error would have immediately been apparent, because the 'Serial.print()' line would have been indented like this:-

S2[bArray] = pgm_read_float_near(D_vector[bArray] + (colElement + 3);
                                         Serial.println(S0[bArray]);

This:-S2[bArray] = pgm_read_float_near(D_vector[bArray] + (colElement + 3);should be this:-S2[bArray] = pgm_read_float_near(D_vector[bArray] + (colElement + 3));
(You left out a closing parenthesis.)
Compiles fine for me after fixing that. :slight_smile:

oqibidipo posted the same as I was typing, but now that I've done it.......

OMG, how did I not see that. Apologies for that, been neck deep in coding all day completely missed that.

Yes I did use auto format actually maybe that caused the problem. Anyways it compiles fine now thank you OldSteve and oqibidipo, your quick replies have helped me immensely.

Cheers

sraj50:
Yes I did use auto format actually maybe that caused the problem.

No, it couldn't possibly cause the problem. But surely it highlighted it for you, when the 'Serial.print()' was indented so far?
(Leaving out the parenthesis caused the problem. 'Auto format' won't remove one.)
ie You have to take the blame for that. :wink: