From 27680097203f1482ba61a9cceef689305d7eadc4 Mon Sep 17 00:00:00 2001 From: BlackMark Date: Fri, 15 May 2020 11:50:11 +0200 Subject: [PATCH] Remove twi library and switch to i2c library submodule --- rtc.cpp | 303 +++++++++++++++--------------- rtc.h | 9 +- twi-lowlevel.cpp | 479 ----------------------------------------------- twi-lowlevel.h | 55 ------ twi.cpp | 226 ---------------------- twi.h | 40 ---- 6 files changed, 160 insertions(+), 952 deletions(-) delete mode 100644 twi-lowlevel.cpp delete mode 100644 twi-lowlevel.h delete mode 100644 twi.cpp delete mode 100644 twi.h diff --git a/rtc.cpp b/rtc.cpp index 8ebef4d..f545dd6 100644 --- a/rtc.cpp +++ b/rtc.cpp @@ -15,7 +15,7 @@ /* * DS1307 register map - * + * * 00h-06h: seconds, minutes, hours, day-of-week, date, month, year (all in BCD) * bit 7 of seconds enables/disables clock * bit 6 of hours toggles 12/24h mode (1 for 12h, 0 for 24h) @@ -73,6 +73,11 @@ #define TRUE 1 #define FALSE 0 +#include "../clock.hpp" + +#include "../i2c/i2c.hpp" +using i2c_t = i2c::I2c>; + #include "rtc.h" #define RTC_ADDR 0x68 // I2C address @@ -93,20 +98,23 @@ uint8_t bcd2dec(uint8_t b) uint8_t rtc_read_byte(uint8_t offset) { - twi_begin_transmission(RTC_ADDR); - twi_send_byte(offset); - twi_end_transmission(); + i2c_t::start(false); + i2c_t::write(offset); + i2c_t::stop(); - twi_request_from(RTC_ADDR, 1); - return twi_receive(); + i2c_t::start(true); + const auto received = i2c_t::read(); + i2c_t::stop(); + + return received; } void rtc_write_byte(uint8_t b, uint8_t offset) { - twi_begin_transmission(RTC_ADDR); - twi_send_byte(offset); - twi_send_byte(b); - twi_end_transmission(); + i2c_t::start(false); + i2c_t::write(offset); + i2c_t::write(b); + i2c_t::stop(); } static bool s_is_ds1307 = false; @@ -114,16 +122,18 @@ static bool s_is_ds3231 = false; void rtc_init(void) { + i2c_t::init(); + // Attempt autodetection: // 1) Read and save temperature register // 2) Write a value to temperature register // 3) Read back the value // equal to the one written: DS1307, write back saved value and return // different from written: DS3231 - + uint8_t temp1 = rtc_read_byte(0x11); uint8_t temp2 = rtc_read_byte(0x12); - + rtc_write_byte(0xee, 0x11); rtc_write_byte(0xdd, 0x12); @@ -153,17 +163,13 @@ struct rtc_tm* rtc_get_time(void) // read 7 bytes starting from register 0 // sec, min, hour, day-of-week, date, month, year - twi_begin_transmission(RTC_ADDR); - twi_send_byte(0x0); - twi_end_transmission(); + i2c_t::start(false); + i2c_t::write(0x0); + i2c_t::stop(); - twi_request_from(RTC_ADDR, 7); - - for (uint8_t i = 0; i < 7; i++) { - rtc[i] = twi_receive(); - } - - twi_end_transmission(); + i2c_t::start(true); + i2c_t::readBytes<7>(rtc); + i2c_t::stop(); // Clear clock halt bit from read data // This starts the clock for a DS1307, and has no effect for a DS3231 @@ -198,18 +204,14 @@ void rtc_get_time_s(uint8_t* hour, uint8_t* min, uint8_t* sec) // read 7 bytes starting from register 0 // sec, min, hour, day-of-week, date, month, year - twi_begin_transmission(RTC_ADDR); - twi_send_byte(0x0); - twi_end_transmission(); - - twi_request_from(RTC_ADDR, 7); - - for(uint8_t i=0; i<7; i++) { - rtc[i] = twi_receive(); - } - - twi_end_transmission(); - + i2c_t::start(false); + i2c_t::write(0x0); + i2c_t::stop(); + + i2c_t::start(true); + i2c_t::readBytes<7>(rtc); + i2c_t::stop(); + if (sec) *sec = bcd2dec(rtc[0]); if (min) *min = bcd2dec(rtc[1]); if (hour) *hour = bcd2dec(rtc[2]); @@ -218,8 +220,8 @@ void rtc_get_time_s(uint8_t* hour, uint8_t* min, uint8_t* sec) // fixme: support 12-hour mode for setting time void rtc_set_time(struct rtc_tm* tm_) { - twi_begin_transmission(RTC_ADDR); - twi_send_byte(0x0); + i2c_t::start(false); + i2c_t::write(0x0); uint8_t century; if (tm_->year > 2000) { @@ -231,28 +233,28 @@ void rtc_set_time(struct rtc_tm* tm_) } // clock halt bit is 7th bit of seconds: this is always cleared to start the clock - twi_send_byte(dec2bcd(tm_->sec)); // seconds - twi_send_byte(dec2bcd(tm_->min)); // minutes - twi_send_byte(dec2bcd(tm_->hour)); // hours - twi_send_byte(dec2bcd(tm_->wday)); // day of week - twi_send_byte(dec2bcd(tm_->mday)); // day - twi_send_byte(dec2bcd(tm_->mon) + century); // month - twi_send_byte(dec2bcd(tm_->year)); // year + i2c_t::write(dec2bcd(tm_->sec)); // seconds + i2c_t::write(dec2bcd(tm_->min)); // minutes + i2c_t::write(dec2bcd(tm_->hour)); // hours + i2c_t::write(dec2bcd(tm_->wday)); // day of week + i2c_t::write(dec2bcd(tm_->mday)); // day + i2c_t::write(dec2bcd(tm_->mon) + century); // month + i2c_t::write(dec2bcd(tm_->year)); // year - twi_end_transmission(); + i2c_t::stop(); } void rtc_set_time_s(uint8_t hour, uint8_t min, uint8_t sec) { - twi_begin_transmission(RTC_ADDR); - twi_send_byte(0x0); + i2c_t::start(false); + i2c_t::write(0x0); // clock halt bit is 7th bit of seconds: this is always cleared to start the clock - twi_send_byte(dec2bcd(sec)); // seconds - twi_send_byte(dec2bcd(min)); // minutes - twi_send_byte(dec2bcd(hour)); // hours - - twi_end_transmission(); + i2c_t::write(dec2bcd(sec)); // seconds + i2c_t::write(dec2bcd(min)); // minutes + i2c_t::write(dec2bcd(hour)); // hours + + i2c_t::stop(); } // DS1307 only (has no effect when run on DS3231) @@ -263,14 +265,14 @@ void rtc_set_time_s(uint8_t hour, uint8_t min, uint8_t sec) void rtc_run_clock(bool run) { if (s_is_ds3231) return; - + uint8_t b = rtc_read_byte(0x0); if (run) b &= ~(_BV(CH_BIT)); // clear bit else b |= _BV(CH_BIT); // set bit - + rtc_write_byte(b, 0x0); } @@ -280,7 +282,7 @@ void rtc_run_clock(bool run) bool rtc_is_clock_running(void) { if (s_is_ds3231) return true; - + uint8_t b = rtc_read_byte(0x0); if (b & _BV(CH_BIT)) return false; @@ -290,31 +292,28 @@ bool rtc_is_clock_running(void) void ds3231_get_temp_int(int8_t* i, uint8_t* f) { uint8_t msb, lsb; - + *i = 0; *f = 0; - + if (s_is_ds1307) return; // only valid on DS3231 - twi_begin_transmission(RTC_ADDR); + i2c_t::start(false); // temp registers 0x11 and 0x12 - twi_send_byte(0x11); - twi_end_transmission(); + i2c_t::write(0x11); + i2c_t::stop(); - twi_request_from(RTC_ADDR, 2); + i2c_t::start(true); + msb = i2c_t::read(); // integer part (in twos complement) + lsb = i2c_t::read(); // fraction part - if (twi_available()) { - msb = twi_receive(); // integer part (in twos complement) - lsb = twi_receive(); // fraction part - - // integer part in entire byte - *i = msb; - // fractional part in top two bits (increments of 0.25) - *f = (lsb >> 6) * 25; + // integer part in entire byte + *i = msb; + // fractional part in top two bits (increments of 0.25) + *f = (lsb >> 6) * 25; - // float value can be read like so: - // float temp = ((((short)msb << 8) | (short)lsb) >> 6) / 4.0f; - } + // float value can be read like so: + // float temp = ((((short)msb << 8) | (short)lsb) >> 6) / 4.0f; } void rtc_force_temp_conversion(uint8_t block) @@ -322,31 +321,34 @@ void rtc_force_temp_conversion(uint8_t block) if (s_is_ds1307) return; // only valid on DS3231 // read control register (0x0E) - twi_begin_transmission(RTC_ADDR); - twi_send_byte(0x0E); - twi_end_transmission(); + i2c_t::start(false); + i2c_t::write(0x0E); + i2c_t::stop(); - twi_request_from(RTC_ADDR, 1); - uint8_t ctrl = twi_receive(); + i2c_t::start(true); + uint8_t ctrl = i2c_t::read(); + i2c_t::stop(); ctrl |= 0b00100000; // Set CONV bit // write new control register value - twi_begin_transmission(RTC_ADDR); - twi_send_byte(0x0E); - twi_send_byte(ctrl); - twi_end_transmission(); + i2c_t::start(false); + i2c_t::write(0x0E); + i2c_t::write(ctrl); + i2c_t::stop(); if (!block) return; - + // Temp conversion is ready when control register becomes 0 do { // Block until CONV is 0 - twi_begin_transmission(RTC_ADDR); - twi_send_byte(0x0E); - twi_end_transmission(); - twi_request_from(RTC_ADDR, 1); - } while ((twi_receive() & 0b00100000) != 0); + i2c_t::start(false); + i2c_t::write(0x0E); + i2c_t::stop(); + + i2c_t::start(true); + // HACK: Missing stop after read, might still work though + } while ((i2c_t::read() & 0b00100000) != 0); } @@ -371,32 +373,35 @@ void rtc_set_sram(uint8_t *data) uint8_t rtc_get_sram_byte(uint8_t offset) { - twi_begin_transmission(RTC_ADDR); - twi_send_byte(DS1307_SRAM_ADDR + offset); - twi_end_transmission(); + i2c_t::start(false); + i2c_t::write(DS1307_SRAM_ADDR + offset); + i2c_t::stop(); - twi_request_from(RTC_ADDR, 1); - return twi_receive(); + i2c_t::start(true); + const auto received = i2c_t::read(); + i2c_t::stop(); + return received; } void rtc_set_sram_byte(uint8_t b, uint8_t offset) { - twi_begin_transmission(RTC_ADDR); - twi_send_byte(DS1307_SRAM_ADDR + offset); - twi_send_byte(b); - twi_end_transmission(); + i2c_t::start(false); + i2c_t::write(DS1307_SRAM_ADDR + offset); + i2c_t::write(b); + i2c_t::stop(); } void rtc_SQW_enable(bool enable) { if (s_is_ds1307) { - twi_begin_transmission(RTC_ADDR); - twi_send_byte(0x07); - twi_end_transmission(); - + i2c_t::start(false); + i2c_t::write(0x07); + i2c_t::stop(); + // read control - twi_request_from(RTC_ADDR, 1); - uint8_t control = twi_receive(); + i2c_t::start(true); + uint8_t control = i2c_t::read(); + i2c_t::stop(); if (enable) control |= 0b00010000; // set SQWE to 1 @@ -404,20 +409,21 @@ void rtc_SQW_enable(bool enable) control &= ~0b00010000; // set SQWE to 0 // write control back - twi_begin_transmission(RTC_ADDR); - twi_send_byte(0x07); - twi_send_byte(control); - twi_end_transmission(); + i2c_t::start(false); + i2c_t::write(0x07); + i2c_t::write(control); + i2c_t::stop(); } else { // DS3231 - twi_begin_transmission(RTC_ADDR); - twi_send_byte(0x0E); - twi_end_transmission(); - + i2c_t::start(false); + i2c_t::write(0x0E); + i2c_t::stop(); + // read control - twi_request_from(RTC_ADDR, 1); - uint8_t control = twi_receive(); + i2c_t::start(true); + uint8_t control = i2c_t::read(); + i2c_t::stop(); if (enable) { control |= 0b01000000; // set BBSQW to 1 @@ -428,51 +434,53 @@ void rtc_SQW_enable(bool enable) } // write control back - twi_begin_transmission(RTC_ADDR); - twi_send_byte(0x0E); - twi_send_byte(control); - twi_end_transmission(); + i2c_t::start(false); + i2c_t::write(0x0E); + i2c_t::write(control); + i2c_t::stop(); } } void rtc_SQW_set_freq(enum RTC_SQW_FREQ freq) { if (s_is_ds1307) { - twi_begin_transmission(RTC_ADDR); - twi_send_byte(0x07); - twi_end_transmission(); - + i2c_t::start(false); + i2c_t::write(0x07); + i2c_t::stop(); + // read control (uses bits 0 and 1) - twi_request_from(RTC_ADDR, 1); - uint8_t control = twi_receive(); + i2c_t::start(true); + uint8_t control = i2c_t::read(); + i2c_t::stop(); control &= ~0b00000011; // Set to 0 control |= freq; // Set freq bitmask // write control back - twi_begin_transmission(RTC_ADDR); - twi_send_byte(0x07); - twi_send_byte(control); - twi_end_transmission(); + i2c_t::start(false); + i2c_t::write(0x07); + i2c_t::write(control); + i2c_t::stop(); } else { // DS3231 - twi_begin_transmission(RTC_ADDR); - twi_send_byte(0x0E); - twi_end_transmission(); - + i2c_t::start(false); + i2c_t::write(0x0E); + i2c_t::stop(); + // read control (uses bits 3 and 4) - twi_request_from(RTC_ADDR, 1); - uint8_t control = twi_receive(); + i2c_t::start(true); + uint8_t control = i2c_t::read(); + i2c_t::stop(); control &= ~0b00011000; // Set to 0 control |= (freq << 4); // Set freq bitmask // write control back - twi_begin_transmission(RTC_ADDR); - twi_send_byte(0x0E); - twi_send_byte(control); - twi_end_transmission(); + i2c_t::start(false); + i2c_t::write(0x0E); + i2c_t::write(control); + i2c_t::stop(); } } @@ -480,13 +488,14 @@ void rtc_osc32kHz_enable(bool enable) { if (!s_is_ds3231) return; - twi_begin_transmission(RTC_ADDR); - twi_send_byte(0x0F); - twi_end_transmission(); + i2c_t::start(false); + i2c_t::write(0x0F); + i2c_t::stop(); // read status - twi_request_from(RTC_ADDR, 1); - uint8_t status = twi_receive(); + i2c_t::start(true); + uint8_t status = i2c_t::read(); + i2c_t::stop(); if (enable) status |= 0b00001000; // set to 1 @@ -494,14 +503,14 @@ void rtc_osc32kHz_enable(bool enable) status &= ~0b00001000; // Set to 0 // write status back - twi_begin_transmission(RTC_ADDR); - twi_send_byte(0x0F); - twi_send_byte(status); - twi_end_transmission(); + i2c_t::start(false); + i2c_t::write(0x0F); + i2c_t::write(status); + i2c_t::stop(); } // Alarm functionality -// fixme: should decide if "alarm disabled" mode should be available, or if alarm should always be enabled +// fixme: should decide if "alarm disabled" mode should be available, or if alarm should always be enabled // at 00:00:00. Currently, "alarm disabled" only works for ds3231 void rtc_reset_alarm(void) { @@ -590,7 +599,7 @@ bool rtc_check_alarm(void) uint8_t cur_hour, cur_min, cur_sec; rtc_get_time_s(&cur_hour, &cur_min, &cur_sec); - + if (cur_hour == hour && cur_min == min && cur_sec == sec) return true; return false; @@ -602,7 +611,7 @@ bool rtc_check_alarm(void) // clear flag when set if (val & 1) rtc_write_byte(val & ~0b00000001, 0x0f); - + return val & 1 ? 1 : 0; } } diff --git a/rtc.h b/rtc.h index da0424e..32890af 100644 --- a/rtc.h +++ b/rtc.h @@ -18,14 +18,13 @@ #include #include -#include "twi.h" #define DS1307_SLAVE_ADDR 0b11010000 /** Time structure - * + * * Both 24-hour and 12-hour time is stored, and is always updated when rtc_get_time is called. - * + * * When setting time and alarm, 24-hour mode is always used. * * If you run your clock in 12-hour mode: @@ -52,7 +51,7 @@ struct rtc_tm { int twelveHour; // 12 hour clock time }; -// statically allocated +// statically allocated extern struct rtc_tm _rtc_tm; // Initialize the RTC and autodetect type (DS1307 or DS3231) @@ -102,6 +101,6 @@ void rtc_set_alarm(struct rtc_tm* tm_); void rtc_set_alarm_s(uint8_t hour, uint8_t min, uint8_t sec); struct rtc_tm* rtc_get_alarm(void); void rtc_get_alarm_s(uint8_t* hour, uint8_t* min, uint8_t* sec); -bool rtc_check_alarm(void); +bool rtc_check_alarm(void); #endif diff --git a/twi-lowlevel.cpp b/twi-lowlevel.cpp deleted file mode 100644 index 73268b4..0000000 --- a/twi-lowlevel.cpp +++ /dev/null @@ -1,479 +0,0 @@ -/* - twi.c - TWI/I2C library for Wiring & Arduino - Copyright (c) 2006 Nicholas Zambetti. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include -#include -#include -#include - -#ifndef cbi -#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) -#endif - -#ifndef sbi -#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) -#endif - -#include "twi-lowlevel.h" - -static volatile uint8_t twi_state; -static uint8_t twi_slarw; - -static void (*twi_onSlaveTransmit)(void); -static void (*twi_onSlaveReceive)(uint8_t*, int); - -static uint8_t twi_masterBuffer[TWI_BUFFER_LENGTH]; -static volatile uint8_t twi_masterBufferIndex; -static uint8_t twi_masterBufferLength; - -static uint8_t twi_txBuffer[TWI_BUFFER_LENGTH]; -static volatile uint8_t twi_txBufferIndex; -static volatile uint8_t twi_txBufferLength; - -static uint8_t twi_rxBuffer[TWI_BUFFER_LENGTH]; -static volatile uint8_t twi_rxBufferIndex; - -static volatile uint8_t twi_error; - -/* - * Function twi_init - * Desc readys twi pins and sets twi bitrate - * Input none - * Output none - */ -void twi_init(void) -{ - // initialize state - twi_state = TWI_READY; - - #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega328P__) - // activate internal pull-ups for twi - // as per note from atmega8 manual pg167 - sbi(PORTC, 4); - sbi(PORTC, 5); - #else - // activate internal pull-ups for twi - // as per note from atmega128 manual pg204 - sbi(PORTD, 0); - sbi(PORTD, 1); - #endif - - // initialize twi prescaler and bit rate - cbi(TWSR, TWPS0); - cbi(TWSR, TWPS1); - TWBR = ((F_CPU / TWI_FREQ) - 16) / 2; - - /* twi bit rate formula from atmega128 manual pg 204 - SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR)) - note: TWBR should be 10 or higher for master mode - It is 72 for a 16mhz Wiring board with 100kHz TWI */ - - // enable twi module, acks, and twi interrupt - TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA); -} - -/* - * Function twi_slaveInit - * Desc sets slave address and enables interrupt - * Input none - * Output none - */ -void twi_setAddress(uint8_t address) -{ - // set twi slave address (skip over TWGCE bit) - TWAR = address << 1; -} - -/* - * Function twi_readFrom - * Desc attempts to become twi bus master and read a - * series of bytes from a device on the bus - * Input address: 7bit i2c device address - * data: pointer to byte array - * length: number of bytes to read into array - * Output number of bytes read - */ -uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length) -{ - uint8_t i; - - // ensure data will fit into buffer - if(TWI_BUFFER_LENGTH < length){ - return 0; - } - - // wait until twi is ready, become master receiver - while(TWI_READY != twi_state){ - continue; - } - twi_state = TWI_MRX; - // reset error state (0xFF.. no error occured) - twi_error = 0xFF; - - // initialize buffer iteration vars - twi_masterBufferIndex = 0; - twi_masterBufferLength = length-1; // This is not intuitive, read on... - // On receive, the previously configured ACK/NACK setting is transmitted in - // response to the received byte before the interrupt is signalled. - // Therefor we must actually set NACK when the _next_ to last byte is - // received, causing that NACK to be sent in response to receiving the last - // expected byte of data. - - // build sla+w, slave device address + w bit - twi_slarw = TW_READ; - twi_slarw |= address << 1; - - // send start condition - TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA); - - // wait for read operation to complete - while(TWI_MRX == twi_state){ - continue; - } - - if (twi_masterBufferIndex < length) - length = twi_masterBufferIndex; - - // copy twi buffer to data - for(i = 0; i < length; ++i){ - data[i] = twi_masterBuffer[i]; - } - - return length; -} - -/* - * Function twi_writeTo - * Desc attempts to become twi bus master and write a - * series of bytes to a device on the bus - * Input address: 7bit i2c device address - * data: pointer to byte array - * length: number of bytes in array - * wait: boolean indicating to wait for write or not - * Output 0 .. success - * 1 .. length to long for buffer - * 2 .. address send, NACK received - * 3 .. data send, NACK received - * 4 .. other twi error (lost bus arbitration, bus error, ..) - */ -uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait) -{ - uint8_t i; - - // ensure data will fit into buffer - if(TWI_BUFFER_LENGTH < length){ - return 1; - } - - // wait until twi is ready, become master transmitter - while(TWI_READY != twi_state){ - continue; - } - twi_state = TWI_MTX; - // reset error state (0xFF.. no error occured) - twi_error = 0xFF; - - // initialize buffer iteration vars - twi_masterBufferIndex = 0; - twi_masterBufferLength = length; - - // copy data to twi buffer - for(i = 0; i < length; ++i){ - twi_masterBuffer[i] = data[i]; - } - - // build sla+w, slave device address + w bit - twi_slarw = TW_WRITE; - twi_slarw |= address << 1; - - // send start condition - TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA); - - // wait for write operation to complete - while(wait && (TWI_MTX == twi_state)){ - continue; - } - - if (twi_error == 0xFF) - return 0; // success - else if (twi_error == TW_MT_SLA_NACK) - return 2; // error: address send, nack received - else if (twi_error == TW_MT_DATA_NACK) - return 3; // error: data send, nack received - else - return 4; // other twi error -} - -/* - * Function twi_transmit - * Desc fills slave tx buffer with data - * must be called in slave tx event callback - * Input data: pointer to byte array - * length: number of bytes in array - * Output 1 length too long for buffer - * 2 not slave transmitter - * 0 ok - */ -uint8_t twi_transmit(uint8_t* data, uint8_t length) -{ - uint8_t i; - - // ensure data will fit into buffer - if(TWI_BUFFER_LENGTH < length){ - return 1; - } - - // ensure we are currently a slave transmitter - if(TWI_STX != twi_state){ - return 2; - } - - // set length and copy data into tx buffer - twi_txBufferLength = length; - for(i = 0; i < length; ++i){ - twi_txBuffer[i] = data[i]; - } - - return 0; -} - -/* - * Function twi_attachSlaveRxEvent - * Desc sets function called before a slave read operation - * Input function: callback function to use - * Output none - */ -void twi_attachSlaveRxEvent( void (*function)(uint8_t*, int) ) -{ - twi_onSlaveReceive = function; -} - -/* - * Function twi_attachSlaveTxEvent - * Desc sets function called before a slave write operation - * Input function: callback function to use - * Output none - */ -void twi_attachSlaveTxEvent( void (*function)(void) ) -{ - twi_onSlaveTransmit = function; -} - -/* - * Function twi_reply - * Desc sends byte or readys receive line - * Input ack: byte indicating to ack or to nack - * Output none - */ -void twi_reply(uint8_t ack) -{ - // transmit master read ready signal, with or without ack - if(ack){ - TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA); - }else{ - TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT); - } -} - -/* - * Function twi_stop - * Desc relinquishes bus master status - * Input none - * Output none - */ -void twi_stop(void) -{ - // send stop condition - TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO); - - // wait for stop condition to be exectued on bus - // TWINT is not set after a stop condition! - while(TWCR & _BV(TWSTO)){ - continue; - } - - // update twi state - twi_state = TWI_READY; -} - -/* - * Function twi_releaseBus - * Desc releases bus control - * Input none - * Output none - */ -void twi_releaseBus(void) -{ - // release bus - TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT); - - // update twi state - twi_state = TWI_READY; -} - -SIGNAL(TWI_vect) -{ - switch(TW_STATUS){ - // All Master - case TW_START: // sent start condition - case TW_REP_START: // sent repeated start condition - // copy device address and r/w bit to output register and ack - TWDR = twi_slarw; - twi_reply(1); - break; - - // Master Transmitter - case TW_MT_SLA_ACK: // slave receiver acked address - case TW_MT_DATA_ACK: // slave receiver acked data - // if there is data to send, send it, otherwise stop - if(twi_masterBufferIndex < twi_masterBufferLength){ - // copy data to output register and ack - TWDR = twi_masterBuffer[twi_masterBufferIndex++]; - twi_reply(1); - }else{ - twi_stop(); - } - break; - case TW_MT_SLA_NACK: // address sent, nack received - twi_error = TW_MT_SLA_NACK; - twi_stop(); - break; - case TW_MT_DATA_NACK: // data sent, nack received - twi_error = TW_MT_DATA_NACK; - twi_stop(); - break; - case TW_MT_ARB_LOST: // lost bus arbitration - twi_error = TW_MT_ARB_LOST; - twi_releaseBus(); - break; - - // Master Receiver - case TW_MR_DATA_ACK: // data received, ack sent - // put byte into buffer - twi_masterBuffer[twi_masterBufferIndex++] = TWDR; - [[fallthrough]]; - case TW_MR_SLA_ACK: // address sent, ack received - // ack if more bytes are expected, otherwise nack - if(twi_masterBufferIndex < twi_masterBufferLength){ - twi_reply(1); - }else{ - twi_reply(0); - } - break; - case TW_MR_DATA_NACK: // data received, nack sent - // put final byte into buffer - twi_masterBuffer[twi_masterBufferIndex++] = TWDR; - [[fallthrough]]; - case TW_MR_SLA_NACK: // address sent, nack received - twi_stop(); - break; - // TW_MR_ARB_LOST handled by TW_MT_ARB_LOST case - - // Slave Receiver - case TW_SR_SLA_ACK: // addressed, returned ack - case TW_SR_GCALL_ACK: // addressed generally, returned ack - case TW_SR_ARB_LOST_SLA_ACK: // lost arbitration, returned ack - case TW_SR_ARB_LOST_GCALL_ACK: // lost arbitration, returned ack - // enter slave receiver mode - twi_state = TWI_SRX; - // indicate that rx buffer can be overwritten and ack - twi_rxBufferIndex = 0; - twi_reply(1); - break; - case TW_SR_DATA_ACK: // data received, returned ack - case TW_SR_GCALL_DATA_ACK: // data received generally, returned ack - // if there is still room in the rx buffer - if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){ - // put byte in buffer and ack - twi_rxBuffer[twi_rxBufferIndex++] = TWDR; - twi_reply(1); - }else{ - // otherwise nack - twi_reply(0); - } - break; - case TW_SR_STOP: // stop or repeated start condition received - // put a null char after data if there's room - if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){ - twi_rxBuffer[twi_rxBufferIndex] = '\0'; - } - // sends ack and stops interface for clock stretching - twi_stop(); - // callback to user defined callback - twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex); - // since we submit rx buffer to "wire" library, we can reset it - twi_rxBufferIndex = 0; - // ack future responses and leave slave receiver state - twi_releaseBus(); - break; - case TW_SR_DATA_NACK: // data received, returned nack - case TW_SR_GCALL_DATA_NACK: // data received generally, returned nack - // nack back at master - twi_reply(0); - break; - - // Slave Transmitter - case TW_ST_SLA_ACK: // addressed, returned ack - case TW_ST_ARB_LOST_SLA_ACK: // arbitration lost, returned ack - // enter slave transmitter mode - twi_state = TWI_STX; - // ready the tx buffer index for iteration - twi_txBufferIndex = 0; - // set tx buffer length to be zero, to verify if user changes it - twi_txBufferLength = 0; - // request for txBuffer to be filled and length to be set - // note: user must call twi_transmit(bytes, length) to do this - twi_onSlaveTransmit(); - // if they didn't change buffer & length, initialize it - if(0 == twi_txBufferLength){ - twi_txBufferLength = 1; - twi_txBuffer[0] = 0x00; - } - // transmit first byte from buffer, fall - [[fallthrough]]; - case TW_ST_DATA_ACK: // byte sent, ack returned - // copy data to output register - TWDR = twi_txBuffer[twi_txBufferIndex++]; - // if there is more to send, ack, otherwise nack - if(twi_txBufferIndex < twi_txBufferLength){ - twi_reply(1); - }else{ - twi_reply(0); - } - break; - case TW_ST_DATA_NACK: // received nack, we are done - case TW_ST_LAST_DATA: // received ack, but we are done already! - // ack future responses - twi_reply(1); - // leave slave receiver state - twi_state = TWI_READY; - break; - - // All - case TW_NO_INFO: // no state information - break; - case TW_BUS_ERROR: // bus error, illegal stop/start - twi_error = TW_BUS_ERROR; - twi_stop(); - break; - } -} - diff --git a/twi-lowlevel.h b/twi-lowlevel.h deleted file mode 100644 index 1619272..0000000 --- a/twi-lowlevel.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - twi.h - TWI/I2C library for Wiring & Arduino - Copyright (c) 2006 Nicholas Zambetti. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef twi_h -#define twi_h - -#include - -#include "../clock.hpp" - -//#define ATMEGA8 - -#ifndef TWI_FREQ -#define TWI_FREQ 100000L -#endif - -#ifndef TWI_BUFFER_LENGTH -#define TWI_BUFFER_LENGTH 32 -#endif - -#define TWI_READY 0 -#define TWI_MRX 1 -#define TWI_MTX 2 -#define TWI_SRX 3 -#define TWI_STX 4 - -void twi_init(void); -void twi_setAddress(uint8_t); -uint8_t twi_readFrom(uint8_t, uint8_t*, uint8_t); -uint8_t twi_writeTo(uint8_t, uint8_t*, uint8_t, uint8_t); -uint8_t twi_transmit(uint8_t*, uint8_t); -void twi_attachSlaveRxEvent( void (*)(uint8_t*, int) ); -void twi_attachSlaveTxEvent( void (*)(void) ); -void twi_reply(uint8_t); -void twi_stop(void); -void twi_releaseBus(void); - -#endif - diff --git a/twi.cpp b/twi.cpp deleted file mode 100644 index f0f347d..0000000 --- a/twi.cpp +++ /dev/null @@ -1,226 +0,0 @@ -/* - TwoWire.cpp - TWI/I2C library for Wiring & Arduino - Copyright (c) 2006 Nicholas Zambetti. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include -#include "twi-lowlevel.h" - -#include "twi.h" - -// local variables -uint8_t rxBuffer[BUFFER_LENGTH]; -uint8_t rxBufferIndex = 0; -uint8_t rxBufferLength = 0; - -uint8_t txAddress = 0; -uint8_t txBuffer[BUFFER_LENGTH]; -uint8_t txBufferIndex = 0; -uint8_t txBufferLength = 0; - -uint8_t transmitting = 0; -void (*user_onRequest)(void); -void (*user_onReceive)(int); - -void onRequestService(void); -void onReceiveService(uint8_t*, int); - -void twi_init_master(void) -{ - rxBufferIndex = 0; - rxBufferLength = 0; - - txBufferIndex = 0; - txBufferLength = 0; - - twi_init(); -} - -void twi_init_slave(uint8_t address) -{ - twi_setAddress(address); - twi_attachSlaveTxEvent(onRequestService); - twi_attachSlaveRxEvent(onReceiveService); - twi_init_master(); -} - -uint8_t twi_request_from(uint8_t address, uint8_t quantity) -{ - // clamp to buffer length - if(quantity > BUFFER_LENGTH){ - quantity = BUFFER_LENGTH; - } - // perform blocking read into buffer - uint8_t read = twi_readFrom(address, rxBuffer, quantity); - // set rx buffer iterator vars - rxBufferIndex = 0; - rxBufferLength = read; - - return read; -} - -void twi_begin_transmission(uint8_t address) -{ - // indicate that we are transmitting - transmitting = 1; - // set address of targeted slave - txAddress = address; - // reset tx buffer iterator vars - txBufferIndex = 0; - txBufferLength = 0; -} - -uint8_t twi_end_transmission(void) -{ - // transmit buffer (blocking) - int8_t ret = twi_writeTo(txAddress, txBuffer, txBufferLength, 1); - // reset tx buffer iterator vars - txBufferIndex = 0; - txBufferLength = 0; - // indicate that we are done transmitting - transmitting = 0; - return ret; -} - -// must be called in: -// slave tx event callback -// or after beginTransmission(address) -void twi_send_byte(uint8_t data) -{ - if(transmitting){ - // in master transmitter mode - // don't bother if buffer is full - if(txBufferLength >= BUFFER_LENGTH){ - return; - } - // put byte in tx buffer - txBuffer[txBufferIndex] = data; - ++txBufferIndex; - // update amount in buffer - txBufferLength = txBufferIndex; - }else{ - // in slave send mode - // reply to master - twi_transmit(&data, 1); - } -} - -// must be called in: -// slave tx event callback -// or after beginTransmission(address) -void twi_send(uint8_t* data, uint8_t quantity) -{ - if(transmitting){ - // in master transmitter mode - for(uint8_t i = 0; i < quantity; ++i){ - twi_send_byte(data[i]); - } - }else{ - // in slave send mode - // reply to master - twi_transmit(data, quantity); - } -} - -// must be called in: -// slave tx event callback -// or after beginTransmission(address) -void twi_send_char(char* data) -{ - twi_send((uint8_t*)data, strlen(data)); -} - -// must be called in: -// slave rx event callback -// or after requestFrom(address, numBytes) -uint8_t twi_available(void) -{ - return rxBufferLength - rxBufferIndex; -} - -// must be called in: -// slave rx event callback -// or after requestFrom(address, numBytes) -uint8_t twi_receive(void) -{ - // default to returning null char - // for people using with char strings - uint8_t value = '\0'; - - // get each successive byte on each call - if(rxBufferIndex < rxBufferLength){ - value = rxBuffer[rxBufferIndex]; - ++rxBufferIndex; - } - - return value; -} - -// behind the scenes function that is called when data is received -void onReceiveService(uint8_t* inBytes, int numBytes) -{ - // don't bother if user hasn't registered a callback - if(!user_onReceive){ - return; - } - // don't bother if rx buffer is in use by a master requestFrom() op - // i know this drops data, but it allows for slight stupidity - // meaning, they may not have read all the master requestFrom() data yet - if(rxBufferIndex < rxBufferLength){ - return; - } - // copy twi rx buffer into local read buffer - // this enables new reads to happen in parallel - for(uint8_t i = 0; i < numBytes; ++i){ - rxBuffer[i] = inBytes[i]; - } - // set rx iterator vars - rxBufferIndex = 0; - rxBufferLength = numBytes; - // alert user program - user_onReceive(numBytes); -} - -// behind the scenes function that is called when data is requested -void onRequestService(void) -{ - // don't bother if user hasn't registered a callback - if(!user_onRequest){ - return; - } - // reset tx buffer iterator vars - // !!! this will kill any pending pre-master sendTo() activity - txBufferIndex = 0; - txBufferLength = 0; - // alert user program - user_onRequest(); -} - -// sets function called on slave write -void twi_set_on_receive( void (*function)(int) ) -{ - user_onReceive = function; -} - -// sets function called on slave read -void twi_set_on_request( void (*function)(void) ) -{ - user_onRequest = function; -} - diff --git a/twi.h b/twi.h deleted file mode 100644 index 87e126d..0000000 --- a/twi.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - TwoWire.h - TWI/I2C library for Arduino & Wiring - Copyright (c) 2006 Nicholas Zambetti. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef TwoWire_h -#define TwoWire_h - -#include - -#define BUFFER_LENGTH 32 - -void twi_init_master(void); -void twi_init_slave(uint8_t); -void twi_begin_transmission(uint8_t); -uint8_t twi_end_transmission(void); -uint8_t twi_request_from(uint8_t, uint8_t); -void twi_send_byte(uint8_t); -void twi_send(uint8_t*, uint8_t); -void twi_send_char(char*); -uint8_t twi_available(void); -uint8_t twi_receive(void); -void twi_set_on_receive( void (*)(int) ); -void twi_set_on_request( void (*)(void) ); - -#endif