Could you try the next sketch. It is still quick and dirty, but it seems to work.
The sketch could be used with a small Pro Mini and a temperature sensor. It stores the temperature for a week when sampled every minute, without extra memory hardware.
The ATmega328P still getting such very useful feature is awesome.
// Test with Arduino Uno to test new optiboot feature to store data into flash.
// http://forum.arduino.cc/index.php?topic=332191.0
//
// An Arduino Pro Mini could be used to store the temperature for a week.
// The sketch requires manual start. An automatic start would be more useful.
#include "optiboot.h"
#include <avr/pgmspace.h>
// SPM_PAGESIZE for ATmega328P is 128
// Sampling every minute for a single channel with 160 pages is 10240 integer samples.
// That is one week storage.
// Now testing with 210 pages.
// Storage area in flash, only writable from the boot sector (using special optiboot bootloader).
// The compiler sets the whole contents default to zero.
const char flash_buffer[SPM_PAGESIZE * 210] __attribute__ (( aligned(SPM_PAGESIZE) )) PROGMEM = { 0,};
// Temporary storage in ram, to get a page of data.
uint8_t ram_buffer[SPM_PAGESIZE];
uint16_t *pSampleBuffer = (uint16_t *) ram_buffer; // create integer pointer to the ram buffer
boolean flagSampling = false;
int index; // sample index
unsigned long previousMillis;
// helper constants
const int MaxPageSamples = SPM_PAGESIZE / sizeof( uint16_t); // max integer samples in a single page.
const int MaxTotalSamples = sizeof( flash_buffer) / sizeof( uint16_t); // total max samples
const int Pages = sizeof(flash_buffer) / SPM_PAGESIZE; // number of storage pages.
const unsigned long interval = 60000UL; // 60000UL is one minute, try 200UL for testing
void setup() {
// Init serial
Serial.begin(9600); // increase to 115200 if dumping data takes very long.
Serial.println(F("\nSample analog A0 and store in flash"));
Serial.println(F("Storage:"));
Serial.print(F(" Samples to store : "));
Serial.println( MaxTotalSamples);
Serial.print(F(" Interval : "));
Serial.print( interval);
Serial.println(F(" ms"));
Serial.print(F(" Page size : "));
Serial.println(SPM_PAGESIZE);
Serial.print(F(" Available pages : "));
Serial.println( Pages);
Serial.println(F("Commands:"));
Serial.println(F(" s = start sampling"));
Serial.println(F(" c = clear storage area"));
Serial.println(F(" d = dump data"));
Serial.println(F(" q = stop sampling"));
}
void loop() {
int i;
if ( flagSampling) {
if ( millis() - previousMillis >= interval) { // software timer with millis()
previousMillis += interval;
// The 'index' counts the number of integer samples.
int data = analogRead( A0);
pSampleBuffer[index % MaxPageSamples] = data;
Serial.print(F("Sample "));
Serial.print(index);
Serial.print(F(" is "));
Serial.println( data);
if (((index + 1) % MaxPageSamples) == 0) { // was this the last sample for a page ?
Serial.print(F("Writing page "));
Serial.println( index / MaxPageSamples);
WriteRamToFlash( ram_buffer, index / MaxPageSamples);
}
index++;
if ( index >= MaxTotalSamples) {
// out of storage space
Serial.println(F("Storage space filled. Sampling stopped"));
flagSampling = false;
}
}
}
if ( Serial.available()) {
int inChar = Serial.read();
switch ( inChar) {
case 's':
Serial.println(F("Sampling started !"));
flagSampling = true;
index = 0;
previousMillis = millis(); // start software timer with millis with current millis()
break;
case 'c':
Serial.print(F("Clearing complete storage area... "));
memset( ram_buffer, '\0', sizeof(ram_buffer)); // fill ram buffer with zeros
for ( i = 0; i < Pages; i++)
WriteRamToFlash( ram_buffer, i);
Serial.println(F("Done"));
break;
case 'd':
// Print current flash buffer content
int n;
if ( index == 0) {
Serial.println(F("no new samples stored, dumping previous stored samples"));
n = MaxTotalSamples;
} else {
n = index;
}
for ( i = 0; i < n; i++) {
if ( i % 16 == 0)
Serial.println();
Serial.print( pgm_read_word( flash_buffer + (sizeof(int16_t) * i)));
Serial.print(F(", "));
}
Serial.println();
break;
case 'q':
Serial.println(F("Stopped sampling"));
flagSampling = false;
// Write current buffer, clear yet unwritten samples.
for( i=index % MaxPageSamples; i<MaxPageSamples; i++)
pSampleBuffer[i] = 0;
Serial.print(F("Writing page "));
Serial.println( index / MaxPageSamples);
WriteRamToFlash( ram_buffer, index / MaxPageSamples);
break;
}
}
}
// WriteRamToFlash
// This function writes a complete SPM_PAGESIZE buffer from ram to flash
// The page is the flash page (used as page offset to 'flash-buffer').
void WriteRamToFlash( uint8_t *buf, int page) {
optiboot_page_erase((uint16_t)(void*) &flash_buffer[page * SPM_PAGESIZE]);
for ( int i = 0; i < SPM_PAGESIZE; i += 2) { // 'i' is in bytes, write words
uint16_t w = word(buf[i+1], buf[i]); // word(high,low)
optiboot_page_fill((uint16_t)(void*) &flash_buffer[(page * SPM_PAGESIZE) + i], w);
}
optiboot_page_write((uint16_t)(void*) &flash_buffer[page * SPM_PAGESIZE]);
}