Hi everyone,
I have this very strange problem: If I use too much PROGMEM for my data (time series I want to output via a PWM pin), the PWM base frequency is set to a very slow value.
What I'm trying to do:
- Add data to my program by storing it in byte arrays stored in PROGMEM.
- Read out that data.
- Output the data on one of the PWM pins, with a high enough frequency.
Some relevant code:
#include <avr/pgmspace.h>
#include "data.h"
// analog output
unsigned int dataPin = 12;
float framerate = 100;
void setup()
{
Serial.begin(9600); // open the serial port at 9600 bps
init_data();
for (unsigned int ii = 0; ii < digits; ++ii) {
pinMode(bit8 - ii, INPUT);
}
pinMode(dataPin, OUTPUT);
// Set PWM timer for pins 11 and 12
// https://arduino-info.wikispaces.com/Arduino-PWM-Frequency
TCCR1B = TCCR1B & B11111000 | B00000010;
};
void init_data() {
data[0] = pgm_get_far_address(data0);
data[1] = pgm_get_far_address(data1);
data[2] = pgm_get_far_address(data2);
data[3] = pgm_get_far_address(data3);
data[4] = pgm_get_far_address(data4);
data[5] = pgm_get_far_address(data5);
data[6] = pgm_get_far_address(data6);
data[7] = pgm_get_far_address(data7);
data[8] = pgm_get_far_address(data8);
// data[9] = pgm_get_far_address(data9);
// data[10] = pgm_get_far_address(data10);
// data[11] = pgm_get_far_address(data11);
// data[12] = pgm_get_far_address(data12);
// data[13] = pgm_get_far_address(data13);
data[14] = pgm_get_far_address(data14);
data[15] = pgm_get_far_address(data15);
}
void loop()
{
unsigned char pos = position();
play_data(pos);
}
void play_data(unsigned char data_index){
float framerate = framerates[data_index];
unsigned int delay_t = round(1000.0/framerate);
uint32_t len = data_lengths[data_index];
uint32_t base_ii = data[data_index];
for (uint32_t ii = 0 ; ii < len; ++ii) {
uint32_t pgm_pos = base_ii + ii;
// sets the value (range from 0 to 255):
unsigned char value = pgm_read_byte_far(pgm_pos);
analogWrite(dataPin, value);
// Serial.println(value);
delay(delay_t);
}
}
And the data input:
#ifndef DATA_H
#define DATA_H
const float framerates[16] = {
1000, 1000, 1000, 1000, // 0..3
1000, 1000, 1000, 1000, // 4..7
1000, 1000, 1000, 1000, // 8..11
100, 10, 10, 10, // 12..15
};
// 256kB / 16 = 16kB
const unsigned char data0[] PROGMEM = {
#include "data/data1.h"
//3, 1, 4, 1, 5, 9, 2, 6, 5, 8, 9, 7, 9
};
const unsigned char data1[] PROGMEM = {
#include "data/data1.h"
};
const unsigned char data2[] PROGMEM = {
#include "data/data2.h"
};
const unsigned char data3[] PROGMEM = {
#include "data/data3.h"
};
const unsigned char data4[] PROGMEM = {
#include "data/data4.h"
};
const unsigned char data5[] PROGMEM = {
#include "data/data5.h"
};
const unsigned char data6[] PROGMEM = {
#include "data/data6.h"
};
const unsigned char data7[] PROGMEM = {
#include "data/data7.h"
};
const unsigned char data8[] PROGMEM = {
#include "data/data8.h"
};
const unsigned char data9[] PROGMEM = {
#include "data/data9.h"
};
const unsigned char data10[] PROGMEM = {
#include "data/data10.h"
};
const unsigned char data11[] PROGMEM = {
#include "data/data11.h"
};
const unsigned char data12[] PROGMEM = {
#include "data/data12.h"
};
const unsigned char data13[] PROGMEM = {
#include "data/data13.h"
};
const unsigned char data14[] PROGMEM = {
#include "data/data14.h"
};
const unsigned char data15[] PROGMEM = {
#include "data/data15.h"
};
// we need to use "pgm_get_far_address" to convert the numbers to
// addresses in the larger progmem address space.
uint32_t data[16];
const uint32_t data_lengths[16] = {
sizeof(data0), sizeof(data1), sizeof(data2), sizeof(data3),
sizeof(data4), sizeof(data5), sizeof(data6), sizeof(data7),
sizeof(data8), sizeof(data9), sizeof(data10), sizeof(data11),
sizeof(data12), sizeof(data13), sizeof(data14), sizeof(data15)
};
#endif //DATA_H
What works, what does not?
It all works fine so far, but I run into trouble if I add more data. I tested it on the Mega2560, with plenty of flash memory still free. If I add more data (by uncommenting more lines in init_data()
), the PWM frequency setting line (last line in setup()
) loses its effect and the PWM frequency is set to something very, very slow. The last "good" setting uses slightly below 70kB (but well over 64kB) of flash memory, the first "bad" setting more than 70kB. I used the PWM divider settings from https://arduino-info.wikispaces.com/Arduino-PWM-Frequency, changing the PWM frequency generally works for me on this chip.
Now, what did I do wrong here, if anything? I do not allocate any memory dynamically, so I do not think that this can be a problem with insufficient SRAM.