Added a bunch of code for EEPROM, STC3100. Fixed some symbol printing

This commit is contained in:
nedko 2022-10-27 18:03:38 +03:00
parent 625c10081e
commit 8f2062db55

View File

@ -8,11 +8,34 @@
#include "i2c_master.h"
#define EEPROM_SIZE 512
#define EEPROM_SIZE 256
#define EEPROM_IDX_SIZE 4
#define BATTERY_REG_MODE 0x00
#define BATTERY_REG_CTRL 0x01
#define BATTERY_READ_ADDR 0x02
#define BATTERY_READ_ADDR_END 0x0B
#define BATTERY_BUFF_SIZE (BATTERY_READ_ADDR_END - BATTERY_READ_ADDR + 1)
#define BATTERY_CHARGE 0
#define BATTERY_VOLT 6
#define BATTERY_TEMP 8
#define BATTERY_MILLIOHM 30
#define BATTERY_CHARGE_MULT 67
#define BATTERY_CHARGE_DIV (10 * BATTERY_MILLIOHM)
#define BATTERY_VOLT_MULT 244
#define BATTERY_VOLT_DIV 100
#define BATTERY_TEMP_MULT 125
#define BATTERY_TEMP_DIV 1000
#define CHAR_SIZE 5
#define OLED_ADDRESS (0x3C << 1)
// #define OLED_ADDRESS (0x3D << 1)
#define EEPROM_ADDRESS (0x50 << 1)
#define BATTERY_ADDRESS (0x70 << 1)
#define OLED_X_SIZE 128
#define OLED_Y_SIZE 64
@ -29,11 +52,6 @@
#define ROT_WHEEL_RAD 13.875
//#define ROT_REVERSE
// Input masks
#define BUTTON_V 0x01
#define BUTTON_S 1
#define BUTTON_M (BUTTON_V << BUTTON_S)
// Event queue macros
#define MAX_EVENT_COUNT 64
#define PTR_INC(x) ((x) = events + ((((x) - events) + 1) % MAX_EVENT_COUNT))
@ -59,12 +77,6 @@ enum btn_state_e
BTN_DOWN14
};
enum state_e
{
STATE_COUNTING,
STATE_SETTING
};
// These are set on hardware init
uint8_t old_btn_pin_state;
uint8_t old_rot_pin_state;
@ -133,7 +145,8 @@ const uint8_t PROGMEM unfold_table[16] =
0xAA
};
const uint8_t PROGMEM symbols[80] =
// Bottom -> Top (In Byte); Left -> Right (In Row)
const uint8_t PROGMEM symbols[90] =
{
0x3E, 0x51, 0x49, 0x45, 0x3E, // 0
0x00, 0x42, 0x7F, 0x40, 0x00, // 1
@ -145,35 +158,80 @@ const uint8_t PROGMEM symbols[80] =
0x03, 0x71, 0x09, 0x05, 0x03, // 7
0x36, 0x49, 0x49, 0x49, 0x36, // 8
0x06, 0x49, 0x49, 0x29, 0x1E, // 9
// A
// B
0x7E, 0x11, 0x11, 0x11, 0x7E, // A
0x7F, 0x49, 0x49, 0x49, 0x36, // B
0x3E, 0x41, 0x41, 0x41, 0x22, // C
0x1F, 0x20, 0x40, 0x20, 0x1F, // V
// h
0x7F, 0x08, 0x04, 0x04, 0x78, // h
0x7C, 0x04, 0x78, 0x04, 0x78, // m
0x00, 0x60, 0x60, 0x00, 0x00, // .
// <
// >
0x41, 0x22, 0x14, 0x08, 0x00, // >
0x0E, 0x11, 0x11, 0x0E, 0x00 // deg
};
// Init direct hardware
void simple_init();
// OLED send cmd helper
void display_send_cmd(uint8_t cmd);
// OLED send data helper
void display_send_data(const uint8_t *data, uint16_t buflen);
// OLED init
void display_init();
// OLED On/Off
void display_enable(uint8_t en);
// Symbol printing helper
void get_symbol16(uint8_t index, uint8_t *out);
// Print symbol on screen
// Symbol idx in table,
// Start X pixel - 0 -- 117
// Y row - 0 -- 3
// Char size - 10x16
void print_symbol(uint8_t symbol_idx, uint8_t x, uint8_t y, uint8_t invert);
// Print the length left with mm and highlight the required digit
// 0 - no highlight, 0xFF - clears everything
void print_mm(uint32_t value, uint8_t highlight);
void print_direction(uint8_t is_up, uint8_t invert);
void print_voltage(uint16_t value);
uint16_t adc_measure();
uint16_t get_voltage();
uint16_t find_eeprom_idx();
void read_eeprom_val(uint16_t idx, uint32_t *value, uint8_t *dir);
void write_eeprom_val(uint16_t idx, uint32_t value, uint8_t dir);
// Print the direction of the filament
// 0xFF - clears everything
void print_direction(uint8_t is_A, uint8_t highlight);
// Find the current eeprom data idx of the attached spool
int16_t find_eeprom_idx();
// Read value and direction of current spool
int8_t read_eeprom_val(int8_t idx, uint32_t *value, uint8_t *direction);
// Write value and direction of current spool
int8_t write_eeprom_val(int8_t idx, uint32_t value, uint8_t direction);
// Reset battery counter stats
int8_t reset_battery();
// Read battery stats
// temp is in celsius
int8_t read_battery(int16_t *mAh, int16_t *mV, int16_t *temp);
// I2C write helper
int8_t i2c_write_buff(uint8_t i2c_addr, uint8_t data_addr, uint8_t *buf, uint8_t len);
// I2C read helper
int8_t i2c_read_buff(uint8_t i2c_addr, uint8_t data_addr, uint8_t *buf, uint8_t len);
// Do the big sleep
void do_sleep();
void update_display(uint32_t value, uint32_t highlight, uint8_t dir, uint8_t dir_highlight);
// Extracts digit from value
// 1 - ones, 2 - tens, 3 - hundreds ...
uint8_t extract_digit(uint32_t value, uint8_t digit_num);
// Updates the ms counter
ISR(TIMER1_OVF_vect)
{
cli();
@ -796,8 +854,8 @@ void print_symbol(uint8_t symbol_idx, uint8_t x, uint8_t y, uint8_t invert)
void print_mm(uint32_t value, uint8_t highlight)
{
static uint32_t old_value = 0;
static uint8_t old_highlight = 0;
static_uint8_t old_symbols[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
static uint8_t old_highlight = 0xFF;
uint8_t x;
uint8_t y;
uint8_t symbol;
@ -822,7 +880,12 @@ void print_mm(uint32_t value, uint8_t highlight)
invert = 0;
}
if (is_first && (0 == highlight) && (0 == symbol) && (1 != i))
// Leading zero removal
// There's no highlight, this is the first digit to write, it's 0
// and it's not the last digit
// or everything is removed
if ((is_first && (0 == highlight) && (0 == symbol) && (1 != i)) ||
(0xFF == highlight))
{
symbol = 0xFF;
}
@ -831,216 +894,296 @@ void print_mm(uint32_t value, uint8_t highlight)
is_first = 0;
}
if ((0 == old_value) || (symbol != extract_digit(old_value, i)) || (old_highlight != highlight))
// Update only necessary digits
// On first run, on highlight change or on symbol change
if ((0xFF == old_highlight) || (old_highlight != highlight) ||
(symbol != old_symbols[6 - i]))
{
print_symbol(symbol, x, y, invert);
old_symbols[6 - i] = symbol;
}
x += (CHAR_SIZE + 1) * 2;
}
// Print 'mm'
if (0 == old_value)
// Print 'mm' (only on first run)
if (0xFF == old_highlight)
{
print_symbol(10, x, y, 0);
print_symbol(15, x, y, 0);
x += (CHAR_SIZE + 1) * 2;
print_symbol(10, x, y, 0);
print_symbol(15, x, y, 0);
}
if (0xFF == highlight)
{
print_symbol(0xFF, x, y, 0);
x += (CHAR_SIZE + 1) * 2;
print_symbol(0xFF, x, y, 0);
}
old_value = value;
old_highlight = highlight;
}
void print_direction(uint8_t is_up, uint8_t invert)
void print_direction(uint8_t is_A, uint8_t highlight)
{
uint8_t symbol_index[2];
static uint8_t old_is_up = 0;
static uint8_t old_invert = 1;
uint8_t symbol;
static uint8_t old_is_A = 0;
static uint8_t old_highlight = 0xFF;
if (is_up)
if (is_A)
{
symbol_index[0] = 14;
symbol_index[1] = 13;
symbol = 10;
}
else
{
symbol_index[0] = 13;
symbol_index[1] = 15;
symbol = 11;
}
if ((old_is_up != is_up) || (old_invert != invert))
// Clear it all
if ((0xFF == highlight) && (old_highlight != highlight))
{
print_symbol(symbol_index[0], OLED_X_SIZE - CHAR_SIZE * 2, 0, invert);
print_symbol(symbol_index[1], OLED_X_SIZE - CHAR_SIZE * 2, 1, invert);
print_symbol(0xFF, OLED_X_SIZE - (CHAR_SIZE + 1) * 2 * 2, 0, 0);
print_symbol(0xFF, OLED_X_SIZE - (CHAR_SIZE + 1) * 2, 0, 0);
}
old_is_up = is_up;
old_invert = invert;
else
{
// Print '>' only when display is comming from clear
if (0xFF == old_highlight)
{
print_symbol(symbol_index[0], OLED_X_SIZE - (CHAR_SIZE + 1) * 2 * 2, 0, 0);
}
// Print symbol on change or highlight change
if ((old_is_A != is_A) || (old_highlight != highlight))
{
print_symbol(symbol, OLED_X_SIZE - (CHAR_SIZE + 1) * 2, 0, highlight);
}
}
old_is_A = is_A;
old_highlight = highlight;
}
void print_voltage(uint16_t value)
int16_t find_eeprom_idx()
{
static uint16_t old_value = 0;
uint8_t x;
uint8_t y;
uint8_t symbol;
uint8_t i;
x = 0;
y = 1;
// Print 3 digits
for (i = 3; i > 0; --i)
{
symbol = extract_digit(value, i);
if ((0 == old_value) || (symbol != extract_digit(old_value, i)))
{
print_symbol(symbol, x, y, 0);
}
if (0 == x)
{
x += (CHAR_SIZE + 1) * 2;
}
x += (CHAR_SIZE + 1) * 2;
}
if (0 == old_value)
{
// Print 'V'
print_symbol(11, x, y, 0);
// Print '.'
x = (CHAR_SIZE + 1) * 2;
print_symbol(12, x, y, 0);
}
old_value = value;
}
uint16_t adc_measure()
{
uint16_t result;
// Enable and start ADC
ADCSRA |= (1 << ADEN) | (1 << ADSC);
// Wait for conversion
while (ADCSRA & (1 << ADSC));
// Read ADC value
result = ADC;
// Redo to get a better reading
ADCSRA |= (1 << ADSC);
while (ADCSRA & (1 << ADSC));
result = ADC;
// Disable ADC
ADCSRA &= ~(1 << ADEN);
return result;
}
uint16_t measure_voltage()
{
uint32_t val;
uint16_t result;
val = 110;
val *= 1023;
val /= adc_measure();
result = val;
return result;
}
uint16_t find_eeprom_idx()
{
uint16_t idx = 0;
uint8_t err;
int16_t idx = 0;
uint8_t found = 0;
uint32_t value = 0xFFFFFFFF;
// FF is the erased byte value and is used as prefix
for (idx = 0; idx < EEPROM_SIZE; ++idx)
// FF is the erased byte value
for (idx = 0; idx < EEPROM_SIZE / EEPROM_IDX_SIZE; ++idx)
{
if (0xFF != eeprom_read_byte((uint8_t *) idx))
err = read_eeprom_val(idx, &value);
if (0 != err)
{
return -1;
}
if (value != 0xFFFFFFFF)
{
found = 1;
break;
}
}
// Not found = new EEPROM
if (!found)
{
return EEPROM_SIZE;
return 0;
}
// FF XX ...
if (1 == idx)
{
// Check Last byte for value
// FF XX ... FF ??
if (0xFF != eeprom_read_byte((uint8_t *) (EEPROM_SIZE - 1)))
{
idx = EEPROM_SIZE - 1;
}
}
// XX ...
if (0 == idx)
{
// XX ... FF ?? ??
for (idx = EEPROM_SIZE - 2; idx < EEPROM_SIZE; ++idx)
{
if (0xFF != eeprom_read_byte((uint8_t *) idx))
{
break;
}
}
}
// idx here is the byte that's not the FF prefix so reverse it by 1
idx += EEPROM_SIZE;
--idx;
idx %= EEPROM_SIZE;
return idx;
}
void read_eeprom_val(uint16_t idx, uint32_t *value, uint8_t *dir)
int8_t read_eeprom_val(int8_t idx, uint32_t *value, uint8_t *direction)
{
uint8_t curr_byte;
uint8_t i;
int8_t err;
uint8_t buf[4];
(*value) = 0;
for (i = 0; i < 4; ++i)
if (idx < 0)
{
curr_byte = eeprom_read_byte((uint8_t *) idx);
(*value) <<= 8;
(*value) |= curr_byte;
++idx;
idx %= EEPROM_SIZE;
return -1;
}
idx %= (EEPROM_SIZE / EEPROM_IDX_SIZE);
err = i2c_read_buff(EEPROM_ADDRESS, idx * EEPROM_IDX_SIZE, buf, 4);
if (4 != err)
{
return -1;
}
*dir = ((*value) & 0x00800000) >> 23;
(*value) &= 0x007FFFFF;
(*direction) = buf[0];
buf[0] = 0;
(*value) = 0;
for (uint8_t i = 0; i < 4; ++i)
{
(*value) <<= 8;
(*value) |= buf[i];
}
return 0;
}
void write_eeprom_val(uint16_t idx, uint32_t value, uint8_t dir)
int8_t write_eeprom_val(int8_t idx, uint32_t value, uint8_t direction)
{
uint8_t curr_byte;
uint8_t i;
int8_t err;
uint8_t buf[4];
value |= 0xFF000000;
if (0 != dir)
if (idx < 0)
{
value |= 0x00800000;
return -1;
}
idx %= (EEPROM_SIZE / EEPROM_IDX_SIZE);
for (uint8_t i = 0; i < 4; ++i)
{
buf[i] = ((value >> ((3 - i) * 8)) & 0xFF);
}
for (i = 0; i < 4; ++i)
buf[0] = direction;
err = i2c_write_buff(EEPROM_ADDRESS, idx * EEPROM_IDX_SIZE, buf, 4)
if (4 != err)
{
curr_byte = (value >> (24 - 8 * i)) & 0xFF;
eeprom_update_byte((uint8_t *) idx, curr_byte);
++idx;
idx %= EEPROM_SIZE;
return -1;
}
return 0;
}
int8_t reset_battery()
{
int8_t err;
uint8_t val;
// Reset All Battery Counters
val = 0x02;
err = i2c_write_buff(BATTERY_ADDRESS, BATTERY_REG_CTRL, &val, 1);
if (1 != err)
{
return -1;
}
// Set Running Mode
val = 0x10;
err = i2c_write_buff(BATTERY_ADDRESS, BATTERY_REG_MODE, &val, 1);
if (1 != err)
{
return -1;
}
return 0;
}
int8_t read_battery(int16_t *mAh, int16_t *mV, int16_t *temp)
{
// Reading from 0x02 to 0x0B inclusive
uint8_t buf[BATTERY_BUFF_SIZE];
int8_t err;
int32_t val;
err = i2c_read_buff(BATTERY_ADDRESS, BATTERY_READ_ADDR, buf, BATTERY_BUFF_SIZE);
if (err != BATTERY_BUFF_SIZE)
{
return -1;
}
// Calc mAh
(*mAh) = buf[BATTERY_CHARGE + 1];
(*mAh) <<= 8;
(*mAh) |= buf[BATTERY_CHARGE];
val = (*mAh);
val *= BATTERY_CHARGE_MULT;
val /= BATTERY_CHARGE_DIV;
(*mAh) = val;
// Calc mV
(*mV) = buf[BATTERY_VOLT + 1];
(*mV) <<= 8;
(*mV) |= buf[BATTERY_VOLT];
val = (*mV);
val *= BATTERY_VOLT_MULT;
val /= BATTERY_VOLT_DIV;
(*mV) = val;
// Calc temp
(*temp) = buf[BATTERY_TEMP + 1];
(*temp) <<= 8;
(*temp) |= buf[BATTERY_TEMP];
val = (*temp);
val *= BATTERY_TEMP_MULT;
val /= BATTERY_TEMP_DIV;
(*temp) = val;
return 0;
}
int8_t i2c_write_buff(uint8_t i2c_addr, uint8_t data_addr, uint8_t *buf, uint8_t len)
{
uint8_t err;
err = i2c_start(i2c_addr | I2C_WRITE);
if (0 != err)
{
i2c_stop();
return -1;
}
err = i2c_write(data_addr);
if (0 != err)
{
i2c_stop();
return -1;
}
for (uint8_t i = 0; i < len; ++i)
{
err = i2c_write(buf[i]);
if (0 != err)
{
i2c_stop();
return i;
}
}
i2c_stop();
return i;
}
int8_t i2c_read_buff(uint8_t i2c_addr, uint8_t data_addr, uint8_t *buf, uint8_t len)
{
uint8_t err;
err = i2c_start(i2c_addr | I2C_WRITE);
if (0 != err)
{
i2c_stop();
return -1;
}
err = i2c_write(data_addr);
if (0 != err)
{
i2c_stop();
return -1;
}
err = i2c_start(i2c_addr | I2C_READ);
if (0 != err)
{
i2c_stop();
return -1;
}
for (uint8_t i = 0; i < len; ++i)
{
buf[i] = i2c_read(i == len - 1);
}
i2c_stop();
return i;
}
void do_sleep()
@ -1066,13 +1209,6 @@ void do_sleep()
PRR &= ~(1 << PRUSI);
}
void update_display(uint32_t value, uint32_t highlight, uint8_t dir, uint8_t dir_highlight)
{
print_mm(value, highlight);
print_direction(dir, dir_highlight);
print_voltage(measure_voltage());
}
uint8_t extract_digit(uint32_t value, uint8_t digit_num)
{
while (1 != digit_num)