added bufferless i2c implementation

This commit is contained in:
Jay Robson 2024-08-31 01:53:25 +10:00
parent 89aaa0c91a
commit ab6bb7d14b
9 changed files with 264 additions and 68 deletions

View File

@ -13,36 +13,19 @@ using namespace data;
static Mode mode = Mode::none;
static void flash_data() {
char buff[128];
unsigned count;
unsigned at = 0;
unsigned max_len = eeprom::length();
uint32_t at = 0;
uint16_t count;
char buffer[eeprom::PAGE_SIZE];
for(;;) {
unsigned count = sizeof(buff);
unsigned end = at + count;
do {
count = serial::read(buffer, eeprom::PAGE_SIZE);
eeprom::page_write(at, buffer);
at += eeprom::PAGE_SIZE;
delay(10);
} while(count == eeprom::PAGE_SIZE);
if(end <= at) {
break;
}
if(end >= max_len) {
unsigned l = end - max_len;
if(count < l) {
break;
}
count -= l;
}
count = serial::read(buff, count);
eeprom::write(at, buff, count);
at += count;
if(count != sizeof(buff)) {
break;
}
}
while(serial::read(buff, sizeof(buff) == sizeof(buff))) {
while(serial::is_connected()) {
serial::get();
}
}

View File

@ -1,41 +1,87 @@
#include <Wire.h>
#include <Arduino.h>
#include <SparkFun_External_EEPROM.h>
#include "eeprom.hpp"
#include "util.hpp"
using namespace eeprom;
constexpr uint8_t WRITE_MS = 3;
constexpr uint8_t ADDR = 0x50;
constexpr unsigned DELAY = 100;
static ExternalEEPROM mem;
uint32_t at = 0;
static unsigned at = 0;
static bool is_responsive(uint8_t i2c_addr) {
bool s = mem.start_write(i2c_addr);
return s;
}
static void wait_for_responsive(uint8_t i2c_addr) {
while(!is_responsive(i2c_addr)) {
delay(1);
}
}
static uint8_t get_i2c_addr(uint32_t at) {
uint8_t i2c_addr = ADDR;
if(at > 0xffff) {
i2c_addr |= 0b100;
}
return i2c_addr;
}
static void set_address(uint8_t i2c_addr, uint16_t at) {
char addr_bytes[2] = {at >> 8, at};
mem.start_write(i2c_addr);
mem.write(at >> 8);
mem.write(at);
}
void eeprom::init() {
Wire.setClock(400000);
Wire.begin();
mem.setMemoryType(1025);
mem.begin();
// Wire.setClock(400000);
// Wire.begin();
// mem.setMemorySizeBytes(eeprom::MAX_LENGTH);
// mem.setAddressBytes(2);
// mem.setPageSizeBytes(128);
// mem.setWriteTimeMs(3);
// mem.begin();
}
unsigned eeprom::length() {
return mem.length();
void eeprom::jump(uint32_t p_at) {
p_at = at;
}
void eeprom::jump(unsigned loc) {
at = loc;
void eeprom::read(char* data, uint16_t data_size) {
uint16_t recorded = 0;
while(recorded < data_size && at < LENGTH) {
uint32_t block_end = at / BLOCK_SIZE * BLOCK_SIZE + BLOCK_SIZE;
uint8_t read_len = min(min(block_end - at, data_size - recorded), 255);
uint8_t i2c_addr = get_i2c_addr(at);
set_address(i2c_addr, at);
mem.start_read(i2c_addr);
mem.read(data + recorded, read_len, true);
recorded += read_len;
at += read_len;
}
mem.end();
for(uint16_t i = recorded; i < data_size; i++) {
data[i] = 0;
}
}
void eeprom::read(char* data, unsigned len) {
mem.read(at, data, len);
at += len;
}
void eeprom::read(unsigned loc, char* data, unsigned len) {
mem.read(loc, data, len);
}
void eeprom::write(unsigned loc, const char* data, unsigned len) {
mem.write(loc, data, len);
void eeprom::page_write(uint32_t at, const char* data) {
uint8_t i2c_addr = get_i2c_addr(at);
wait_for_responsive(i2c_addr);
mem.start_write(i2c_addr);
mem.write(at >> 8);
mem.write(at);
mem.write(data, PAGE_SIZE - (at % PAGE_SIZE));
mem.end();
delay(WRITE_MS);
}

View File

@ -1,15 +1,20 @@
#pragma once
#include <inttypes.h>
#include "soft_twi.hpp"
namespace eeprom {
constexpr unsigned char PAGE_SIZE = 128;
constexpr uint8_t PAGE_SIZE = 128;
constexpr uint32_t BLOCK_SIZE = 0x10000;
constexpr uint32_t LENGTH = 0x20000;
inline SoftTWI mem(A4, A5);//A4, A5);
void init();
void jump(unsigned addr);
void read(char* data, unsigned len);
void read(unsigned addr, char* data, unsigned len);
void write(unsigned addr, const char* data, unsigned len);
unsigned length();
void jump(uint32_t addr);
void read(char* data, uint16_t len);
void page_write(uint32_t at, const char* data);
};

View File

@ -3,21 +3,24 @@
#include "indicator.hpp"
#include "tones.hpp"
constexpr int PIN = 10;
constexpr int PIN = 9;
void indicator::init() {
pinMode(PIN, OUTPUT);
pinMode(PIN+0, OUTPUT);
pinMode(PIN+1, OUTPUT);
}
void indicator::reset() {
analogWrite(PIN, 0);
analogWrite(PIN+0, 0);
analogWrite(PIN+1, 0);
}
void indicator::update() {
unsigned v = 0;
unsigned v[2] = {2};
for(int i = 0; i < tones::active; i++) {
v += tones::all[i].amplitude;
v[i % 2] += tones::all[i].amplitude;
}
analogWrite(PIN, min(v, 255));
analogWrite(PIN+0, min(v[0], 255));
analogWrite(PIN+1, min(v[1], 255));
}

View File

@ -22,10 +22,6 @@ struct {
bool active = false;
} next;
constexpr uint64_t bm(int n) {
return ((uint64_t)1 << n) - 1;
}
void scheduler::reset() {
tones::clear_all();
ts_init = micros();

View File

@ -2,7 +2,6 @@
#pragma once
#include <SoftwareSerial.h>
#include <avr/pgmspace.h>
namespace serial {

126
soft_twi.cpp Normal file
View File

@ -0,0 +1,126 @@
#include "soft_twi.hpp"
#include <Arduino.h>
SoftTWI::SoftTWI(unsigned pin_sda, unsigned pin_scl, unsigned delay) {
_pin_scl = pin_scl;
_pin_sda = pin_sda;
_delay = delay;
}
void SoftTWI::begin() {
digitalWrite(_pin_sda, 0);
digitalWrite(_pin_scl, 0);
}
void SoftTWI::sleep(unsigned t) {
if(_delay) {
delayMicroseconds(_delay * t);
}
}
void SoftTWI::set_sda(bool s) {
pinMode(_pin_sda, s ? INPUT : OUTPUT);
}
void SoftTWI::set_scl(bool s) {
pinMode(_pin_scl, s ? INPUT : OUTPUT);
}
bool SoftTWI::read_sda() {
return digitalRead(_pin_sda);
}
bool SoftTWI::read_scl() {
return digitalRead(_pin_scl);
}
void SoftTWI::wait_scl() {
while(!read_scl()) {}
}
bool SoftTWI::read_bit() {
set_sda(1);
sleep();
set_scl(1);
sleep(2);
wait_scl();
bool s = read_sda();
set_scl(0);
sleep();
return s;
}
void SoftTWI::write_bit(bool s) {
set_sda(s);
sleep();
set_scl(1);
sleep(2);
wait_scl();
set_scl(0);
sleep();
}
void SoftTWI::start() {
set_sda(1);
sleep();
set_scl(1);
sleep();
set_sda(0);
sleep();
set_scl(0);
sleep();
}
void SoftTWI::end() {
set_sda(0);
sleep();
set_scl(1);
sleep();
set_sda(1);
sleep(2);
}
bool SoftTWI::start_read(uint8_t addr) {
start();
return write((addr << 1) | 1);
}
bool SoftTWI::start_write(uint8_t addr) {
start();
return write(addr << 1);
}
uint8_t SoftTWI::read(bool ack) {
uint8_t v = 0;
for(unsigned m = 0x80; m; m >>= 1) {
if(read_bit()) {
v |= m;
}
}
write_bit(!ack); // send ACK
return v;
}
bool SoftTWI::write(uint8_t v) {
for(unsigned m = 0x80; m; m >>= 1) {
write_bit(v & m);
}
return !read_bit(); // get ACK
}
unsigned SoftTWI::write(const uint8_t* data, unsigned data_len) {
for(unsigned i = 0; i < data_len; i++) {
if(!write(data[i])) {
return i;
}
}
return data_len;
}
void SoftTWI::read(uint8_t* data, unsigned data_len, bool nack_at_end) {
for(unsigned i = 0; i < data_len; i++) {
data[i] = read(nack_at_end ? (i < data_len - 1) : true);
}
}

37
soft_twi.hpp Normal file
View File

@ -0,0 +1,37 @@
#pragma once
#include <inttypes.h>
struct SoftTWI {
SoftTWI(unsigned pin_sda, unsigned pin_scl, unsigned delay = 0);
void begin();
void sleep(unsigned=1);
void set_sda(bool);
void set_scl(bool);
bool read_sda();
bool read_scl();
void wait_scl();
void write_bit(bool);
bool write(uint8_t);
unsigned write(const uint8_t*, unsigned);
bool read_bit();
uint8_t read(bool=true);
void read(uint8_t*, unsigned, bool=false);
bool start_read(uint8_t);
bool start_write(uint8_t);
void start();
void end();
private:
unsigned _pin_scl;
unsigned _pin_sda;
unsigned _delay;
};

View File

@ -13,5 +13,6 @@ inline void swap(T& a, T& b) {
a = t;
}
#define bm(V) (((uint64_t)1 << V) - 1);
#define size(V) (sizeof(V) / sizeof(V[0]))