/*
datalog.cpp -- a simple program to read data using an Atmega328p and
write it to a windbond flash chip.
Copyright 2011, 2012, 2013, Peter J. Torelli
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see
*/
#include
// Chip Select (pin 10)
// MOSI: pin 11
// MISO: pin 12
// SCK: pin 13
#define ROTOR_INPUT_PIN 2
#define ROTOR_IRQ 0
#define STATUS_LED_PIN 0
#define MODE_JUMPER_PIN 7
#define CHIP_SELECT 10
unsigned int g_rotor_counter(0);
unsigned int seconds(0);
byte g_page_buffer[256];
unsigned int g_next_page(0);
#define ERROR_FLASH_FULL 0x10
void setup(void) {
delay(1000);
pinMode(ROTOR_INPUT_PIN, INPUT);
pinMode(STATUS_LED_PIN, OUTPUT);
digitalWrite(STATUS_LED_PIN, LOW);
pinMode(MODE_JUMPER_PIN, INPUT);
delay(100);
SPI.begin();
SPI.setDataMode(0);
SPI.setBitOrder(MSBFIRST);
pinMode(CHIP_SELECT, OUTPUT);
digitalWrite(CHIP_SELECT, HIGH);
// In debug mode, we never enter loop()
if (digitalRead(MODE_JUMPER_PIN) == LOW) {
attachInterrupt(ROTOR_IRQ, pulse_count_change_debug_flash, CHANGE);
while (1) {};
}
// Flash the status led if there's no more memory pages
g_next_page = find_free_page();
if (g_next_page >= 4096) {
error_loop(ERROR_FLASH_FULL);
}
attachInterrupt(ROTOR_IRQ, pulse_count_change, CHANGE);
}
void loop(void) {
static unsigned int bytes_buffered(0);
delay(1000);
// Detatch the interrupt so that we don't interrupt the page write
detachInterrupt(ROTOR_IRQ);
// 0xFFFF means the address is free, so 0xFFFE is the highest rotor count
// we can store.
if (g_rotor_counter > 0xFE) {
g_rotor_counter = 0xfe;
}
g_page_buffer[bytes_buffered] = g_rotor_counter & 0xFF;
++bytes_buffered;
g_rotor_counter = 0;
if (bytes_buffered == 256) {
page_write();
bytes_buffered = 0;
}
attachInterrupt(ROTOR_IRQ, pulse_count_change, CHANGE);
}
// This debuf mode interrupt just flashes the main LED
// with the detector status.
void pulse_count_change_debug_flash(void) {
digitalWrite(STATUS_LED_PIN, digitalRead(ROTOR_INPUT_PIN));
}
void pulse_count_change(void) {
cli();
++g_rotor_counter;
sei();
}
void not_busy(void) {
digitalWrite(10, LOW);
SPI.transfer(0x05);
while (SPI.transfer(0) & 1) {};
digitalWrite(10, HIGH);
}
void error_loop(unsigned int code) {
// I always wanted to write a POST code...
while (1) {
digitalWrite(STATUS_LED_PIN, HIGH);
delay(100);
digitalWrite(STATUS_LED_PIN, LOW);
delay(100);
digitalWrite(STATUS_LED_PIN, HIGH);
delay(100);
digitalWrite(STATUS_LED_PIN, LOW);
delay(100);
digitalWrite(STATUS_LED_PIN, HIGH);
delay(100);
digitalWrite(STATUS_LED_PIN, LOW);
delay(100);
digitalWrite(STATUS_LED_PIN, HIGH);
delay(1000);
digitalWrite(STATUS_LED_PIN, LOW);
delay(100);
}
}
void read_page(unsigned int page, byte *page_ptr) {
digitalWrite(10, LOW);
SPI.transfer(0x03);
SPI.transfer((page >> 8) & 0xFF);
SPI.transfer((page >> 0) & 0xFF);
SPI.transfer(0);
for (int i = 0; i < 256; ++i) {
page_ptr[i] = SPI.transfer(0);
}
digitalWrite(10, HIGH);
not_busy();
}
// Search for the first page that starts with 0xFFFF. This is
// "fresh flash" (as the rotor count range is 0..0xFFFe). This
// is where we start writing every time we boot.
unsigned int find_free_page(void) {
unsigned int page(0);
static byte page_ptr[256];
word value(0);
do {
read_page(page, page_ptr);
if (page_ptr[0] == 0xFF && page_ptr[1] == 0xFF) {
break;
}
++page;
} while (page < 4096);
return page;
}
void page_write(void) {
digitalWrite(CHIP_SELECT, LOW);
SPI.transfer(0x06);
digitalWrite(CHIP_SELECT, HIGH);
digitalWrite(CHIP_SELECT, LOW);
SPI.transfer(0x02);
SPI.transfer((g_next_page >> 8) & 0xFF);
SPI.transfer((g_next_page >> 0) & 0xFF);
SPI.transfer(0);
for (int i = 0; i < 256; ++i) {
SPI.transfer(g_page_buffer[i]);
}
digitalWrite(CHIP_SELECT, HIGH);
digitalWrite(CHIP_SELECT, LOW);
SPI.transfer(0x04);
digitalWrite(CHIP_SELECT, HIGH);
not_busy();
++g_next_page;
if (g_next_page >= 4096) {
error_loop(ERROR_FLASH_FULL);
}
}