optimise I2C

This commit is contained in:
Jay Robson 2024-10-01 16:19:43 +10:00
parent 1077930330
commit 78965abed2
6 changed files with 138 additions and 132 deletions

View File

@ -33,10 +33,6 @@ static void set_address(uint8_t i2c_addr, uint16_t at) {
mem.write(at); mem.write(at);
} }
void eeprom::init() {
mem.begin();
}
void eeprom::jump(uint32_t p_at) { void eeprom::jump(uint32_t p_at) {
last_block_end = 0; last_block_end = 0;
at = p_at; at = p_at;

View File

@ -12,7 +12,6 @@ namespace eeprom {
inline SoftTWI mem(A4, A5); inline SoftTWI mem(A4, A5);
void init();
void jump(uint32_t addr); void jump(uint32_t addr);
void read(char* data, uint16_t len); void read(char* data, uint16_t len);
void page_write(uint32_t at, const char* data); void page_write(uint32_t at, const char* data);

69
port.hpp Normal file
View File

@ -0,0 +1,69 @@
#pragma once
#include "util.hpp"
namespace port {
struct Drain {
uint8_t mask;
uint8_t imask;
volatile uint8_t* mode;
volatile uint8_t* in;
inline Drain(unsigned pin) AW_IN {
mask = digitalPinToBitMask(pin);
mode = portModeRegister(digitalPinToPort(pin));
in = portInputRegister(digitalPinToPort(pin));
imask = ~mask;
}
inline void set(uint8_t b) AW_IN {
if(b) {
*mode &= imask;
} else {
*mode |= mask;
}
}
inline uint8_t get() AW_IN {
return *in & mask;
}
};
struct Input {
uint8_t mask;
uint8_t imask;
volatile uint8_t* in;
inline Input(unsigned pin) AW_IN {
mask = digitalPinToBitMask(pin);
in = portInputRegister(digitalPinToPort(pin));
imask = ~mask;
}
inline uint8_t get() AW_IN {
return *in & mask;
}
};
struct Output {
uint8_t mask;
uint8_t imask;
volatile uint8_t* out;
inline Output(unsigned pin) AW_IN {
mask = digitalPinToBitMask(pin);
out = portOutputRegister(digitalPinToPort(pin));
imask = ~mask;
}
inline void set(uint8_t b) AW_IN {
if(b) {
*out |= mask;
} else {
*out &= imask;
}
}
};
};

View File

@ -1,42 +1,53 @@
#include "soft_twi.hpp"
#include <Arduino.h> #include <Arduino.h>
#include "soft_twi.hpp"
void SoftTWI::set_pin(uint8_t pin, bool state) { #include "port.hpp"
uint8_t bitmask = digitalPinToBitMask(pin);
volatile uint8_t* reg = portModeRegister(digitalPinToPort(pin));
if(state) {
*reg &= ~bitmask;
} else {
*reg |= bitmask;
}
}
void SoftTWI::begin() {
digitalWrite(_sda, 0);
digitalWrite(_scl, 0);
}
bool SoftTWI::read_pin(uint8_t pin) {
return digitalRead(pin);
}
uint8_t SoftTWI::read(bool ack) { uint8_t SoftTWI::read(bool ack) {
port::Drain sda(_sda);
port::Drain scl(_scl);
uint8_t v = 0; uint8_t v = 0;
for(unsigned m = 0x80; m; m >>= 1) { for(unsigned m = 0x80; m; m >>= 1) {
if(read_bit()) { sda.set(1);
scl.set(1);
while(!scl.get()) {}
if(sda.get()) {
v |= m; v |= m;
} }
scl.set(0);
} }
write_bit(!ack); // send ACK
// send ACK
if(ack) {
sda.set(!ack);
scl.set(1);
while(!scl.get()) {}
scl.set(0);
}
return v; return v;
} }
bool SoftTWI::write(uint8_t v) { bool SoftTWI::write(uint8_t v) {
port::Drain sda(_sda);
port::Drain scl(_scl);
for(unsigned m = 0x80; m; m >>= 1) { for(unsigned m = 0x80; m; m >>= 1) {
write_bit(v & m); sda.set(v & m);
scl.set(1);
while(!scl.get()) {}
scl.set(0);
} }
return !read_bit(); // get ACK
// get ACK
sda.set(1);
scl.set(1);
while(!scl.get()) {}
uint8_t s = sda.get();
scl.set(0);
return !s;
} }
void SoftTWI::read(uint8_t* data, unsigned data_len, bool nack_at_end) { void SoftTWI::read(uint8_t* data, unsigned data_len, bool nack_at_end) {
@ -54,3 +65,21 @@ unsigned SoftTWI::write(const uint8_t* data, unsigned data_len) {
return data_len; return data_len;
} }
bool SoftTWI::start(uint8_t addr) {
port::Drain sda(_sda);
port::Drain scl(_scl);
sda.set(1);
scl.set(1);
sda.set(0);
scl.set(0);
write(addr);
}
void SoftTWI::end() {
port::Drain sda(_sda);
port::Drain scl(_scl);
sda.set(0);
scl.set(1);
sda.set(1);
}

View File

@ -6,115 +6,29 @@
struct SoftTWI { struct SoftTWI {
constexpr SoftTWI(unsigned sda, unsigned scl, unsigned delay = 0); constexpr SoftTWI::SoftTWI(unsigned sda, unsigned scl)
: _sda(sda)
, _scl(scl) {
}
void begin();
inline void sleep(uint8_t=1) AW_IN {}
inline void wait_scl() AW_IN;
void set_pin(uint8_t, bool);
inline void set_sda(bool) AW_IN;
inline void set_scl(bool) AW_IN;
bool read_pin(uint8_t);
inline bool read_sda() AW_IN;
inline bool read_scl() AW_IN;
inline void write_bit(bool) AW_IN;
bool write(uint8_t);
unsigned write(const uint8_t*, unsigned); unsigned write(const uint8_t*, unsigned);
inline bool read_bit() AW_IN;
uint8_t read(bool=true);
void read(uint8_t*, unsigned, bool=false); void read(uint8_t*, unsigned, bool=false);
uint8_t read(bool=true);
bool write(uint8_t);
void end();
inline bool start_read(uint8_t addr) {
return start((addr << 1) | 1);
}
inline bool start_read(uint8_t) AW_IN; inline bool start_write(uint8_t addr) {
inline bool start_write(uint8_t) AW_IN; return start(addr << 1);
}
inline void start() AW_IN;
inline void end() AW_IN;
private: private:
unsigned _sda; unsigned _sda;
unsigned _scl; unsigned _scl;
unsigned _delay;
bool start(uint8_t addr);
}; };
constexpr SoftTWI::SoftTWI(unsigned sda, unsigned scl, unsigned delay)
: _sda(sda)
, _scl(scl)
, _delay(delay) {
}
inline void SoftTWI::set_sda(bool s) {
set_pin(_sda, s);
}
inline void SoftTWI::set_scl(bool s) {
set_pin(_scl, s);
}
inline bool SoftTWI::read_sda() {
return read_pin(_sda);
}
inline bool SoftTWI::read_scl() {
return read_pin(_scl);
}
inline void SoftTWI::wait_scl() {
while(!read_pin(_scl)) {}
}
inline 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;
}
inline void SoftTWI::write_bit(bool s) {
set_sda(s);
sleep();
set_scl(1);
sleep(2);
wait_scl();
set_scl(0);
sleep();
}
inline void SoftTWI::start() {
set_sda(1);
sleep();
set_scl(1);
sleep();
set_sda(0);
sleep();
set_scl(0);
sleep();
}
inline void SoftTWI::end() {
set_sda(0);
sleep();
set_scl(1);
sleep();
set_sda(1);
sleep(2);
}
inline bool SoftTWI::start_read(uint8_t addr) {
start();
return write((addr << 1) | 1);
}
inline bool SoftTWI::start_write(uint8_t addr) {
start();
return write(addr << 1);
}

View File

@ -25,7 +25,6 @@ void setup() {
Tone::init(); Tone::init();
dac::init(); dac::init();
serial::init(); serial::init();
eeprom::init();
tones::init(); tones::init();
indicator::init(); indicator::init();
buttons::init(); buttons::init();