From 78965abed2c9311b61fbaf7abb279025138edf2a Mon Sep 17 00:00:00 2001 From: Jay Robson Date: Tue, 1 Oct 2024 16:19:43 +1000 Subject: [PATCH] optimise I2C --- eeprom.cpp | 4 -- eeprom.hpp | 1 - port.hpp | 69 ++++++++++++++++++++++++++ soft_twi.cpp | 77 ++++++++++++++++++++--------- soft_twi.hpp | 118 ++++++--------------------------------------- tone-generator.ino | 1 - 6 files changed, 138 insertions(+), 132 deletions(-) create mode 100644 port.hpp diff --git a/eeprom.cpp b/eeprom.cpp index 3fbe556..3828c9a 100644 --- a/eeprom.cpp +++ b/eeprom.cpp @@ -33,10 +33,6 @@ static void set_address(uint8_t i2c_addr, uint16_t at) { mem.write(at); } -void eeprom::init() { - mem.begin(); -} - void eeprom::jump(uint32_t p_at) { last_block_end = 0; at = p_at; diff --git a/eeprom.hpp b/eeprom.hpp index 3aef733..b82c041 100644 --- a/eeprom.hpp +++ b/eeprom.hpp @@ -12,7 +12,6 @@ namespace eeprom { inline SoftTWI mem(A4, A5); - void init(); void jump(uint32_t addr); void read(char* data, uint16_t len); void page_write(uint32_t at, const char* data); diff --git a/port.hpp b/port.hpp new file mode 100644 index 0000000..bd67cbf --- /dev/null +++ b/port.hpp @@ -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; + } + } + }; +}; + diff --git a/soft_twi.cpp b/soft_twi.cpp index 9cbc404..2941aa5 100644 --- a/soft_twi.cpp +++ b/soft_twi.cpp @@ -1,42 +1,53 @@ -#include "soft_twi.hpp" #include - -void SoftTWI::set_pin(uint8_t pin, bool state) { - 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); -} +#include "soft_twi.hpp" +#include "port.hpp" uint8_t SoftTWI::read(bool ack) { + port::Drain sda(_sda); + port::Drain scl(_scl); + uint8_t v = 0; for(unsigned m = 0x80; m; m >>= 1) { - if(read_bit()) { + sda.set(1); + scl.set(1); + while(!scl.get()) {} + if(sda.get()) { 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; } bool SoftTWI::write(uint8_t v) { + port::Drain sda(_sda); + port::Drain scl(_scl); + 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) { @@ -54,3 +65,21 @@ unsigned SoftTWI::write(const uint8_t* data, unsigned 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); +} + diff --git a/soft_twi.hpp b/soft_twi.hpp index 9c25faa..3b9ceaf 100644 --- a/soft_twi.hpp +++ b/soft_twi.hpp @@ -6,115 +6,29 @@ 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); - - inline bool read_bit() AW_IN; - uint8_t read(bool=true); 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) AW_IN; - - inline void start() AW_IN; - inline void end() AW_IN; + inline bool start_write(uint8_t addr) { + return start(addr << 1); + } private: unsigned _sda; 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); -} - diff --git a/tone-generator.ino b/tone-generator.ino index 6b0fa7e..0f5d550 100644 --- a/tone-generator.ino +++ b/tone-generator.ino @@ -25,7 +25,6 @@ void setup() { Tone::init(); dac::init(); serial::init(); - eeprom::init(); tones::init(); indicator::init(); buttons::init();