Skip to content

Commit

Permalink
add EEPROM support
Browse files Browse the repository at this point in the history
  • Loading branch information
Manawyrm committed Jun 9, 2019
1 parent 52fec52 commit 5468c4c
Show file tree
Hide file tree
Showing 23 changed files with 242 additions and 31 deletions.
Binary file added firmware/.vscode/ipch/28f76e90068b509/eeprom.ipch
Binary file not shown.
Binary file not shown.
Binary file added firmware/.vscode/ipch/28f7be90068bd88/eeprom.ipch
Binary file not shown.
Binary file not shown.
Binary file added firmware/.vscode/ipch/3c8c53219f92bcc9/main.ipch
Binary file not shown.
Binary file not shown.
Binary file added firmware/.vscode/ipch/5dc83a422fbb2a7f/crc.ipch
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified firmware/.vscode/ipch/9f1fad073dd28f88/main.ipch
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added firmware/eeprom.bin
Binary file not shown.
15 changes: 15 additions & 0 deletions firmware/src/crc.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#include "crc.h"

// Shamelessly stolen fron Stackoverflow (https://stackoverflow.com/questions/10564491/function-to-calculate-a-crc16-checksum)

uint16_t crc16_8(const unsigned char* data, uint8_t len) {
uint8_t x;
uint16_t crc = 0xFFFF;

while (len--) {
x = crc >> 8 ^ *data++;
x ^= x>>4;
crc = (crc << 8) ^ ((uint16_t)(x << 12)) ^ ((uint16_t)(x <<5)) ^ ((uint16_t)x);
}
return crc;
}
5 changes: 5 additions & 0 deletions firmware/src/crc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#pragma once

#include <stdint.h>

uint16_t crc16_8(const unsigned char* data, uint8_t len);
121 changes: 121 additions & 0 deletions firmware/src/eeprom.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#include "eeprom.h"
#include <avr/eeprom.h>
#include <avr/interrupt.h>
#include "crc.h"
#include "util.h"

static uint16_t next_log_entry;

static unsigned char* write_data;
uint8_t write_len;
uint16_t write_addr;

#define LOG_ENTRY_LEN (sizeof(struct eeprom_log_block))
#define LOG_DATA_LEN (sizeof(struct eeprom_log_data_priv))
#define DEV_DATA_LEN (sizeof(struct eeprom_device_block))

#define LOG_ENTRIES CLAMPH(((EEPROM_SIZE) / LOG_ENTRY_LEN), 255)

EEMEM struct eeprom_log_block logdata[LOG_ENTRIES];
struct eeprom_log_data log_data;
static struct eeprom_log_block log_block;

void eeprom_init() {
next_log_entry = 0;
}

static void inc_log() {
next_log_entry++;
if(next_log_entry >= ARRAY_LEN(logdata)) {
next_log_entry = 0;
}
log_block.data.serial++;
}

// For some bizarre reason eeprom_read_block reads data backwards...
static void eeprom_read_block_8(void* dst, void* src, uint8_t len) {
while(len--) {
*((unsigned char*)dst++) = eeprom_read_byte(src++);
}
}

static uint8_t eeprom_read_log_block(struct eeprom_log_block* log, uint8_t entry) {
eeprom_read_block_8(log, &logdata[entry], LOG_ENTRY_LEN);
return log->crc == crc16_8((unsigned char*)&log->data, LOG_DATA_LEN);
}

uint8_t eeprom_find_log_block() {
struct eeprom_log_block log;
struct eeprom_log_block last_log;
uint8_t entry = 0;
uint8_t found = 0;
if(eeprom_read_log_block(&last_log, ARRAY_LEN(logdata) - 1)) {
found = 1;
log_block = last_log;
log_data = log_block.data.data;
next_log_entry = entry;
inc_log();
}
while(entry < ARRAY_LEN(logdata)) {
if(eeprom_read_log_block(&log, entry)) {
if(found) {
uint8_t expected_serial = last_log.data.serial;
expected_serial++;
// Sequence break, last log entry is most recent one
if(log.data.serial != expected_serial) {
uint8_t prev_entry = entry;
prev_entry--;
log_block = last_log;
log_data = log_block.data.data;
next_log_entry = prev_entry;
inc_log();
break;
}
}
log_block = log;
log_data = log_block.data.data;
next_log_entry = entry;
inc_log();
found = 1;
last_log = log;
}
entry++;
}
return found;
}


uint8_t eeprom_busy() {
return write_len != 0;
}

void eeprom_write_next_byte() {
EEARL = write_addr & 0xFF;
EEARH = (write_addr >> 8);
EEDR = *write_data;
EECR |= BIT(EEMPE) | BIT(EERIE);
EECR |= BIT(EEPE);
}

void eeprom_write_log_block() {
log_block.data.data = log_data;
write_addr = (uint16_t)&logdata[next_log_entry];
write_len = LOG_ENTRY_LEN;
write_data = (unsigned char*)&log_block;
log_block.crc = crc16_8((unsigned char*)&log_block.data, LOG_DATA_LEN);
eeprom_write_next_byte();
}

ISR(EE_READY_vect) {
write_addr++;
write_data++;
write_len--;
if(write_len) {
// Enqueue next byte
eeprom_write_next_byte();
} else {
// Transfer finished, disable interrupts and increment serial
EECR &= ~BIT(EERIE);
inc_log();
}
}
36 changes: 36 additions & 0 deletions firmware/src/eeprom.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#pragma once

#include <stdint.h>
#include "main.h"

struct eeprom_log_data
{
uint16_t voltage;
uint16_t sleepInterval;
uint16_t undervoltageLockout;
uint16_t undervoltageHysteresis;
uint8_t disableTimeout;
uint16_t timeout;
};


struct eeprom_log_data_priv {
uint8_t serial;
struct eeprom_log_data data;
};

struct eeprom_log_block {
struct eeprom_log_data_priv data;
// Writing the data block can not be an atomic
// operation, crc ensures integrity
uint16_t crc;
};

#define EEPROM_SIZE 1024

void eeprom_init();
uint8_t eeprom_find_log_block();
uint8_t eeprom_busy();
void eeprom_write_log_block();

extern struct eeprom_log_data log_data;
64 changes: 33 additions & 31 deletions firmware/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,55 +7,63 @@
@par 2019-05-26 Tobias Mädel Initial version
*/
#include <Arduino.h>
#include "main.h"
#include "config.h"
#include <SoftWire.h>
#include <EEPROM.h>

#include "Wire/src/Wire.h"
#include "Adafruit_INA219.h"
#include "LowPower.h"

// todo: eeprom
// todo: timeout
volatile uint8_t state = STATE_ACTIVE;
uint16_t activeTime = 0;
uint16_t currentSleepTime = 0;

// INA220 Init
Adafruit_INA219 ina219;
void setINAState(bool state = LOW);
SoftWire inaWire(AVR_SDA, AVR_SCL);
uint8_t txBuf[20];
uint8_t rxBuf[20];

// RPi I2C Slave
volatile uint8_t i2cRegister;
volatile uint8_t i2cData;
void handleI2CReceive(volatile int numBytes);
void handleI2CRequest();
void sleep(uint16_t sleepTime);
void shutdownSignaled();

struct
{
uint16_t voltage;
uint16_t sleepInterval;
uint16_t undervoltageLockout;
uint16_t undervoltageHysteresis;
uint8_t disableTimeout;
uint16_t timeout;
} registers = {
/*registerDefinition registers = {
.voltage = 0,
.sleepInterval = 3,
.undervoltageLockout = 7000,
.undervoltageHysteresis = 7500,
.disableTimeout = 0,
.timeout = 60
};

};*/
#define registers log_data

void setup()
{
Serial.begin(9600);

eeprom_init();
if (!eeprom_find_log_block())
{
Serial.println("Initializing EEPROM");
log_data = {
.voltage = 0,
.sleepInterval = 3,
.undervoltageLockout = 7000,
.undervoltageHysteresis = 7500,
.disableTimeout = 0,
.timeout = 60
};
eeprom_write_log_block();
}
else
{
Serial.println("block found!");
}

Serial.print("Timeout: ");
Serial.println(registers.timeout);

//Serial.println("ohai");
pinMode(RPI_SHDN, INPUT_PULLUP);
pinMode(AVR_PWR_EN, OUTPUT);
Expand All @@ -75,15 +83,6 @@ void setup()
attachInterrupt(digitalPinToInterrupt(RPI_SHDN), shutdownSignaled, FALLING);
}

enum states {
STATE_ACTIVE,
STATE_SLEEP,
STATE_UNDERVOLTAGE
};
volatile uint8_t state = STATE_ACTIVE;

uint16_t activeTime = 0;

void loop()
{
registers.voltage = (ina219.getBusVoltage_V() * 1000.0f);
Expand All @@ -108,6 +107,9 @@ void loop()
case STATE_SLEEP:
registers.disableTimeout = 0;
activeTime = 0;

while (eeprom_busy());

sleep(registers.sleepInterval);
state = STATE_ACTIVE;
break;
Expand Down Expand Up @@ -157,6 +159,7 @@ void handleI2CReceive(volatile int numBytes)
if (sizeof(registers) > i2cRegister)
{
((uint8_t*)&registers)[i2cRegister] = i2cData;
eeprom_write_log_block();
}
}
while (Wire.available()>0){Serial.print(Wire.read(), HEX);}
Expand All @@ -170,7 +173,6 @@ void setINAState(bool state = LOW)
digitalWrite(INA_3V3, state);
}

uint16_t currentSleepTime = 0;
void sleep(uint16_t sleepTime)
{
setINAState(false);
Expand Down
17 changes: 17 additions & 0 deletions firmware/src/main.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once

#include <Arduino.h>
#include "eeprom.h"

void handleI2CReceive(volatile int numBytes);
void handleI2CRequest();
void sleep(uint16_t sleepTime);
void shutdownSignaled();
void setINAState(bool state);


enum states {
STATE_ACTIVE,
STATE_SLEEP,
STATE_UNDERVOLTAGE
};
15 changes: 15 additions & 0 deletions firmware/src/util.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once
#define BIT(x) (1<<(x))

#define ARRAY_LEN(arr) (sizeof(arr) / sizeof(*arr))

#define ATOMIC_BEGIN do { cli();
#define ATOMIC_END sei(); } while(0);

#ifndef NULL
#define NULL ((void*)0U)
#endif

#define CLAMPH(x, max) (((x) > (max) ? (max) : (x)))

#define ABS(x) ((x) < 0 ? -(x) : (x))

0 comments on commit 5468c4c

Please sign in to comment.