├── extras └── tests │ ├── baseline │ ├── mockup.h │ ├── mockup.cpp │ └── baseline.ino │ ├── results.txt │ ├── hardi2c │ └── hardi2c.ino │ ├── wire │ └── wire.ino │ ├── usiwire │ └── usiwire.ino │ ├── slowsoft │ ├── slowsoft.ino │ ├── SlowSoftI2CMaster.h │ └── SlowSoftI2CMaster.cpp │ ├── tinywire │ └── tinywire.ino │ ├── slowwire │ └── slowwire.ino │ ├── softi2cpt │ └── softi2cpt.ino │ ├── softwire │ └── softwire.ino │ └── softi2c │ └── softi2c.ino ├── keywords.txt ├── library.properties ├── library.json ├── examples ├── simpleSoftWire │ └── simpleSoftWire.ino ├── simpleSoftI2C │ └── simpleSoftI2C.ino ├── stretchTest │ └── stretchTest.ino ├── EepromFill │ ├── sendfiles.pl │ └── EepromFill.ino ├── MLX90614Soft │ └── MLX90614Soft.ino ├── BMA020SoftWire │ └── BMA020SoftWire.ino ├── I2CScanSoftI2C │ └── I2CScanSoftI2C.ino ├── TSL2561Soft │ ├── TSL2561Soft.h │ └── TSL2561Soft.ino ├── I2CScanSoftWire │ └── I2CScanSoftWire.ino ├── BMA020SoftI2C │ └── BMA020SoftI2C.ino ├── I2CShell │ ├── README.md │ └── I2CShell.ino ├── Eeprom24AA1025SoftWire │ └── Eeprom24AA1025SoftWire.ino └── Eeprom24AA1025SoftI2C │ └── Eeprom24AA1025SoftI2C.ino ├── .github └── workflows │ └── LibraryBuild.yml ├── src ├── SoftWire.h └── SoftI2CMaster.h ├── README.md └── LICENSE.txt /extras/tests/baseline/mockup.h: -------------------------------------------------------------------------------- 1 | #define I2C_WRITE 0 2 | #define I2C_READ 1 3 | 4 | using namespace std; 5 | 6 | bool i2c_init(void); 7 | bool i2c_start(uint8_t addr); 8 | bool i2c_start_wait(uint8_t addr); 9 | bool i2c_rep_start(uint8_t addr); 10 | bool i2c_write(uint8_t data); 11 | byte i2c_read(bool last); 12 | void i2c_stop(); 13 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | SoftWire KEYWORD1 2 | begin KEYWORD2 3 | end KEYWORD2 4 | setClock KEYWORD2 5 | beginTransmission KEYWORD2 6 | endTransmission KEYWORD2 7 | write KEYWORD2 8 | requestFrom KEYWORD2 9 | available KEYWORD2 10 | read KEYWORD2 11 | peek KEYWORD2 12 | 13 | i2c_init KEYWORD2 14 | i2c_start KEYWORD2 15 | i2c_start_wait KEYWORD2 16 | i2c_rep_start KEYWORD2 17 | i2c_stop KEYWORD2 18 | i2c_write KEYWORD2 19 | i2c_read KEYWORD2 20 | 21 | I2C_READ LITERAL1 22 | I2C_WRITE LITERAL1 23 | -------------------------------------------------------------------------------- /extras/tests/baseline/mockup.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "mockup.h" 4 | 5 | bool i2c_init(void) 6 | { 7 | return true; 8 | } 9 | 10 | bool i2c_start(uint8_t addr) 11 | { 12 | return true; 13 | } 14 | 15 | bool i2c_start_wait(uint8_t addr) 16 | { 17 | return true; 18 | } 19 | 20 | bool i2c_rep_start(uint8_t addr) 21 | { 22 | return true; 23 | } 24 | 25 | bool i2c_write(uint8_t data) 26 | { 27 | return true; 28 | } 29 | 30 | byte i2c_read(bool last) 31 | { 32 | return 0xA1; 33 | } 34 | 35 | void i2c_stop() 36 | { 37 | } 38 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=SoftI2CMaster 2 | version=2.1.9 3 | author=Bernhard Nebel, Peter Fleury 4 | maintainer=Bernhard Nebel 5 | sentence=I2C lib that supports bit banging and hardware support 6 | paragraph=Tiny and lightweight I2C library for master mode only. It features no RAM usage compared to Arduino Wire (210 bytes) and only 500 bytes programming size compared to around 2000 for Wire. Even bit banging mode runs up to 370 kHz I2C clock frequency on a 16 MHz Arduino. 7 | category=Communication 8 | url=https://github.com/felias-fogg/SoftI2CMaster 9 | architectures=avr 10 | depends= 11 | -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "SoftI2CMaster", 3 | "version": "2.1.9", 4 | "keywords": "i2c", 5 | "description": "Software I2C Arduino library", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/felias-fogg/SoftI2CMaster.git" 9 | }, 10 | "authors": [ 11 | { 12 | "name": "Bernhard Nebel", 13 | "url": "http://hinterm-ziel.de/", 14 | "maintainer": true 15 | }, 16 | { 17 | "name": "Peter Fleury", 18 | "url": "http://www.peterfleury.epizy.com/" 19 | } 20 | ], 21 | "frameworks": "arduino", 22 | "platforms": "Atmel AVR" 23 | } 24 | -------------------------------------------------------------------------------- /extras/tests/results.txt: -------------------------------------------------------------------------------- 1 | Memory consumption 2 | baseline is the test program using a library with empty function bodys. 3 | 4 | ATmega328 ATmega256 ATtiny85 ATtiny84 5 | baseline 1022+9 1540+9 756+9 772+9 6 | softi2c 1504+9 +482 1988+9 +448 1184+9 +428 1200+9 +428 7 | softi2cpt 1586+9 (+82) 2068+9 (+80) 1266+9 (+82) 1282+9 (+82) 8 | hardi2c 1456+9 +434 1934+9 +394 ------ ----- 9 | softwire 2088+75 +1066 2560+75 1758+75 +1002 1774+75 10 | slowsoft 1996+13 +974 2408+13 1488+13 +732 1504+13 11 | slowwire 2578+79 +1556 2986+79 2048+79 +1292 2100+79 12 | usiwire ------- ------ 1864+54 +1108 1958+54 13 | tinywire ------- ------ 2590+95 +1834 ------- 14 | wire 2814+219 +1972 3304+219 ------- ------- 15 | -------------------------------------------------------------------------------- /examples/simpleSoftWire/simpleSoftWire.ino: -------------------------------------------------------------------------------- 1 | // -*- c++ -*- 2 | // Simple sketch to read out one register of an I2C device 3 | 4 | #define I2C_TIMEOUT 1000 5 | #define I2C_PULLUP 1 6 | 7 | #ifdef __AVR_ATmega328P__ 8 | /* Corresponds to A4/A5 - the hardware I2C pins on Arduinos */ 9 | #define SDA_PORT PORTC 10 | #define SDA_PIN 4 11 | #define SCL_PORT PORTC 12 | #define SCL_PIN 5 13 | #define I2C_FASTMODE 1 14 | #else 15 | #define SDA_PORT PORTB 16 | #define SDA_PIN 0 17 | #define SCL_PORT PORTB 18 | #define SCL_PIN 2 19 | #define I2C_FASTMODE 1 20 | #endif 21 | 22 | #include 23 | 24 | #define I2C_7BITADDR 0x68 // DS1307 25 | #define MEMLOC 0x0A 26 | #define ADDRLEN 1 27 | 28 | void setup(void) { 29 | Serial.begin(57600); 30 | Wire.begin(); 31 | } 32 | 33 | void loop(void){ 34 | Wire.beginTransmission(I2C_7BITADDR); 35 | for (byte i=1; i 22 | 23 | #define I2C_7BITADDR 0x68 // DS1307 24 | #define MEMLOC 0x0A 25 | #define ADDRLEN 1 // address length, usually 1 or 2 bytes 26 | 27 | void setup(void) { 28 | Serial.begin(115200); 29 | Serial.println(F("START " __FILE__ " from " __DATE__)); 30 | 31 | if (!i2c_init()) { 32 | Serial.println("I2C init failed"); 33 | } 34 | } 35 | 36 | void loop(void) { 37 | if (!i2c_start_wait((I2C_7BITADDR << 1) | I2C_WRITE)) { 38 | Serial.println("I2C device busy"); 39 | delay(1000); 40 | return; 41 | } 42 | for (byte i = 1; i < ADDRLEN; i++) { 43 | i2c_write(0x00); 44 | } 45 | i2c_write(MEMLOC); 46 | i2c_rep_start((I2C_7BITADDR << 1) | I2C_READ); 47 | byte val = i2c_read(true); 48 | i2c_stop(); 49 | Serial.println(val); 50 | delay(1000); 51 | } 52 | -------------------------------------------------------------------------------- /examples/stretchTest/stretchTest.ino: -------------------------------------------------------------------------------- 1 | // This is a short sketch that stretches the low pulse on an I2C bus 2 | // in order to test the timeout feature. 3 | // Put any Arduino and I2C device, e.g. a memory chip, as usual on a breadboard, 4 | // then use another Arduino and flash this program into it. Connect the 5 | // pin 5 (of PORTD) with the SCL line and verify on the scope that the 6 | // low period is indeed stretched. 7 | 8 | #include 9 | 10 | #define SCL_PORT PORTD 11 | #define SCL_PIN 5 12 | 13 | #define DELAY 8 // strech SCL low for that many milli seconds 14 | 15 | #define SCL_DDR (_SFR_IO_ADDR(SCL_PORT) - 1) 16 | #define SCL_OUT _SFR_IO_ADDR(SCL_PORT) 17 | #define SCL_IN (_SFR_IO_ADDR(SCL_PORT) - 2) 18 | 19 | void initScl(void) { 20 | asm volatile 21 | (" cbi %[SCLDDR],%[SCLPIN] ;release SCL \n\t" 22 | " cbi %[SCLOUT],%[SCLPIN] ;clear SCL output value \n\t" 23 | :: [SCLDDR] "I" (SCL_DDR), [SCLPIN] "I" (SCL_PIN), [SCLOUT] "I" (SCL_OUT)); 24 | } 25 | 26 | void grabScl(void) { 27 | asm volatile 28 | ("_L_wait: \n\t" 29 | " sbic %[SCLIN],%[SCLPIN] \n\t" 30 | " rjmp _L_wait \n\t" 31 | " sbi %[SCLDDR],%[SCLPIN]" 32 | ::[SCLDDR] "I" (SCL_DDR), [SCLPIN] "I" (SCL_PIN), [SCLIN] "I" (SCL_IN)); 33 | } 34 | 35 | void releaseScl(void) { 36 | asm volatile 37 | (" cbi %[SCLDDR],%[SCLPIN] \n\t" 38 | :: [SCLDDR] "I" (SCL_DDR), [SCLPIN] "I" (SCL_PIN)); 39 | } 40 | 41 | void setup(void) 42 | { 43 | Serial.begin(19200); 44 | Serial.println("Intializing ..."); 45 | initScl(); 46 | } 47 | 48 | void loop(void) { 49 | grabScl(); 50 | delay(DELAY); 51 | releaseScl(); 52 | } 53 | -------------------------------------------------------------------------------- /extras/tests/baseline/baseline.ino: -------------------------------------------------------------------------------- 1 | // -*- c++ -*- 2 | /* Write MEMLEN bytes of EEPROM and then read it back. 3 | * If successful, light a LED with slow blinks, otherwise blink very hecticly. 4 | * The baseline uses almost empty functions, the other 5 | * implementations are measured against it 6 | */ 7 | 8 | #define MEMADDR7B 0x57 // 7-bit addr of memory chip 9 | #define ADDRLEN 2 // length of internal mem addr 10 | #define MEMLEN 10 // the number of bytes to be written and to be read 11 | #define LEDPIN 13 // LEd to report result 12 | 13 | #include "mockup.h" 14 | 15 | void setup() { 16 | pinMode(LEDPIN, OUTPUT); 17 | digitalWrite(LEDPIN, HIGH); 18 | delay(1000); 19 | digitalWrite(LEDPIN, LOW); 20 | delay(1000); 21 | if (!i2c_init()) error(); 22 | } 23 | 24 | void loop() { 25 | byte i; 26 | if (!i2c_start(MEMADDR7B<<1 | I2C_WRITE)) error(); 27 | for (i=0; i < ADDRLEN; i++) 28 | if (!i2c_write(0)) error(); 29 | for (i=0; i 15 | 16 | void setup() { 17 | pinMode(LEDPIN, OUTPUT); 18 | digitalWrite(LEDPIN, HIGH); 19 | delay(1000); 20 | digitalWrite(LEDPIN, LOW); 21 | delay(1000); 22 | if (!i2c_init()) error(); 23 | } 24 | 25 | void loop() { 26 | byte i; 27 | if (!i2c_start(MEMADDR7B<<1 | I2C_WRITE)) error(); 28 | for (i=0; i < ADDRLEN; i++) 29 | if (!i2c_write(0)) error(); 30 | for (i=0; i 15 | 16 | void setup() { 17 | pinMode(LEDPIN, OUTPUT); 18 | digitalWrite(LEDPIN, HIGH); 19 | delay(1000); 20 | digitalWrite(LEDPIN, LOW); 21 | delay(1000); 22 | Wire.begin(); 23 | } 24 | 25 | void loop() { 26 | byte i; 27 | // writing 10 bytes 28 | Wire.beginTransmission(MEMADDR7B); 29 | for (i=0; i < ADDRLEN; i++) 30 | Wire.write(0); 31 | for (i=0; i 15 | 16 | void setup() { 17 | pinMode(LEDPIN, OUTPUT); 18 | digitalWrite(LEDPIN, HIGH); 19 | delay(1000); 20 | digitalWrite(LEDPIN, LOW); 21 | delay(1000); 22 | Wire.begin(); 23 | } 24 | 25 | void loop() { 26 | byte i; 27 | // writing 10 bytes 28 | Wire.beginTransmission(MEMADDR7B); 29 | for (i=0; i < ADDRLEN; i++) 30 | Wire.write(0); 31 | for (i=0; inew("/dev/tty.usbserial-A900ccgj"); 5 | 6 | sub readFile { 7 | my($name) = @_; 8 | my($buffer); 9 | my(@outbuf) = (); 10 | open(INFILE,"<",$name) or die "Cannot open $name\n"; 11 | binmode(INFILE); 12 | while(read(INFILE,$buffer,256000) != 0) { 13 | push(@outbuf,split(//,$buffer)); 14 | } 15 | close(INFILE); 16 | return @outbuf; 17 | } 18 | 19 | $| = 1; 20 | $port->baudrate(19200); 21 | $port->databits(8); 22 | $port->parity("none"); 23 | $port->stopbits(1); 24 | 25 | # wait for 3 X's 26 | $port->are_match("XXX"); 27 | while (1) { 28 | my $c = $port->lookfor(); 29 | last if ($c ne ""); 30 | } 31 | 32 | while (@ARGV) { 33 | my $nextfile = shift(@ARGV); 34 | my @buf = readFile($nextfile); 35 | my $len = @buf; 36 | print "Sending $nextfile, $len bytes ...\n"; 37 | my $counter = 0; 38 | while (@buf) { 39 | my $byte = ord(shift(@buf)); 40 | my $hexstr = sprintf("%02X\n",$byte); 41 | $port->write("$hexstr"); 42 | $counter++; 43 | if ($counter%256 == 0) { 44 | $port->are_match("PAGE"); 45 | while (1) { 46 | my $p = $port->lookfor(); 47 | last if ($p ne ""); 48 | } 49 | print "."; 50 | } 51 | # print "$hexstr"; 52 | } 53 | $port->write("XX\n"); 54 | print "... $nextfile sent\n"; 55 | my $timo = time()+3; 56 | $port->are_match("ZZZ"); 57 | while (time() < $timo) { 58 | my $c = $port->lookfor(); 59 | next if $c eq ""; 60 | print "ACK received\n"; 61 | last; 62 | } 63 | if (time() >= $timo) { die("no ACK for $nextfile") }; 64 | } 65 | $port->write(" ZZ\n"); 66 | print "wait to write table\n"; 67 | sleep 3; 68 | print "DONE\n"; 69 | 70 | -------------------------------------------------------------------------------- /extras/tests/slowsoft/SlowSoftI2CMaster.h: -------------------------------------------------------------------------------- 1 | /* Arduino Slow Software I2C Master 2 | Copyright (c) 2017 Bernhard Nebel. 3 | 4 | This library is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU Lesser General Public 6 | License as published by the Free Software Foundation; either 7 | version 3 of the License, or (at your option) any later version. 8 | 9 | This library is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this library; if not, write to the Free Software 16 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 17 | */ 18 | 19 | #ifndef SLOW_SOFT_I2C_MASTER_H 20 | #define SLOW_SOFT_I2C_MASTER_H 21 | 22 | #include 23 | #include 24 | 25 | #define I2C_READ 1 26 | #define I2C_WRITE 0 27 | #define DELAY 4 // usec delay 28 | #define BUFFER_LENGTH 32 29 | #define I2C_MAXWAIT 5000 30 | 31 | class SlowSoftI2CMaster { 32 | public: 33 | SlowSoftI2CMaster(uint8_t sda, uint8_t scl); 34 | SlowSoftI2CMaster(uint8_t sda, uint8_t scl, bool internal_pullup); 35 | bool i2c_init(void); 36 | bool i2c_start(uint8_t addr); 37 | bool i2c_start_wait(uint8_t addr); 38 | bool i2c_rep_start(uint8_t addr); 39 | void i2c_stop(void); 40 | bool i2c_write(uint8_t value); 41 | uint8_t i2c_read(bool last); 42 | bool error; 43 | 44 | private: 45 | void setHigh(uint8_t pin); 46 | void setLow(uint8_t pin); 47 | uint8_t _sda; 48 | uint8_t _scl; 49 | bool _pullup; 50 | }; 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /extras/tests/tinywire/tinywire.ino: -------------------------------------------------------------------------------- 1 | // -*- c++ -*- 2 | /* Write MEMLEN bytes of EEPROM and then read it back. 3 | * If successful, light a LED with slow blinks, otherwise blink very hecticly. 4 | * The baseline uses almost empty functions, the other 5 | * implementations are measured against it 6 | */ 7 | 8 | #define MEMADDR7B 0x57 // 7-bit addr of memory chip 9 | #define DATA 0xA1 // can be changed 10 | #define ADDRLEN 2 // length of internal mem addr 11 | #define MEMLEN 10 // the number of bytes to be written and to be read 12 | #define LEDPIN 1 // LEd to report result 13 | 14 | #include 15 | 16 | void setup() { 17 | pinMode(LEDPIN, OUTPUT); 18 | digitalWrite(LEDPIN, HIGH); 19 | delay(1000); 20 | digitalWrite(LEDPIN, LOW); 21 | delay(1000); 22 | TinyWire.begin(); 23 | } 24 | 25 | void loop() { 26 | byte i; 27 | // writing 10 bytes 28 | TinyWire.beginTransmission(MEMADDR7B); 29 | for (i=0; i < ADDRLEN; i++) 30 | TinyWire.send(0); 31 | for (i=0; i 15 | 16 | SlowSoftWire Wire = SlowSoftWire(4, 5); 17 | 18 | void setup() { 19 | pinMode(LEDPIN, OUTPUT); 20 | digitalWrite(LEDPIN, HIGH); 21 | delay(1000); 22 | digitalWrite(LEDPIN, LOW); 23 | delay(1000); 24 | Wire.begin(); 25 | } 26 | 27 | void loop() { 28 | byte i; 29 | // writing 10 bytes 30 | Wire.beginTransmission(MEMADDR7B); 31 | for (i=0; i < ADDRLEN; i++) 32 | Wire.write(0); 33 | for (i=0; i 21 | 22 | void setup() { 23 | pinMode(LEDPIN, OUTPUT); 24 | digitalWrite(LEDPIN, HIGH); 25 | delay(1000); 26 | digitalWrite(LEDPIN, LOW); 27 | delay(1000); 28 | if (!i2c_init()) error(); 29 | } 30 | 31 | void loop() { 32 | byte i; 33 | if (!i2c_start(MEMADDR7B<<1 | I2C_WRITE)) error(); 34 | for (i=0; i < ADDRLEN; i++) 35 | if (!i2c_write(0)) error(); 36 | for (i=0; i 19 | 20 | void setup() { 21 | pinMode(LEDPIN, OUTPUT); 22 | digitalWrite(LEDPIN, HIGH); 23 | delay(1000); 24 | digitalWrite(LEDPIN, LOW); 25 | delay(1000); 26 | Wire.begin(); 27 | } 28 | 29 | void loop() { 30 | byte i; 31 | // writing 10 bytes 32 | Wire.beginTransmission(MEMADDR7B); 33 | for (i=0; i < ADDRLEN; i++) 34 | Wire.write(0); 35 | for (i=0; i 29 | 30 | void setup() { 31 | pinMode(LEDPIN, OUTPUT); 32 | digitalWrite(LEDPIN, HIGH); 33 | delay(1000); 34 | digitalWrite(LEDPIN, LOW); 35 | delay(1000); 36 | if (!i2c_init()) error(); 37 | } 38 | 39 | void loop() { 40 | byte i; 41 | if (!i2c_start(MEMADDR7B<<1 | I2C_WRITE)) error(); 42 | for (i=0; i < ADDRLEN; i++) 43 | if (!i2c_write(0)) error(); 44 | for (i=0; i 4 | #ifdef __AVR_ATmega328P__ 5 | /* Corresponds to A4/A5 - the hardware I2C pins on Arduinos */ 6 | #define SDA_PORT PORTC 7 | #define SDA_PIN 4 8 | #define SCL_PORT PORTC 9 | #define SCL_PIN 5 10 | #define I2C_FASTMODE 1 11 | #else 12 | #define SDA_PORT PORTB 13 | #define SDA_PIN 0 14 | #define SCL_PORT PORTB 15 | #define SCL_PIN 2 16 | #define I2C_FASTMODE 1 17 | #endif 18 | 19 | #include 20 | 21 | void setup(){ 22 | #if (__AVR_ARCH__ == 5) // means ATMEGA 23 | Serial.begin(19200); 24 | Serial.println("Setup..."); 25 | #endif 26 | i2c_init(); 27 | } 28 | 29 | void loop(){ 30 | int dev = 0x5A<<1; 31 | int data_low = 0; 32 | int data_high = 0; 33 | int pec = 0; 34 | 35 | i2c_start(dev+I2C_WRITE); 36 | i2c_write(0x07); 37 | // read 38 | i2c_rep_start(dev+I2C_READ); 39 | data_low = i2c_read(false); //Read 1 byte and then send ack 40 | data_high = i2c_read(false); //Read 1 byte and then send ack 41 | pec = i2c_read(true); 42 | i2c_stop(); 43 | 44 | //This converts high and low bytes together and processes temperature, MSB is a error bit and is ignored for temps 45 | double tempFactor = 0.02; // 0.02 degrees per LSB (measurement resolution of the MLX90614) 46 | double tempData = 0x0000; // zero out the data 47 | int frac; // data past the decimal point 48 | 49 | // This masks off the error bit of the high byte, then moves it left 8 bits and adds the low byte. 50 | tempData = (double)(((data_high & 0x007F) << 8) + data_low); 51 | tempData = (tempData * tempFactor)-0.01; 52 | 53 | float celcius = tempData - 273.15; 54 | float fahrenheit = (celcius*1.8) + 32; 55 | 56 | #if (__AVR_ARCH__ == 5) // means ATMEGA 57 | Serial.print("Celcius: "); 58 | Serial.println(celcius); 59 | 60 | Serial.print("Fahrenheit: "); 61 | Serial.println(fahrenheit); 62 | #endif 63 | 64 | delay(1000); // wait a second before printing again 65 | } 66 | -------------------------------------------------------------------------------- /examples/BMA020SoftWire/BMA020SoftWire.ino: -------------------------------------------------------------------------------- 1 | // -*- c++ -*- 2 | // Simple sketch to read out BMA020 using SoftWire 3 | 4 | // Readout BMA020 chip 5 | 6 | #ifdef __AVR_ATmega328P__ 7 | /* Corresponds to A4/A5 - the hardware I2C pins on Arduinos */ 8 | #define SDA_PORT PORTC 9 | #define SDA_PIN 4 10 | #define SCL_PORT PORTC 11 | #define SCL_PIN 5 12 | #define I2C_FASTMODE 1 13 | #else 14 | #define SDA_PORT PORTB 15 | #define SDA_PIN 0 16 | #define SCL_PORT PORTB 17 | #define SCL_PIN 2 18 | #define I2C_FASTMODE 1 19 | #endif 20 | 21 | #define I2C_TIMEOUT 100 22 | //#define I2C_FASTMODE 1 23 | 24 | #include 25 | #include 26 | 27 | 28 | #define BMAADDR 0x38 29 | 30 | int xval, yval, zval; 31 | 32 | 33 | boolean setControlBits(uint8_t cntr) 34 | { 35 | Wire.beginTransmission(BMAADDR); 36 | Wire.write(0x0A); 37 | Wire.write(cntr); 38 | return (Wire.endTransmission() == 0); 39 | } 40 | 41 | boolean initBma(void) 42 | { 43 | if (!setControlBits(B00000010)) return false; 44 | delay(100); 45 | return true; 46 | } 47 | 48 | int readOneVal(void) 49 | { 50 | uint8_t msb, lsb; 51 | lsb = Wire.read(); 52 | msb = Wire.read(); 53 | return (int)((msb<<8)|lsb)/64; 54 | } 55 | 56 | boolean readBma(void) 57 | { 58 | xval = 0xFFFF; 59 | yval = 0xFFFF; 60 | zval = 0xFFFF; 61 | Wire.beginTransmission(BMAADDR); 62 | Wire.write(0x02); 63 | if (Wire.endTransmission(false) != 0) return false; 64 | Wire.requestFrom(BMAADDR, 6, true); 65 | xval = readOneVal(); 66 | yval = readOneVal(); 67 | zval = readOneVal(); 68 | return true; 69 | } 70 | 71 | 72 | 73 | //------------------------------------------------------------------------------ 74 | void setup(void) { 75 | Serial.begin(19200); 76 | Wire.begin(); 77 | if (!initBma()) { 78 | Serial.println(F("INIT ERROR")); 79 | while (1); 80 | } 81 | 82 | } 83 | 84 | void loop(void){ 85 | if (!readBma()) { 86 | Serial.println(F("READ ERROR")); 87 | while (1); 88 | } 89 | Serial.print(F("X=")); 90 | Serial.print(xval); 91 | Serial.print(F(" Y=")); 92 | Serial.print(yval); 93 | Serial.print(F(" Z=")); 94 | Serial.println(zval); 95 | delay(300); 96 | } 97 | -------------------------------------------------------------------------------- /examples/I2CScanSoftI2C/I2CScanSoftI2C.ino: -------------------------------------------------------------------------------- 1 | // -*-c++-*- 2 | // Scan I2C bus for device responses 3 | 4 | 5 | #define I2C_TIMEOUT 0 6 | #define I2C_NOINTERRUPT 0 7 | #define I2C_FASTMODE 0 8 | #define FAC 1 9 | #define I2C_CPUFREQ (F_CPU/FAC) 10 | 11 | /* Adjust to your own liking */ 12 | #ifdef __AVR_ATmega328P__ 13 | /* Corresponds to A4/A5 - the hardware I2C pins on Arduinos */ 14 | #define SDA_PORT PORTC 15 | #define SDA_PIN 4 16 | #define SCL_PORT PORTC 17 | #define SCL_PIN 5 18 | #define I2C_FASTMODE 1 19 | #else 20 | #define SDA_PORT PORTB 21 | #define SDA_PIN 0 22 | #define SCL_PORT PORTB 23 | #define SCL_PIN 2 24 | #define I2C_FASTMODE 1 25 | #endif 26 | #define I2C_FASTMODE 0 27 | 28 | 29 | #include 30 | #include 31 | 32 | //------------------------------------------------------------------------------ 33 | void CPUSlowDown(int fac) { 34 | // slow down processor by a fac 35 | CLKPR = _BV(CLKPCE); 36 | CLKPR = _BV(CLKPS1) | _BV(CLKPS0); 37 | } 38 | 39 | 40 | 41 | void setup(void) { 42 | #if FAC != 1 43 | CPUSlowDown(FAC); 44 | #endif 45 | 46 | Serial.begin(57600); // change baudrate to 2400 on terminal when low CPU freq! 47 | Serial.println(F("Intializing ...")); 48 | Serial.print("I2C delay counter: "); 49 | Serial.println(I2C_DELAY_COUNTER); 50 | if (!i2c_init()) 51 | Serial.println(F("Initialization error. SDA or SCL are low")); 52 | else 53 | Serial.println(F("...done")); 54 | } 55 | 56 | void loop(void) 57 | { 58 | uint8_t add = 0; 59 | int found = false; 60 | Serial.println("Scanning ..."); 61 | 62 | Serial.println(" 8-bit 7-bit addr"); 63 | // try read 64 | do { 65 | delay(100); 66 | if (i2c_start(add | I2C_READ)) { 67 | found = true; 68 | i2c_read(true); 69 | i2c_stop(); 70 | Serial.print("Read: 0x"); 71 | if (add < 0x0F) Serial.print(0, HEX); 72 | Serial.print(add+I2C_READ, HEX); 73 | Serial.print(" 0x"); 74 | if (add>>1 < 0x0F) Serial.print(0, HEX); 75 | Serial.println(add>>1, HEX); 76 | } else i2c_stop(); 77 | add += 2; 78 | } while (add); 79 | 80 | // try write 81 | add = 0; 82 | do { 83 | if (i2c_start(add | I2C_WRITE)) { 84 | found = true; 85 | i2c_stop(); 86 | Serial.print("Write: 0x"); 87 | if (add < 0x0F) Serial.print(0, HEX); 88 | Serial.print(add+I2C_WRITE, HEX); 89 | Serial.print(" 0x"); 90 | if (add>>1 < 0x0F) Serial.print(0, HEX); 91 | Serial.println(add>>1, HEX); 92 | } else i2c_stop(); 93 | i2c_stop(); 94 | add += 2; 95 | } while (add); 96 | if (!found) Serial.println(F("No I2C device found.")); 97 | Serial.println("Done\n\n"); 98 | delay(1000/FAC); 99 | } 100 | -------------------------------------------------------------------------------- /examples/TSL2561Soft/TSL2561Soft.h: -------------------------------------------------------------------------------- 1 | #ifndef _TSL2561_H_ 2 | #define _TSL2561_H_ 3 | 4 | #define TSL2561_VISIBLE 2 // channel 0 - channel 1 5 | #define TSL2561_INFRARED 1 // channel 1 6 | #define TSL2561_FULLSPECTRUM 0 // channel 0 7 | 8 | #define TSL2561_LUX_LUXSCALE (14) // Scale by 2^14 9 | #define TSL2561_LUX_RATIOSCALE (9) // Scale ratio by 2^9 10 | #define TSL2561_LUX_CHSCALE (10) // Scale channel values by 2^10 11 | #define TSL2561_LUX_CHSCALE_TINT0 (0x7517) // 322/11 * 2^TSL2561_LUX_CHSCALE 12 | #define TSL2561_LUX_CHSCALE_TINT1 (0x0FE7) // 322/81 * 2^TSL2561_LUX_CHSCALE 13 | 14 | // T, FN and CL package values 15 | #define TSL2561_LUX_K1T (0x0040) // 0.125 * 2^RATIO_SCALE 16 | #define TSL2561_LUX_B1T (0x01f2) // 0.0304 * 2^LUX_SCALE 17 | #define TSL2561_LUX_M1T (0x01be) // 0.0272 * 2^LUX_SCALE 18 | #define TSL2561_LUX_K2T (0x0080) // 0.250 * 2^RATIO_SCALE 19 | #define TSL2561_LUX_B2T (0x0214) // 0.0325 * 2^LUX_SCALE 20 | #define TSL2561_LUX_M2T (0x02d1) // 0.0440 * 2^LUX_SCALE 21 | #define TSL2561_LUX_K3T (0x00c0) // 0.375 * 2^RATIO_SCALE 22 | #define TSL2561_LUX_B3T (0x023f) // 0.0351 * 2^LUX_SCALE 23 | #define TSL2561_LUX_M3T (0x037b) // 0.0544 * 2^LUX_SCALE 24 | #define TSL2561_LUX_K4T (0x0100) // 0.50 * 2^RATIO_SCALE 25 | #define TSL2561_LUX_B4T (0x0270) // 0.0381 * 2^LUX_SCALE 26 | #define TSL2561_LUX_M4T (0x03fe) // 0.0624 * 2^LUX_SCALE 27 | #define TSL2561_LUX_K5T (0x0138) // 0.61 * 2^RATIO_SCALE 28 | #define TSL2561_LUX_B5T (0x016f) // 0.0224 * 2^LUX_SCALE 29 | #define TSL2561_LUX_M5T (0x01fc) // 0.0310 * 2^LUX_SCALE 30 | #define TSL2561_LUX_K6T (0x019a) // 0.80 * 2^RATIO_SCALE 31 | #define TSL2561_LUX_B6T (0x00d2) // 0.0128 * 2^LUX_SCALE 32 | #define TSL2561_LUX_M6T (0x00fb) // 0.0153 * 2^LUX_SCALE 33 | #define TSL2561_LUX_K7T (0x029a) // 1.3 * 2^RATIO_SCALE 34 | #define TSL2561_LUX_B7T (0x0018) // 0.00146 * 2^LUX_SCALE 35 | #define TSL2561_LUX_M7T (0x0012) // 0.00112 * 2^LUX_SCALE 36 | #define TSL2561_LUX_K8T (0x029a) // 1.3 * 2^RATIO_SCALE 37 | #define TSL2561_LUX_B8T (0x0000) // 0.000 * 2^LUX_SCALE 38 | #define TSL2561_LUX_M8T (0x0000) // 0.000 * 2^LUX_SCALE 39 | 40 | // Auto-gain thresholds 41 | #define TSL2561_AGC_THI_13MS (4850) // Max value at Ti 13ms = 5047 42 | #define TSL2561_AGC_TLO_13MS (100) 43 | #define TSL2561_AGC_THI_101MS (36000) // Max value at Ti 101ms = 37177 44 | #define TSL2561_AGC_TLO_101MS (200) 45 | #define TSL2561_AGC_THI_402MS (63000) // Max value at Ti 402ms = 65535 46 | #define TSL2561_AGC_TLO_402MS (500) 47 | 48 | // Clipping thresholds 49 | #define TSL2561_CLIPPING_13MS (4900) 50 | #define TSL2561_CLIPPING_101MS (37000) 51 | #define TSL2561_CLIPPING_402MS (65000) 52 | 53 | // Integration time 54 | #define TSL2561_TIME_13MS 0x00 // 13.7ms 55 | #define TSL2561_TIME_101MS 0x01 // 101ms 56 | #define TSL2561_TIME_402MS 0x02 // 402ms 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /examples/I2CScanSoftWire/I2CScanSoftWire.ino: -------------------------------------------------------------------------------- 1 | // -*- c++ -*- 2 | 3 | // -------------------------------------- 4 | // i2c_scanner (using SoftWire and SoftI2CMaster) 5 | // 6 | // Version 1 7 | // This program (or code that looks like it) 8 | // can be found in many places. 9 | // For example on the Arduino.cc forum. 10 | // The original author is not know. 11 | // Version 2, Juni 2012, Using Arduino 1.0.1 12 | // Adapted to be as simple as possible by Arduino.cc user Krodal 13 | // Version 3, Feb 26 2013 14 | // V3 by louarnold 15 | // Version 4, March 3, 2013, Using Arduino 1.0.3 16 | // by Arduino.cc user Krodal. 17 | // Changes by louarnold removed. 18 | // Scanning addresses changed from 0...127 to 1...119, 19 | // according to the i2c scanner by Nick Gammon 20 | // http://www.gammon.com.au/forum/?id=10896 21 | // Version 5, March 28, 2013 22 | // As version 4, but address scans now to 127. 23 | // A sensor seems to use address 120. 24 | // Version 6, November 27, 2015. 25 | // Added waiting for the Leonardo serial communication. 26 | // Version 7, October 1, 2016 27 | // Changed it to use the SoftWire library 28 | // 29 | // This sketch tests the standard 7-bit addresses 30 | // Devices with higher bit address might not be seen properly. 31 | // 32 | 33 | #ifdef __AVR_ATmega328P__ 34 | /* Corresponds to A4/A5 - the hardware I2C pins on Arduinos */ 35 | #define SDA_PORT PORTC 36 | #define SDA_PIN 4 37 | #define SCL_PORT PORTC 38 | #define SCL_PIN 5 39 | #define I2C_FASTMODE 1 40 | #else 41 | #define SDA_PORT PORTB 42 | #define SDA_PIN 0 43 | #define SCL_PORT PORTB 44 | #define SCL_PIN 2 45 | #define I2C_FASTMODE 1 46 | #endif 47 | 48 | #define I2C_TIMEOUT 100 49 | #define I2C_FASTMODE 1 50 | 51 | #include 52 | 53 | void setup() 54 | { 55 | Wire.begin(); 56 | 57 | Serial.begin(2400); 58 | while (!Serial); // Leonardo: wait for serial monitor 59 | Serial.println("\nI2C Scanner"); 60 | } 61 | 62 | 63 | void loop() 64 | { 65 | byte error, address; 66 | int nDevices; 67 | 68 | Serial.println(F("Scanning I2C bus (7-bit addresses) ...")); 69 | 70 | nDevices = 0; 71 | for(address = 1; address < 127; address++ ) 72 | { 73 | // The i2c_scanner uses the return value of 74 | // the Write.endTransmisstion to see if 75 | // a device did acknowledge to the address. 76 | Wire.beginTransmission(address); 77 | error = Wire.endTransmission(); 78 | 79 | if (error == 0) 80 | { 81 | Serial.print(F("I2C device found at address 0x")); 82 | if (address<16) 83 | Serial.print(F("0")); 84 | Serial.print(address,HEX); 85 | Serial.println(F(" !")); 86 | 87 | nDevices++; 88 | } 89 | else if (error==4) 90 | { 91 | Serial.print(F("Unknow error at address 0x")); 92 | if (address<16) 93 | Serial.print("0"); 94 | Serial.println(address,HEX); 95 | } 96 | } 97 | if (nDevices == 0) 98 | Serial.println("No I2C devices found\n"); 99 | else 100 | Serial.println("done\n"); 101 | 102 | delay(5000); // wait 5 seconds for next scan 103 | } 104 | 105 | -------------------------------------------------------------------------------- /examples/BMA020SoftI2C/BMA020SoftI2C.ino: -------------------------------------------------------------------------------- 1 | // -*- c++ -*- 2 | // Simple sketch to read out BMA020 using SoftI2C 3 | 4 | // Readout BMA020 chip 5 | 6 | // use low processor speed (you have to change the baud rate to 2400!) 7 | //#define I2C_CPUFREQ (F_CPU/16) 8 | //#define NO_INTERRUPT 1 9 | //#define I2C_FASTMODE 1 10 | //#define I2C_SLOWMODE 1 11 | //#define I2C_TIMEOUT 1000 12 | #define TERMOUT 1 13 | 14 | #ifdef __AVR_ATmega328P__ 15 | /* Corresponds to A4/A5 - the hardware I2C pins on Arduinos */ 16 | #define SDA_PORT PORTC 17 | #define SDA_PIN 4 18 | #define SCL_PORT PORTC 19 | #define SCL_PIN 5 20 | #define I2C_FASTMODE 1 21 | #else 22 | #define SDA_PORT PORTB 23 | #define SDA_PIN 0 24 | #define SCL_PORT PORTB 25 | #define SCL_PIN 2 26 | #define I2C_FASTMODE 1 27 | #endif 28 | 29 | #include 30 | #include 31 | 32 | 33 | #define BMAADDR 0x70 34 | #define LEDPIN 13 35 | 36 | int xval, yval, zval; 37 | 38 | void CPUSlowDown(int fac) { 39 | // slow down processor by a fac 40 | switch(fac) { 41 | case 2: 42 | CLKPR = _BV(CLKPCE); 43 | CLKPR = _BV(CLKPS0); 44 | break; 45 | case 4: 46 | CLKPR = _BV(CLKPCE); 47 | CLKPR = _BV(CLKPS1); 48 | break; 49 | case 8: 50 | CLKPR = _BV(CLKPCE); 51 | CLKPR = _BV(CLKPS1) | _BV(CLKPS0); 52 | break; 53 | case 16: 54 | CLKPR = _BV(CLKPCE); 55 | CLKPR = _BV(CLKPS2); 56 | break; 57 | } 58 | } 59 | 60 | 61 | boolean setControlBits(uint8_t cntr) 62 | { 63 | #ifdef TERMOUT 64 | Serial.println(F("Soft reset")); 65 | #endif 66 | if (!i2c_start(BMAADDR | I2C_WRITE)) { 67 | return false; 68 | } 69 | if (!i2c_write(0x0A)) { 70 | return false; 71 | } 72 | if (!i2c_write(cntr)) { 73 | return false; 74 | } 75 | i2c_stop(); 76 | return true; 77 | } 78 | 79 | boolean initBma(void) 80 | { 81 | if (!setControlBits(B00000010)) return false;; 82 | delay(100); 83 | return true; 84 | } 85 | 86 | int readOneVal(boolean last) 87 | { 88 | uint8_t msb, lsb; 89 | lsb = i2c_read(false); 90 | msb = i2c_read(last); 91 | if (last) i2c_stop(); 92 | return (int)((msb<<8)|lsb)/64; 93 | } 94 | 95 | boolean readBma(void) 96 | { 97 | xval = 0xFFFF; 98 | yval = 0xFFFF; 99 | zval = 0xFFFF; 100 | if (!i2c_start(BMAADDR | I2C_WRITE)) return false; 101 | if (!i2c_write(0x02)) return false; 102 | if (!i2c_rep_start(BMAADDR | I2C_READ)) return false; 103 | xval = readOneVal(false); 104 | yval = readOneVal(false); 105 | zval = readOneVal(true); 106 | return true; 107 | } 108 | 109 | 110 | 111 | //------------------------------------------------------------------------------ 112 | void setup(void) { 113 | pinMode(LEDPIN, OUTPUT); 114 | digitalWrite(LEDPIN, LOW); 115 | i2c_init(); 116 | #if I2C_CPUFREQ != F_CPU 117 | CPUSlowDown(F_CPU/I2C_CPUFREQ); 118 | #endif 119 | Serial.begin(19200); // in case of CPU slow down, change to baud rate / FAC! 120 | if (!initBma()) { 121 | #ifdef TERMOUT 122 | Serial.println(F("INIT ERROR")); 123 | #else 124 | while (1); 125 | #endif 126 | } 127 | 128 | } 129 | 130 | void loop(void){ 131 | if (!readBma()) { 132 | #ifdef TERMOUT 133 | Serial.println(F("READ ERROR")); 134 | #else 135 | while (1); 136 | #endif 137 | } 138 | #ifdef TERMOUT 139 | Serial.print(F("X=")); 140 | Serial.print(xval); 141 | Serial.print(F(" Y=")); 142 | Serial.print(yval); 143 | Serial.print(F(" Z=")); 144 | Serial.println(zval); 145 | delay(300); 146 | #else 147 | digitalWrite(LEDPIN, HIGH); 148 | delay(500); 149 | digitalWrite(LEDPIN, LOW); 150 | delay(500); 151 | delay(5000); 152 | #endif 153 | } 154 | -------------------------------------------------------------------------------- /.github/workflows/LibraryBuild.yml: -------------------------------------------------------------------------------- 1 | # LibraryBuild.yml 2 | # Github workflow script to test compile all examples of an Arduino library repository. 3 | # 4 | # Copyright (C) 2021 Armin Joachimsmeyer 5 | # https://github.com/ArminJo/Github-Actions 6 | 7 | # This is the name of the workflow, visible on GitHub UI. 8 | name: LibraryBuild 9 | 10 | on: 11 | workflow_dispatch: # To run it manually 12 | push: # see: https://help.github.com/en/actions/reference/events-that-trigger-workflows#pull-request-event-pull_request 13 | paths: 14 | - '**.ino' 15 | - '**.cpp' 16 | - '**.h' 17 | - '**LibraryBuild.yml' 18 | pull_request: 19 | 20 | jobs: 21 | build: 22 | name: ${{ matrix.arduino-boards-fqbn }} - test compiling examples 23 | 24 | runs-on: ubuntu-latest # I picked Ubuntu to use shell scripts. 25 | 26 | strategy: 27 | matrix: 28 | # The matrix will produce one job for each configuration parameter of type `arduino-boards-fqbn` 29 | # In the Arduino IDE, the fqbn is printed in the first line of the verbose output for compilation as parameter -fqbn=... for the "arduino-builder -dump-prefs" command 30 | # 31 | # Examples: arduino:avr:uno, arduino:avr:leonardo, arduino:avr:nano, arduino:avr:mega 32 | # arduino:sam:arduino_due_x, arduino:samd:arduino_zero_native" 33 | # ATTinyCore:avr:attinyx5:chip=85,clock=1internal, digistump:avr:digispark-tiny, digistump:avr:digispark-pro 34 | # STMicroelectronics:stm32:GenF1:pnum=BLUEPILL_F103C8 35 | # esp8266:esp8266:huzzah:eesz=4M3M,xtal=80, esp32:esp32:featheresp32:FlashFreq=80 36 | # You may add a suffix behind the fqbn with "|" to specify one board for e.g. different compile options like arduino:avr:uno|trace 37 | ############################################################################################################# 38 | arduino-boards-fqbn: 39 | - arduino:avr:uno 40 | - arduino:avr:leonardo 41 | - arduino:avr:mega 42 | - digistump:avr:digispark-tiny:clock=clock1 43 | - digistump:avr:digispark-pro 44 | - ATTinyCore:avr:attinyx5:chip=85,clock=1internal 45 | 46 | # Choose the right platform for the boards we want to test. (maybe in the future Arduino will automatically do this for you) 47 | # With sketches-exclude you may exclude specific examples for a board. Use a comma separated list. 48 | ############################################################################################################# 49 | include: 50 | - arduino-boards-fqbn: digistump:avr:digispark-tiny:clock=clock1 # ATtiny85 board @1 MHz 51 | platform-url: https://raw.githubusercontent.com/ArminJo/DigistumpArduino/master/package_digistump_index.json 52 | sketches-exclude: hardi2c,stretchTest,I2CShell,EepromFill 53 | 54 | - arduino-boards-fqbn: digistump:avr:digispark-pro 55 | platform-url: https://raw.githubusercontent.com/ArminJo/DigistumpArduino/master/package_digistump_index.json 56 | sketches-exclude: hardi2c,stretchTest,I2CShell 57 | 58 | - arduino-boards-fqbn: ATTinyCore:avr:attinyx5:chip=85,clock=1internal 59 | platform-url: http://drazzy.com/package_drazzy.com_index.json 60 | sketches-exclude: hardi2c,stretchTest,I2CShell 61 | 62 | # Do not cancel all jobs / architectures if one job fails 63 | fail-fast: false 64 | 65 | steps: 66 | - name: Checkout 67 | uses: actions/checkout@master 68 | 69 | - name: Compile all examples 70 | uses: ArminJo/arduino-test-compile@master 71 | with: 72 | arduino-board-fqbn: ${{ matrix.arduino-boards-fqbn }} 73 | platform-url: ${{ matrix.platform-url }} 74 | sketches-exclude: tinywire,usiwire,slowwire,${{ matrix.sketches-exclude }} 75 | build-properties: ${{ toJson(matrix.build-properties) }} 76 | 77 | -------------------------------------------------------------------------------- /examples/EepromFill/EepromFill.ino: -------------------------------------------------------------------------------- 1 | // Sketch to fill up EEPROM, sent from the Perl script sendfiles.pl 2 | // Sendbytes sends whole files with the size always as the first number 3 | // Receivebytes stores these chunks in EEPROM and stores in the first 4 | // 256 bytes a table of 64 (unsigned long) addresses to these chunks. 5 | 6 | #ifdef __AVR_ATmega328P__ 7 | /* Corresponds to A4/A5 - the hardware I2C pins on Arduinos */ 8 | #define SDA_PORT PORTC 9 | #define SDA_PIN 4 10 | #define SCL_PORT PORTC 11 | #define SCL_PIN 5 12 | #define I2C_FASTMODE 1 13 | #else 14 | #define SDA_PORT PORTB 15 | #define SDA_PIN 0 16 | #define SCL_PORT PORTB 17 | #define SCL_PIN 2 18 | #define I2C_FASTMODE 1 19 | #endif 20 | 21 | #define I2C_FASTMODE 1 22 | // #define I2C_TIMEOUT 10 // timeout after 10 msec 23 | // #define I1C_NOINTERRUPT 1 // no interrupts 24 | // #define I2C_CPUFREQ (F_CPU/8) // slow down CPU frequency 25 | #include 26 | 27 | #define EEPROMADDR 0xA6 // set by jumper (A1=1 and A0=1) 28 | #define MAXADDR 0x1FFFF 29 | 30 | long unsigned startaddrs[64]; 31 | long unsigned addr = 0; 32 | boolean newpage = true; 33 | 34 | boolean writeEEPROM(uint8_t byte) { 35 | if (newpage) { 36 | // issue a start condition, send device address and write direction bit 37 | i2c_start_wait(EEPROMADDR | I2C_WRITE | (addr&0x10000 ? 8 : 0)); 38 | newpage = false; 39 | // send the address 40 | if (!i2c_write((addr>>8)&0xFF)) return false; 41 | if (!i2c_write(addr&0xFF)) return false; 42 | } 43 | // send data to EEPROM 44 | if (!i2c_write(byte)) return false; 45 | addr++; 46 | 47 | if (addr%128 == 0) { 48 | // if add points to new page, save the old one! 49 | finishEEPage(); 50 | } 51 | return true; 52 | } 53 | 54 | void finishEEPage(void) 55 | { 56 | i2c_stop(); 57 | newpage = true; 58 | } 59 | 60 | int convHexDigit(char c) 61 | { 62 | if (c >= '0' && c <= '9') return (c - '0'); 63 | else if (c >= 'A' && c <= 'F') return(c - 'A' + 10); 64 | else return (-99); 65 | } 66 | 67 | int convHex(char c1, char c2) 68 | { 69 | int i1 = convHexDigit(c1); 70 | int i2 = convHexDigit(c2); 71 | if (i1 < 0 || i2 < 0) return -99; 72 | else return (i1*16+i2); 73 | } 74 | 75 | 76 | int readNextByte(void) 77 | { 78 | char c1 = '\0'; 79 | char c2; 80 | while (c1 == '\0') { 81 | while (!Serial.available()) { }; 82 | c1 = Serial.read(); 83 | if (c1 <= ' ') c1 = '\0'; 84 | } 85 | while (!Serial.available()) { }; 86 | c2 = Serial.read(); 87 | if (c1 == 'X' && c2 == 'X') return -1; 88 | if (c1 == 'Z' && c2 == 'Z') return -2; 89 | 90 | return convHex(c1,c2); 91 | } 92 | 93 | 94 | 95 | //------------------------------------------------------------------------------ 96 | 97 | void setup(void) 98 | { 99 | Serial.begin(19200); 100 | Serial.println("XXX"); 101 | } 102 | 103 | void loop(void) 104 | { 105 | boolean ready = false; 106 | int byte; 107 | int chunk = 0; 108 | int counter; 109 | 110 | addr=0; 111 | for (int i=0; i< 256; i++) writeEEPROM(0xFF); 112 | Serial.setTimeout(5000); 113 | startaddrs[chunk++] = addr; 114 | counter = 0; 115 | while (!ready) { 116 | byte = readNextByte(); 117 | if (byte < 0) { 118 | switch (byte) { 119 | case -99: 120 | Serial.print("Num error\n"); 121 | while (1) { }; 122 | break; 123 | case -1: 124 | finishEEPage(); 125 | Serial.println("ZZZ"); 126 | startaddrs[chunk++] = addr; 127 | counter = 0; 128 | break; 129 | case -2: 130 | Serial.println("ZZ seen"); 131 | ready = true; 132 | break; 133 | } 134 | } else { 135 | writeEEPROM((uint8_t)byte); 136 | counter++; 137 | if (counter%256 == 0) { 138 | Serial.println("PAGE"); 139 | counter = 0; 140 | } 141 | } 142 | } 143 | pinMode(13,OUTPUT); 144 | digitalWrite(13,HIGH); 145 | delay(1000); 146 | digitalWrite(13,LOW); 147 | finishEEPage(); 148 | addr = 0; // write start addr table 149 | for (chunk = 0; chunk < 64; chunk++) { 150 | writeEEPROM((uint8_t)(startaddrs[chunk]>>24)&0xFF); 151 | writeEEPROM((uint8_t)(startaddrs[chunk]>>16)&0xFF); 152 | writeEEPROM((uint8_t)(startaddrs[chunk]>>8)&0xFF); 153 | writeEEPROM((uint8_t)(startaddrs[chunk])&0xFF); 154 | } 155 | while (1) { }; 156 | } 157 | -------------------------------------------------------------------------------- /extras/tests/slowsoft/SlowSoftI2CMaster.cpp: -------------------------------------------------------------------------------- 1 | /* Arduino Slow Software I2C Master 2 | Copyright (c) 2017 Bernhard Nebel. 3 | 4 | This library is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU Lesser General Public License 6 | as published by the Free Software Foundation; either version 3 of 7 | the License, or (at your option) any later version. 8 | 9 | This library is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this library; if not, write to the Free Software 16 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 17 | USA 18 | */ 19 | 20 | #include "SlowSoftI2CMaster.h" 21 | 22 | SlowSoftI2CMaster::SlowSoftI2CMaster(uint8_t sda, uint8_t scl) { 23 | _sda = sda; 24 | _scl = scl; 25 | _pullup = false; 26 | } 27 | 28 | SlowSoftI2CMaster::SlowSoftI2CMaster(uint8_t sda, uint8_t scl, bool pullup) { 29 | _sda = sda; 30 | _scl = scl; 31 | _pullup = pullup; 32 | } 33 | // Init function. Needs to be called once in the beginning. 34 | // Returns false if SDA or SCL are low, which probably means 35 | // a I2C bus lockup or that the lines are not pulled up. 36 | bool SlowSoftI2CMaster::i2c_init(void) { 37 | digitalWrite(_sda, LOW); 38 | digitalWrite(_scl, LOW); 39 | setHigh(_sda); 40 | setHigh(_scl); 41 | if (digitalRead(_sda) == LOW || digitalRead(_scl) == LOW) return false; 42 | return true; 43 | } 44 | 45 | // Start transfer function: is the 8-bit I2C address (including the R/W 46 | // bit). 47 | // Return: true if the slave replies with an "acknowledge", false otherwise 48 | bool SlowSoftI2CMaster::i2c_start(uint8_t addr) { 49 | setLow(_sda); 50 | delayMicroseconds(DELAY); 51 | setLow(_scl); 52 | return i2c_write(addr); 53 | } 54 | 55 | // Try to start transfer until an ACK is returned 56 | bool SlowSoftI2CMaster::i2c_start_wait(uint8_t addr) { 57 | long retry = I2C_MAXWAIT; 58 | while (!i2c_start(addr)) { 59 | i2c_stop(); 60 | if (--retry == 0) return false; 61 | } 62 | return true; 63 | } 64 | 65 | // Repeated start function: After having claimed the bus with a start condition, 66 | // you can address another or the same chip again without an intervening 67 | // stop condition. 68 | // Return: true if the slave replies with an "acknowledge", false otherwise 69 | bool SlowSoftI2CMaster::i2c_rep_start(uint8_t addr) { 70 | setHigh(_sda); 71 | setHigh(_scl); 72 | delayMicroseconds(DELAY); 73 | return i2c_start(addr); 74 | } 75 | 76 | // Issue a stop condition, freeing the bus. 77 | void SlowSoftI2CMaster::i2c_stop(void) { 78 | setLow(_sda); 79 | delayMicroseconds(DELAY); 80 | setHigh(_scl); 81 | delayMicroseconds(DELAY); 82 | setHigh(_sda); 83 | delayMicroseconds(DELAY); 84 | } 85 | 86 | // Write one byte to the slave chip that had been addressed 87 | // by the previous start call. is the byte to be sent. 88 | // Return: true if the slave replies with an "acknowledge", false otherwise 89 | bool SlowSoftI2CMaster::i2c_write(uint8_t value) { 90 | for (uint8_t curr = 0X80; curr != 0; curr >>= 1) { 91 | if (curr & value) setHigh(_sda); else setLow(_sda); 92 | setHigh(_scl); 93 | delayMicroseconds(DELAY); 94 | setLow(_scl); 95 | } 96 | // get Ack or Nak 97 | setHigh(_sda); 98 | setHigh(_scl); 99 | delayMicroseconds(DELAY/2); 100 | uint8_t ack = digitalRead(_sda); 101 | setLow(_scl); 102 | delayMicroseconds(DELAY/2); 103 | setLow(_sda); 104 | return ack == 0; 105 | } 106 | 107 | // Read one byte. If is true, we send a NAK after having received 108 | // the byte in order to terminate the read sequence. 109 | uint8_t SlowSoftI2CMaster::i2c_read(bool last) { 110 | uint8_t b = 0; 111 | setHigh(_sda); 112 | for (uint8_t i = 0; i < 8; i++) { 113 | b <<= 1; 114 | delayMicroseconds(DELAY); 115 | setHigh(_scl); 116 | if (digitalRead(_sda)) b |= 1; 117 | setLow(_scl); 118 | } 119 | if (last) setHigh(_sda); else setLow(_sda); 120 | setHigh(_scl); 121 | delayMicroseconds(DELAY/2); 122 | setLow(_scl); 123 | delayMicroseconds(DELAY/2); 124 | setLow(_sda); 125 | return b; 126 | } 127 | 128 | void SlowSoftI2CMaster::setLow(uint8_t pin) { 129 | noInterrupts(); 130 | if (_pullup) 131 | digitalWrite(pin, LOW); 132 | pinMode(pin, OUTPUT); 133 | interrupts(); 134 | } 135 | 136 | 137 | void SlowSoftI2CMaster::setHigh(uint8_t pin) { 138 | noInterrupts(); 139 | if (_pullup) 140 | pinMode(pin, INPUT_PULLUP); 141 | else 142 | pinMode(pin, INPUT); 143 | interrupts(); 144 | } 145 | 146 | -------------------------------------------------------------------------------- /examples/TSL2561Soft/TSL2561Soft.ino: -------------------------------------------------------------------------------- 1 | // Sketch to explore the luminosity sensor TSL2561 (breakout board by Adafruit) 2 | 3 | #define INTTIME TSL2561_TIME_402MS 4 | #define GAIN false 5 | 6 | #ifdef __AVR_ATmega328P__ 7 | #define SDA_PORT PORTC 8 | #define SDA_PIN 4 9 | #define SCL_PORT PORTC 10 | #define SCL_PIN 5 11 | #define I2C_FASTMODE 1 12 | #else 13 | #define SDA_PORT PORTB 14 | #define SDA_PIN 0 15 | #define SCL_PORT PORTB 16 | #define SCL_PIN 2 17 | #define I2C_FASTMODE 1 18 | #endif 19 | 20 | #include 21 | #include "TSL2561Soft.h" 22 | 23 | #define ADDR 0x72 24 | 25 | //------------------------------------------------------------------------------ 26 | unsigned long computeLux(boolean gain, int intTime , unsigned long channel0, unsigned long channel1){ 27 | 28 | uint16_t clipThreshold; 29 | unsigned long chScale; 30 | 31 | switch (intTime) { 32 | case TSL2561_TIME_13MS: 33 | clipThreshold = TSL2561_CLIPPING_13MS; 34 | chScale = TSL2561_LUX_CHSCALE_TINT0; 35 | break; 36 | case TSL2561_TIME_101MS: 37 | clipThreshold = TSL2561_CLIPPING_101MS; 38 | chScale = TSL2561_LUX_CHSCALE_TINT1; 39 | break; 40 | case TSL2561_TIME_402MS: 41 | clipThreshold = TSL2561_CLIPPING_402MS; 42 | chScale = (1 << TSL2561_LUX_CHSCALE); 43 | break; 44 | } 45 | if (!gain) chScale = chScale << 4; 46 | 47 | /* Return MAX lux if the sensor is saturated */ 48 | if ((channel0 > clipThreshold) || (channel1 > clipThreshold)) 49 | { 50 | #ifdef __AVR_ATmega328P__ 51 | Serial.println(F("Sensor is saturated")); 52 | #endif 53 | return 32000; 54 | } 55 | 56 | channel0 = (channel0 * chScale) >> TSL2561_LUX_CHSCALE; 57 | channel1 = (channel1 * chScale) >> TSL2561_LUX_CHSCALE; 58 | 59 | 60 | /* Find the ratio of the channel values (Channel1/Channel0) */ 61 | unsigned long ratio1 = 0; 62 | if (channel0 != 0) ratio1 = (channel1 << (TSL2561_LUX_RATIOSCALE+1)) / channel0; 63 | 64 | /* round the ratio value */ 65 | unsigned long ratio = (ratio1 + 1) >> 1; 66 | 67 | unsigned int b, m; 68 | 69 | if ((ratio >= 0) && (ratio <= TSL2561_LUX_K1T)) 70 | {b=TSL2561_LUX_B1T; m=TSL2561_LUX_M1T;} 71 | else if (ratio <= TSL2561_LUX_K2T) 72 | {b=TSL2561_LUX_B2T; m=TSL2561_LUX_M2T;} 73 | else if (ratio <= TSL2561_LUX_K3T) 74 | {b=TSL2561_LUX_B3T; m=TSL2561_LUX_M3T;} 75 | else if (ratio <= TSL2561_LUX_K4T) 76 | {b=TSL2561_LUX_B4T; m=TSL2561_LUX_M4T;} 77 | else if (ratio <= TSL2561_LUX_K5T) 78 | {b=TSL2561_LUX_B5T; m=TSL2561_LUX_M5T;} 79 | else if (ratio <= TSL2561_LUX_K6T) 80 | {b=TSL2561_LUX_B6T; m=TSL2561_LUX_M6T;} 81 | else if (ratio <= TSL2561_LUX_K7T) 82 | {b=TSL2561_LUX_B7T; m=TSL2561_LUX_M7T;} 83 | else if (ratio > TSL2561_LUX_K8T) 84 | {b=TSL2561_LUX_B8T; m=TSL2561_LUX_M8T;} 85 | 86 | unsigned long temp; 87 | temp = ((channel0 * b) - (channel1 * m)); 88 | 89 | /* Do not allow negative lux value */ 90 | if (temp < 0) temp = 0; 91 | 92 | /* Round lsb (2^(LUX_SCALE-1)) */ 93 | temp += (1 << (TSL2561_LUX_LUXSCALE-1)); 94 | 95 | /* Strip off fractional portion */ 96 | unsigned long lux = temp >> TSL2561_LUX_LUXSCALE; 97 | 98 | return lux; 99 | } 100 | 101 | void setup(void) { 102 | 103 | #ifdef __AVR_ATmega328P__ 104 | Serial.begin(19200); 105 | Serial.println("Initializing ..."); 106 | #endif 107 | i2c_init(); 108 | 109 | if (!i2c_start(ADDR | I2C_WRITE)) { 110 | #ifdef __AVR_ATmega328P__ 111 | Serial.println(F("Device does not respond")); 112 | #endif 113 | } 114 | if (!i2c_write(0x80)) { 115 | #ifdef __AVR_ATmega328P__ 116 | Serial.println(F("Cannot address reg 0")); 117 | #endif 118 | } 119 | if (!i2c_write(0x03)) { 120 | #ifdef __AVR_ATmega328P__ 121 | Serial.println(F("Cannot wake up")); // wake up 122 | #endif 123 | } 124 | i2c_stop(); 125 | i2c_start(ADDR | I2C_WRITE); 126 | if (!i2c_write(0x81)) { 127 | #ifdef __AVR_ATmega328P__ 128 | Serial.println(F("Cannot address reg 1")); 129 | #endif 130 | } 131 | if (!i2c_write((GAIN ? 0x10 : 0x00)+INTTIME)) { 132 | #ifdef __AVR_ATmega328P__ 133 | Serial.println(F("Cannot change gain & integration time")); 134 | #endif 135 | } 136 | i2c_stop(); 137 | 138 | } 139 | 140 | void loop (void) { 141 | unsigned int low0, high0, low1, high1; 142 | unsigned int chan0, chan1; 143 | unsigned int lux; 144 | 145 | if (!i2c_start(ADDR | I2C_WRITE)) { 146 | #ifdef __AVR_ATmega328P__ 147 | Serial.println(F("Device does not respond")); 148 | #endif 149 | } 150 | if (!i2c_write(0x80)) { 151 | #ifdef __AVR_ATmega328P__ 152 | Serial.println(F("Cannot address reg 0")); 153 | #endif 154 | } 155 | if (!i2c_write(0x03)) { 156 | #ifdef __AVR_ATmega328P__ 157 | Serial.println(F("Cannot wake up")); 158 | #endif 159 | } 160 | i2c_stop(); 161 | delay(600); 162 | i2c_start(ADDR | I2C_WRITE); 163 | i2c_write(0x8C); 164 | i2c_rep_start(ADDR | I2C_READ); 165 | low0 = i2c_read(false); 166 | high0 = i2c_read(true); 167 | i2c_stop(); 168 | i2c_start(ADDR | I2C_WRITE); 169 | i2c_write(0x8E); 170 | i2c_rep_start(ADDR | I2C_READ); 171 | low1 = i2c_read(false); 172 | high1 = i2c_read(true); 173 | i2c_stop(); 174 | i2c_start(ADDR | I2C_WRITE); 175 | if (!i2c_write(0x80)) { 176 | #ifdef __AVR_ATmega328P__ 177 | Serial.println(F("Cannot address reg 0")); 178 | #endif 179 | } 180 | if (!i2c_write(0x00)) { 181 | #ifdef __AVR_ATmega328P__ 182 | Serial.println(F("Cannot wake up")); 183 | #endif 184 | } 185 | i2c_stop(); 186 | #ifdef __AVR_ATmega328P__ 187 | Serial.print(F("Raw values: chan0=")); 188 | Serial.print(chan0=(low0+(high0<<8))); 189 | Serial.print(F(" / chan1=")); 190 | Serial.println(chan1=(low1+(high1<<8))); 191 | lux = computeLux(GAIN,INTTIME,chan0,chan1); 192 | Serial.print(F("Lux value=")); 193 | Serial.println(lux); 194 | #else 195 | while (1) ; 196 | #endif 197 | delay(1000); 198 | } 199 | -------------------------------------------------------------------------------- /examples/I2CShell/README.md: -------------------------------------------------------------------------------- 1 | # I2CShell 2 | 3 | I2CShell allows you to interact with I2C devices from the console, 4 | similar to what you can do with the Bus Pirate. You 5 | can type in a line such as 6 | 7 | [ 0x10 5 [ 0x11 r:3 ] 8 | This will address the I2C device under (8-bit) address 0x10, 9 | corresponding to 7-bit address 0x08 in writing direction, and 10 | send 0x05 to the device. After that the device is again addressed 11 | with a repeated start in reading direction and 3 bytes are requested. 12 | The output could look like as follows: 13 | 14 | Start: 0x10 (0x08!) + ACK 15 | Write: 0x05 + ACK 16 | Rep. start: 0x11 (0x08?) + ACK 17 | Read: 0x10 + ACK 18 | Read: 0x5A + ACK 19 | Read: 0x98 + NAK 20 | Stop 21 | 22 | 23 | ## Installation and configuration 24 | 25 | I2CShell is part of the bit-banging I2C library 26 | [SoftI2CMaster](https://github.com/felias-fogg/SoftI2CMaster). After 27 | downloading this library, you find I2CShell as one of the examples in 28 | the examples folder. 29 | 30 | Before you use the sketch, you should probably adjust some of the 31 | compile-time constants in the sketch. 32 | 33 | USEEEPROM 34 | If 1 (the default), macros are stored in EEPROM so that they survive 35 | program exits. If 0, the EEPROM contents is not touched. 36 | 37 | I2C_HARDWARE 38 | If 1 (default), the I2C hardware support is used instead of the 39 | bit-banging version of the I2C library. This gives a little bit more 40 | flexibility (concerning clock frequency and pullup resistors), 41 | but restricts you to use the standard I2C pins SDA and SCL. 42 | 43 | I2C_TIMEOUT 44 | If 0, I2C operations do not time out. The default value is 100 45 | (milliseconds). It is safe to leave it this way. 46 | 47 | I2C_PULLUP 48 | If 1 (the default), then the MCU internal pullups are activated. This 49 | is safe as long as you do not connect 3 Volt devices that get 50 | destroyed by higher voltage. 51 | 52 | Finally, there are the four constants to determine the I2C pins when 53 | you use the bit-banging version of the I2C library (i.e. I2C_HARDWARE 54 | is 0). These pins have to be specified in a 55 | way so that 56 | [port manipulation commands](http://www.arduino.cc/en/Reference/PortManipulation) 57 | can be used. Instead of specifying the number of the digital pin 58 | (0-19), the *port* (PORTB, PORTC, PORTD) and the *port pin* has to be 59 | specified. The mapping is explained 60 | [here](http://www.arduino.cc/en/Reference/PortManipulation). For 61 | example, if you want to use *digital pin 2* for *SCL* and *digital pin 14* 62 | (= analog pin 0) for *SDA*, you have to specify *port pin 2 of PORTD* for 63 | SCL and *port pin 0 of PORTC* for SDA. 64 | 65 | #define SCL_PIN 2 66 | #define SCL_PORT PORTD 67 | #define SDA_PIN 0 68 | #define SDA_PORT PORTC 69 | 70 | 71 | Note that all the compile time constants have to be placed before the 72 | inclusion of the SoftI2CMaster library. 73 | 74 | 75 | ## Commands 76 | 77 | You can use I2CShell either with Arduino's serial monitor or with 78 | an ordinary terminal program (e.g. screen under 79 | Unix). Baudrate is 115200, 8 bits, 1 stop bit, no parity bit. 80 | 81 | In the following _\_ denotes a single decimal digit and *\* 82 | denotes a non-negative number in the usual notation, i.e., 17, 0x11, 83 | 0X11, 0o21, or 0b10001 84 | can all be written in order to refer to the decimal number 85 | seventeen. As a means to make life easier when converting between 8-bit 86 | and 7-bit addresses, one can postfix a number with ! or 87 | ? in order to signify the write, resp. read direction 88 | together with a 7-bit address. This means that, e.g. 0x10 can also be 89 | written as 0x08! and 0x11 as 0x08?. In general, the input is case 90 | insensitive. 91 | 92 | There are a number of commands that one can use to interact with the 93 | program in order to configure it and to access the I2C bus: 94 | 95 | * H gives a short help screen. 96 | * S scans the I2C bus for devices. Reports under which 97 | addresses the program receives an ACK. 98 | * T prints last execution trace again. 99 | * T\ prints 20 commands of the last execution trace 100 | starting at command \ (numbering starts at command 0). 101 | * \=... defines a macro under the single digit 102 | identifier \. These macros can be used later inside I2C command 103 | strings. 104 | * L lists all macros. 105 | * L\ lists the macro with identifier \. 106 | * P shows status of pullup resistors. 107 | * P\ enables the pullups (1) or disables them 108 | (0). Works only if the hardware interface has been enabled (I2C_HARDWARE 109 | must be 1). 110 | * F reports the I2C clock frequency. 111 | * F\ sets the I2C clock frequency to \ 112 | kHz. Works only if the hardware interface has been enabled. 113 | 114 | ## I2C interaction 115 | 116 | You can write one line (of 80 characters) of I2C commands that is 117 | sent to the I2C bus after you finish the line with the \ 118 | key. The results are recorded and then presented in the terminal 119 | window, as shown above. There exist the following commands: 120 | 121 | * [ Issue a start condition; this is needed in order to claim access to the bus and is always followed by an I2C device address. 122 | * { Issue start conditions until the addressed device responds with an ACK. The maximum number of repetitions is 255. 123 | * ] Issue a stop condition, which releases the bus. 124 | * \ Send one byte to the I2C bus; the receipt of 125 | the byte will be acknowledged by the receiving device with an ACK. 126 | * R Read one byte from the addressed I2C device. The NAK 127 | for the last byte will be automatically generated. 128 | * & Wait for a microsecond. 129 | * % Wait for a millisecond. 130 | * :\ Repeat the previous command \ 131 | times. This is not allowed for start conditions and previous 132 | repetitions. 133 | * (\) Execute macro. 134 | 135 | Between commands, one can put commas and blanks in order to make the line 136 | more readable. The only point when you have to use such separators is 137 | when two numbers are adjacent. 138 | 139 | ## Edit commands 140 | 141 | When using a terminal window, there are also a number of edit commands 142 | one can use: 143 | 144 | * Ctrl-A or UP arrow Go to start of line. 145 | * Ctrl-E or DOWN arrow Go to end on line. 146 | * Ctrl-B or LEFT arrow Go one character 147 | backward. 148 | * Ctrl-F or RIGHT arrow Go one character 149 | forward. 150 | * Ctrl-H or DELETE Delete last character. 151 | * Ctrl-D Delete character under cursor. 152 | * Ctrl-K Kill rest of line. 153 | * Ctrl-P If typed before anything else is written, the 154 | last line is retrieved and can be edited. 155 | * $\ Inserts the macro \ at this point 156 | into the line. 157 | -------------------------------------------------------------------------------- /src/SoftWire.h: -------------------------------------------------------------------------------- 1 | /* 2 | SoftWire.h - A Wire compatible wrapper for SoftI2CMaster 3 | Copyright (c) 2016 Bernhard Nebel. 4 | 5 | This file is part of SoftI2CMaster https://github.com/felias-fogg/SoftI2CMaster. 6 | 7 | This library is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU Lesser General Public 9 | License as published by the Free Software Foundation; either 10 | version 2.1 of the License, or (at your option) any later version. 11 | 12 | This library is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public 18 | License along with this library; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | 22 | #ifndef _SoftWire_h 23 | #define _SoftWire_h 24 | 25 | #include 26 | #include "Stream.h" 27 | 28 | #ifndef I2C_BUFFER_LENGTH 29 | #define I2C_BUFFER_LENGTH 32 30 | #endif 31 | 32 | // WIRE_HAS_END means Wire has end() 33 | #define WIRE_HAS_END 1 34 | 35 | class SoftWire : public Stream // @suppress("Class has a virtual method and non-virtual destructor") 36 | { 37 | private: 38 | uint8_t rxBuffer[I2C_BUFFER_LENGTH]; 39 | uint8_t rxBufferIndex; 40 | uint8_t rxBufferLength; 41 | uint8_t transmitting; 42 | uint8_t error; 43 | public: 44 | SoftWire(void); 45 | 46 | void begin(void); 47 | void end(void); 48 | void setClock(uint32_t _); 49 | 50 | void beginTransmission(uint8_t address); 51 | 52 | void beginTransmission(int address); 53 | uint8_t endTransmission(uint8_t sendStop); 54 | 55 | // This provides backwards compatibility with the original 56 | // definition, and expected behaviour, of endTransmission 57 | // 58 | uint8_t endTransmission(void); 59 | 60 | size_t write(uint8_t data); 61 | size_t write(const uint8_t *data, size_t quantity); 62 | 63 | uint8_t requestFrom(uint8_t address, uint8_t quantity, 64 | uint32_t iaddress, uint8_t isize, uint8_t sendStop); 65 | uint8_t requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop); 66 | uint8_t requestFrom(int address, int quantity, int sendStop); 67 | uint8_t requestFrom(uint8_t address, uint8_t quantity); 68 | uint8_t requestFrom(int address, int quantity); 69 | 70 | int available(void); 71 | int read(void); 72 | int peek(void); 73 | void flush(void); 74 | 75 | inline size_t write(unsigned long n) { return write((uint8_t)n); } 76 | inline size_t write(long n) { return write((uint8_t)n); } 77 | inline size_t write(unsigned int n) { return write((uint8_t)n); } 78 | inline size_t write(int n) { return write((uint8_t)n); } 79 | 80 | // using Print::write; 81 | }; 82 | 83 | extern SoftWire Wire; 84 | 85 | #if !defined(USE_SOFTWIRE_H_AS_PLAIN_INCLUDE) 86 | /* 87 | * The implementation part of the header only library starts here 88 | */ 89 | #include 90 | 91 | SoftWire::SoftWire(void) { 92 | } 93 | 94 | void SoftWire::begin(void) { 95 | rxBufferIndex = 0; 96 | rxBufferLength = 0; 97 | error = 0; 98 | transmitting = false; 99 | 100 | i2c_init(); 101 | } 102 | 103 | void SoftWire::end(void) { 104 | } 105 | 106 | void SoftWire::setClock(uint32_t _) { 107 | (void) _; 108 | } 109 | 110 | void SoftWire::beginTransmission(uint8_t address) { 111 | if (transmitting) { 112 | error = (i2c_rep_start((address<<1)|I2C_WRITE) ? 0 : 2); 113 | } else { 114 | error = (i2c_start((address<<1)|I2C_WRITE) ? 0 : 2); 115 | } 116 | // indicate that we are transmitting 117 | transmitting = 1; 118 | } 119 | 120 | void SoftWire::beginTransmission(int address) { 121 | beginTransmission((uint8_t)address); 122 | } 123 | 124 | uint8_t SoftWire::endTransmission(uint8_t sendStop) 125 | { 126 | uint8_t transError = error; 127 | if (sendStop) { 128 | i2c_stop(); 129 | transmitting = 0; 130 | } 131 | error = 0; 132 | return transError; 133 | } 134 | 135 | // This provides backwards compatibility with the original 136 | // definition, and expected behaviour, of endTransmission 137 | // 138 | uint8_t SoftWire::endTransmission(void) 139 | { 140 | return endTransmission(true); 141 | } 142 | 143 | size_t SoftWire::write(uint8_t data) { 144 | if (i2c_write(data)) { 145 | return 1; 146 | } else { 147 | if (error == 0) error = 3; 148 | return 0; 149 | } 150 | } 151 | 152 | size_t SoftWire::write(const uint8_t *data, size_t quantity) { 153 | size_t trans = 0; 154 | for(size_t i = 0; i < quantity; ++i){ 155 | trans += write(data[i]); 156 | } 157 | return trans; 158 | } 159 | 160 | uint8_t SoftWire::requestFrom(uint8_t address, uint8_t quantity, 161 | uint32_t iaddress, uint8_t isize, uint8_t sendStop) { 162 | error = 0; 163 | uint8_t localerror = 0; 164 | if (isize > 0) { 165 | // send internal address; this mode allows sending a repeated start to access 166 | // some devices' internal registers. This function is executed by the hardware 167 | // TWI module on other processors (for example Due's TWI_IADR and TWI_MMR registers) 168 | beginTransmission(address); 169 | // the maximum size of internal address is 3 bytes 170 | if (isize > 3){ 171 | isize = 3; 172 | } 173 | // write internal register address - most significant byte first 174 | while (isize-- > 0) { 175 | write((uint8_t)(iaddress >> (isize*8))); 176 | } 177 | endTransmission(false); 178 | } 179 | // clamp to buffer length 180 | if(quantity > I2C_BUFFER_LENGTH){ 181 | quantity = I2C_BUFFER_LENGTH; 182 | } 183 | if (transmitting) { 184 | localerror = !i2c_rep_start((address<<1) | I2C_READ); 185 | } else { 186 | localerror = !i2c_start((address<<1) | I2C_READ); 187 | } 188 | if (error == 0 && localerror) error = 2; 189 | // perform blocking read into buffer 190 | for (uint8_t cnt=0; cnt < quantity; cnt++) { 191 | rxBuffer[cnt] = i2c_read(cnt == quantity-1); 192 | } 193 | // set rx buffer iterator vars 194 | rxBufferIndex = 0; 195 | rxBufferLength = error ? 0 : quantity; 196 | if (sendStop) { 197 | transmitting = 0; 198 | i2c_stop(); 199 | } 200 | return rxBufferLength; 201 | } 202 | 203 | uint8_t SoftWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop) { 204 | return requestFrom((uint8_t)address, (uint8_t)quantity, (uint32_t)0, (uint8_t)0, (uint8_t)sendStop); 205 | } 206 | 207 | uint8_t SoftWire::requestFrom(int address, int quantity, int sendStop) { 208 | return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)sendStop); 209 | } 210 | 211 | 212 | uint8_t SoftWire::requestFrom(uint8_t address, uint8_t quantity) { 213 | return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true); 214 | } 215 | 216 | uint8_t SoftWire::requestFrom(int address, int quantity) { 217 | return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true); 218 | } 219 | 220 | int SoftWire::available(void) { 221 | return rxBufferLength - rxBufferIndex; 222 | } 223 | 224 | int SoftWire::read(void) { 225 | int value = -1; 226 | if(rxBufferIndex < rxBufferLength){ 227 | value = rxBuffer[rxBufferIndex]; 228 | ++rxBufferIndex; 229 | } 230 | return value; 231 | } 232 | 233 | int SoftWire::peek(void) { 234 | int value = -1; 235 | 236 | if(rxBufferIndex < rxBufferLength){ 237 | value = rxBuffer[rxBufferIndex]; 238 | } 239 | return value; 240 | } 241 | 242 | void SoftWire::flush(void) { 243 | } 244 | 245 | 246 | // Preinstantiate Objects ////////////////////////////////////////////////////// 247 | 248 | SoftWire Wire = SoftWire(); 249 | 250 | #endif // !defined(USE_SOFTWIRE_H_AS_PLAIN_INCLUDE) 251 | 252 | #endif // #ifndef _SoftWire_h 253 | #pragma once 254 | -------------------------------------------------------------------------------- /examples/Eeprom24AA1025SoftWire/Eeprom24AA1025SoftWire.ino: -------------------------------------------------------------------------------- 1 | // Sketch to explore 24AA1024 using SoftI2C 2 | 3 | #ifdef __AVR_ATmega328P__ 4 | /* Corresponds to A4/A5 - the hardware I2C pins on Arduinos */ 5 | #define SDA_PORT PORTC 6 | #define SDA_PIN 4 7 | #define SCL_PORT PORTC 8 | #define SCL_PIN 5 9 | #define I2C_FASTMODE 1 10 | #else 11 | #define SDA_PORT PORTB 12 | #define SDA_PIN 0 13 | #define SCL_PORT PORTB 14 | #define SCL_PIN 2 15 | #define I2C_FASTMODE 1 16 | #endif 17 | 18 | #define I2C_FASTMODE 1 19 | // #define I2C_TIMEOUT 10 // timeout after 10 msec 20 | #define I1C_NOINTERRUPT 1 // no interrupts 21 | // #define I2C_CPUFREQ (F_CPU/8) // slow down CPU frequency 22 | #include 23 | 24 | #define EEPROMADDR 0xA6 // set by jumper (A0 and A1 = High) 25 | #define MAXADDR 0x1FFFF 26 | #define MAXTESTADDR 0x003FF 27 | 28 | void CPUSlowDown(void) { 29 | // slow down processor by a factor of 8 30 | CLKPR = _BV(CLKPCE); 31 | CLKPR = _BV(CLKPS1) | _BV(CLKPS0); 32 | } 33 | 34 | 35 | //------------------------------------------------------------------------------ 36 | /* 37 | * read one byte from address 38 | */ 39 | boolean readEEPROM(unsigned long address, uint8_t *byte) { 40 | // issue a start condition, send device address and write direction bit 41 | uint8_t i2caddr = (EEPROMADDR >> 1) | (address&0x10000 ? 4 : 0); 42 | uint8_t end; 43 | Wire.beginTransmission(i2caddr); 44 | Wire.write((address>>8)&0xFF); 45 | Wire.write(address&0xFF); 46 | end = Wire.endTransmission(false); 47 | Wire.requestFrom(i2caddr,1); 48 | *byte = Wire.read(); 49 | return (end == 0); 50 | } 51 | //------------------------------------------------------------------------------ 52 | /* 53 | *burst read 54 | */ 55 | boolean readBurstEEPROM(unsigned long start, unsigned long stop) { 56 | // does not handle the transition from 0x0FFFF to 0x10000 57 | // since we only use it for performance evaluation, we do not care! 58 | unsigned long addr = start; 59 | uint8_t byte; 60 | uint8_t i2caddr = (EEPROMADDR >> 1) | (start&0x10000 ? 4 : 0); 61 | uint8_t end; 62 | 63 | Wire.beginTransmission(i2caddr); 64 | Wire.write((start>>8)&0xFF); 65 | Wire.write(start&0xFF); 66 | end = Wire.endTransmission(false); 67 | 68 | while (addr < stop) { 69 | addr += 32; 70 | Wire.requestFrom(i2caddr,32,(addr >= stop)); 71 | while (Wire.available()) byte = Wire.read(); 72 | } 73 | return (end == 0); 74 | } 75 | 76 | 77 | //------------------------------------------------------------------------------ 78 | 79 | /* 80 | * write 1 byte to 'address' in eeprom 81 | */ 82 | boolean writeEEPROM(long unsigned address, uint8_t byte) { 83 | 84 | uint8_t end; 85 | uint8_t i2caddr = (EEPROMADDR >> 1) | (address&0x10000 ? 4 : 0); 86 | Wire.beginTransmission(i2caddr); 87 | Wire.write((address>>8)&0xFF); 88 | Wire.write(address&0xFF); 89 | Wire.write(byte); 90 | end = Wire.endTransmission(true); 91 | 92 | delay(6); 93 | return (end == 0); 94 | } 95 | 96 | //------------------------------------------------------------------------------ 97 | /* 98 | * delete eeprom 99 | */ 100 | boolean deleteEEPROM(long unsigned from, unsigned long to, uint8_t byte, 101 | boolean poll) { 102 | 103 | unsigned long tempto, i; 104 | uint8_t i2caddr; 105 | uint8_t end = 0; 106 | 107 | while (from <= to) { 108 | tempto = ((from/128)+1)*128-1; 109 | if (tempto > to) tempto = to; 110 | i2caddr = (EEPROMADDR >> 1) | (from&0x10000 ? 4 : 0); 111 | Wire.beginTransmission(i2caddr); 112 | Wire.write((from>>8)&0xFF); 113 | Wire.write(from&0xFF); 114 | 115 | // send data to EEPROM 116 | for (i=from; i<=tempto; i++) 117 | Wire.write(byte); 118 | // issue a stop condition 119 | end |= Wire.endTransmission(); 120 | 121 | // wait for ack again 122 | if (!poll) delay(6); 123 | 124 | from = tempto+1; 125 | } 126 | return (end == 0); 127 | } 128 | 129 | //------------------------------------------------------------------------------ 130 | boolean performanceTest() { 131 | unsigned long eeaddr; 132 | unsigned long startmicros, endmicros; 133 | int avgtime; 134 | boolean OK = true; 135 | uint8_t byte; 136 | 137 | Serial.println(F("\nPerformance test:")); 138 | 139 | Serial.println(F("Sequential reads ...")); 140 | startmicros = micros(); 141 | OK &= readBurstEEPROM(0,MAXTESTADDR); 142 | endmicros = micros(); 143 | Serial.print(F("Time: ")); 144 | avgtime = (endmicros-startmicros)/(MAXTESTADDR+1); 145 | Serial.print(avgtime); 146 | Serial.println(F(" micro secs/byte")); 147 | if (!OK) { 148 | Serial.println(F("An error occured")); 149 | return false; 150 | } 151 | 152 | Serial.println(F("Random reads ...")); 153 | startmicros = micros(); 154 | for (eeaddr = 0; eeaddr <= MAXTESTADDR; eeaddr++) 155 | OK &= readEEPROM(eeaddr,&byte); 156 | endmicros = micros(); 157 | Serial.print(F("Time: ")); 158 | avgtime = (endmicros-startmicros)/(MAXTESTADDR+1); 159 | Serial.print(avgtime); 160 | Serial.println(F(" micro secs/byte")); 161 | if (!OK) { 162 | Serial.println(F("An error occured")); 163 | return false; 164 | } 165 | 166 | Serial.println(F("Random writes ...")); 167 | startmicros = micros(); 168 | for (eeaddr = 0; eeaddr <= MAXTESTADDR; eeaddr++) 169 | OK &= writeEEPROM(eeaddr,0x55); 170 | endmicros = micros(); 171 | Serial.print(F("Time: ")); 172 | avgtime = (endmicros-startmicros)/(MAXTESTADDR+1); 173 | Serial.print(avgtime); 174 | Serial.println(F(" micro secs/byte")); 175 | if (!OK) { 176 | Serial.println(F("An error occured")); 177 | return false; 178 | } 179 | 180 | Serial.println(F("Page writes with wait ...")); 181 | startmicros = micros(); 182 | OK &= deleteEEPROM(0,MAXTESTADDR,0xFF,false); 183 | endmicros = micros(); 184 | Serial.print(F("Time: ")); 185 | avgtime = (endmicros-startmicros)/(MAXTESTADDR+1); 186 | Serial.print(avgtime); 187 | Serial.println(F(" micro secs/byte")); 188 | if (!OK) { 189 | Serial.println(F("An error occured")); 190 | return false; 191 | } 192 | 193 | Serial.println(F("Page writes with poll ...")); 194 | startmicros = micros(); 195 | OK &= deleteEEPROM(0,MAXTESTADDR,0xFF,true); 196 | endmicros = micros(); 197 | Serial.print(F("Time: ")); 198 | avgtime = (endmicros-startmicros)/(MAXTESTADDR+1); 199 | Serial.print(avgtime); 200 | Serial.println(F(" micro secs/byte")); 201 | if (!OK) { 202 | Serial.println(F("An error occured")); 203 | return false; 204 | } 205 | 206 | return true; 207 | } 208 | //------------------------------------------------------------------------------ 209 | 210 | unsigned long parseHex() { 211 | unsigned long result = 0L; 212 | char inp = '\0'; 213 | byte num = 0; 214 | 215 | while (inp != '\r' && inp != '#') { 216 | while (!Serial.available()); 217 | inp = Serial.read(); 218 | if (inp == '\r' || inp == '#') break; 219 | if (inp >= 'a' && inp <= 'f') 220 | inp = inp -'a' + 'A'; 221 | if ((inp >= '0' && inp <= '9') || 222 | (inp >= 'A' && inp <= 'F')) { 223 | Serial.print(inp); 224 | if (inp >= '0' && inp <= '9') num = inp - '0'; 225 | else num = inp - 'A' + 10; 226 | result = result * 16; 227 | result = result + num; 228 | } 229 | } 230 | Serial.println(); 231 | return result; 232 | } 233 | 234 | void help (void) { 235 | Serial.println(); 236 | Serial.println(F("r - read byte from address")); 237 | Serial.println(F("w - write byte to address")); 238 | Serial.println(F("d - delete from start address to end address")); 239 | Serial.println(F("l - list memory range")); 240 | Serial.println(F("p - test performance")); 241 | Serial.println(F("h - help message")); 242 | Serial.println(F("Finish all numeric inputs with '#'")); 243 | } 244 | 245 | //------------------------------------------------------------------------------ 246 | 247 | 248 | 249 | void setup(void) { 250 | #if I2C_CPUFREQ == (F_CPU/8) 251 | CPUSlowDown(); 252 | #endif 253 | 254 | Serial.begin(115200); 255 | Serial.println(F("\n\nTest program for EEPROM 24AA1025 (SoftWire)")); 256 | help(); 257 | } 258 | 259 | 260 | void loop(void) { 261 | char cmd; 262 | uint8_t byte; 263 | boolean noterror; 264 | unsigned long addr, toaddr; 265 | 266 | while (!Serial.available()); 267 | cmd = Serial.read(); 268 | switch (cmd) { 269 | case 'r': Serial.print(F("Read from addr: ")); 270 | addr = parseHex(); 271 | Serial.println(F("Reading...")); 272 | noterror = readEEPROM(addr,&byte); 273 | Serial.print(addr,HEX); 274 | Serial.print(F(": ")); 275 | if (byte < 0x10) Serial.print("0"); 276 | Serial.println(byte,HEX); 277 | if (!noterror) Serial.println(F("Error while reading")); 278 | break; 279 | case 'w': 280 | Serial.print(F("Write to addr: ")); 281 | addr = parseHex(); 282 | Serial.print(F("Value: ")); 283 | byte = parseHex(); 284 | Serial.println(F("Writing...")); 285 | noterror = writeEEPROM(addr,byte); 286 | if (!noterror) Serial.println(F("Error while reading")); 287 | break; 288 | case 'd': 289 | Serial.print(F("Delete from addr: ")); 290 | addr = parseHex(); 291 | Serial.print(F("to addr: ")); 292 | toaddr = parseHex(); 293 | Serial.print(F("Value: ")); 294 | byte = parseHex(); 295 | Serial.print(F("Deleting ... ")); 296 | noterror = deleteEEPROM(addr,toaddr,byte,false); 297 | Serial.println(F("...done")); 298 | if (!noterror) Serial.println(F("Error while deleting")); 299 | break; 300 | case 'l': 301 | Serial.print(F("List from addr: ")); 302 | addr = parseHex(); 303 | Serial.print(F("to addr: ")); 304 | toaddr = parseHex(); 305 | while (addr <= toaddr) { 306 | noterror = readEEPROM(addr,&byte); 307 | Serial.print(addr,HEX); 308 | Serial.print(F(": ")); 309 | if (byte < 0x10) Serial.print("0"); 310 | Serial.println(byte,HEX); 311 | if (!noterror) Serial.println(F("Error while reading")); 312 | addr++; 313 | } 314 | break; 315 | case 'p': 316 | noterror = performanceTest(); 317 | if (!noterror) Serial.println(F("Error while executing performance test")); 318 | break; 319 | case 'h': 320 | help(); 321 | break; 322 | case '\r': 323 | case '\n': 324 | case ' ': 325 | break; 326 | default: 327 | Serial.println(F("Unknown command")); 328 | Serial.println(); 329 | help(); 330 | } 331 | } 332 | -------------------------------------------------------------------------------- /examples/Eeprom24AA1025SoftI2C/Eeprom24AA1025SoftI2C.ino: -------------------------------------------------------------------------------- 1 | // -*-c++-*- 2 | // Sketch to explore 24AA1024 using SoftI2C 3 | 4 | #ifdef __AVR_ATmega328P__ 5 | /* Corresponds to A4/A5 - the hardware I2C pins on Arduinos */ 6 | #define SDA_PORT PORTC 7 | #define SDA_PIN 4 8 | #define SCL_PORT PORTC 9 | #define SCL_PIN 5 10 | #define I2C_FASTMODE 1 11 | #else 12 | #define SDA_PORT PORTB 13 | #define SDA_PIN 0 14 | #define SCL_PORT PORTB 15 | #define SCL_PIN 2 16 | #define I2C_FASTMODE 1 17 | #endif 18 | 19 | //#define I2C_SLOWMODE 1 20 | //#define I2C_FASTMODE 1 21 | //#define I2C_TIMEOUT 10 // timeout after 10 msec 22 | //#define I1C_NOINTERRUPT 1 // no interrupts 23 | //#define I2C_CPUFREQ (F_CPU/8) // slow down CPU frequency 24 | #include 25 | 26 | #define EEPROMADDR 0xA6 // set by jumper (A0 and A1 = High) 27 | #define MAXADDR 0x1FFFF 28 | #define MAXTESTADDR 0x007FF 29 | 30 | void CPUSlowDown(void) { 31 | // slow down processor by a factor of 8 32 | CLKPR = _BV(CLKPCE); 33 | CLKPR = _BV(CLKPS1) | _BV(CLKPS0); 34 | } 35 | 36 | 37 | //------------------------------------------------------------------------------ 38 | /* 39 | * read one byte from address 40 | */ 41 | boolean readEEPROM(unsigned long address, uint8_t *byte) { 42 | // issue a start condition, send device address and write direction bit 43 | if (!i2c_start(EEPROMADDR | I2C_WRITE | (address&0x10000 ? 8 : 0) )) return false; 44 | 45 | // send the address 46 | if (!i2c_write((address>>8)&0xFF)) return false; 47 | if (!i2c_write(address&0xFF)) return false; 48 | 49 | // issue a repeated start condition, send device address and read direction bit 50 | if (!i2c_rep_start(EEPROMADDR | I2C_READ | (address&0x10000 ? 8 : 0) ))return false; 51 | 52 | *byte = i2c_read(true); 53 | 54 | i2c_stop(); 55 | return true; 56 | } 57 | //------------------------------------------------------------------------------ 58 | /* 59 | *burst read 60 | */ 61 | boolean readBurstEEPROM(unsigned long start, unsigned long stop) { 62 | // does not handle the transition from 0x0FFFF to 0x10000 63 | // since we only use it for performance evaluation, we do not care! 64 | unsigned long addr = start; 65 | uint8_t byte; 66 | // issue a start condition, send device address and write direction bit 67 | if (!i2c_start(EEPROMADDR | I2C_WRITE | (addr&0x10000 ? 8 : 0) )) return false; 68 | 69 | // send the address 70 | if (!i2c_write((addr>>8)&0xFF)) return false; 71 | if (!i2c_write(addr&0xFF)) return false; 72 | 73 | // issue a repeated start condition, send device address and read direction bit 74 | if (!i2c_rep_start(EEPROMADDR | I2C_READ | (addr&0x10000 ? 8 : 0) ))return false; 75 | addr++; 76 | while (addr++ < stop) byte = i2c_read(false); 77 | byte = i2c_read(true); 78 | i2c_stop(); 79 | return true; 80 | } 81 | 82 | 83 | //------------------------------------------------------------------------------ 84 | 85 | /* 86 | * write 1 byte to 'address' in eeprom 87 | */ 88 | boolean writeEEPROM(long unsigned address, uint8_t byte) { 89 | // issue a start condition, send device address and write direction bit 90 | if (!i2c_start(EEPROMADDR | I2C_WRITE | (address&0x10000 ? 8 : 0))) return false; 91 | 92 | // send the address 93 | if (!i2c_write((address>>8)&0xFF)) return false; 94 | if (!i2c_write(address&0xFF)) return false; 95 | 96 | 97 | // send data to EEPROM 98 | if (!i2c_write(byte)) return false; 99 | 100 | // issue a stop condition 101 | i2c_stop(); 102 | 103 | delay(6); 104 | 105 | return true; 106 | } 107 | 108 | //------------------------------------------------------------------------------ 109 | /* 110 | * delete eeprom 111 | */ 112 | boolean deleteEEPROM(long unsigned from, unsigned long to, uint8_t byte, 113 | boolean poll) { 114 | 115 | unsigned long tempto, i; 116 | boolean firstpage = true; 117 | 118 | while (from <= to) { 119 | tempto = ((from/128)+1)*128-1; 120 | if (tempto > to) tempto = to; 121 | if (firstpage || !poll) { 122 | if (!i2c_start(EEPROMADDR | I2C_WRITE | (from&0x10000 ? 8 : 0))) 123 | return false; 124 | } else i2c_start_wait(EEPROMADDR | I2C_WRITE | (from&0x10000 ? 8 : 0)); 125 | // send the address 126 | if (!i2c_write((from>>8)&0xFF)) return false; 127 | if (!i2c_write(from&0xFF)) return false; 128 | 129 | 130 | // send data to EEPROM 131 | for (i=from; i<=tempto; i++) 132 | if (!i2c_write(byte)) return false; 133 | // issue a stop condition 134 | i2c_stop(); 135 | 136 | // wait for ack again 137 | if (!poll) delay(6); 138 | 139 | from = tempto+1; 140 | firstpage = false; 141 | } 142 | return true; 143 | } 144 | 145 | //------------------------------------------------------------------------------ 146 | boolean performanceTest() { 147 | unsigned long eeaddr; 148 | unsigned long startmicros, endmicros; 149 | int avgtime; 150 | boolean OK = true; 151 | uint8_t byte; 152 | 153 | Serial.println(F("\nPerformance test:")); 154 | 155 | Serial.println(F("Sequential reads ...")); 156 | startmicros = micros(); 157 | OK &= readBurstEEPROM(0,MAXTESTADDR); 158 | endmicros = micros(); 159 | Serial.print(F("Time: ")); 160 | avgtime = (endmicros-startmicros)/(MAXTESTADDR+1); 161 | Serial.print(avgtime); 162 | Serial.println(F(" micro secs/byte")); 163 | 164 | Serial.println(F("Random reads ...")); 165 | startmicros = micros(); 166 | for (eeaddr = 0; eeaddr <= MAXTESTADDR; eeaddr++) 167 | OK &= readEEPROM(eeaddr,&byte); 168 | endmicros = micros(); 169 | Serial.print(F("Time: ")); 170 | avgtime = (endmicros-startmicros)/(MAXTESTADDR+1); 171 | Serial.print(avgtime); 172 | Serial.println(F(" micro secs/byte")); 173 | 174 | Serial.println(F("Random writes ...")); 175 | startmicros = micros(); 176 | for (eeaddr = 0; eeaddr <= MAXTESTADDR; eeaddr++) 177 | OK &= writeEEPROM(eeaddr,0x55); 178 | endmicros = micros(); 179 | Serial.print(F("Time: ")); 180 | avgtime = (endmicros-startmicros)/(MAXTESTADDR+1); 181 | Serial.print(avgtime); 182 | Serial.println(F(" micro secs/byte")); 183 | 184 | Serial.println(F("Page writes with wait ...")); 185 | startmicros = micros(); 186 | OK &= deleteEEPROM(0,MAXTESTADDR,0xFF,false); 187 | endmicros = micros(); 188 | Serial.print(F("Time: ")); 189 | avgtime = (endmicros-startmicros)/(MAXTESTADDR+1); 190 | Serial.print(avgtime); 191 | Serial.println(F(" micro secs/byte")); 192 | 193 | Serial.println(F("Page writes with poll ...")); 194 | startmicros = micros(); 195 | OK &= deleteEEPROM(0,MAXTESTADDR,0xFF,true); 196 | endmicros = micros(); 197 | Serial.print(F("Time: ")); 198 | avgtime = (endmicros-startmicros)/(MAXTESTADDR+1); 199 | Serial.print(avgtime); 200 | Serial.println(F(" micro secs/byte")); 201 | 202 | return OK; 203 | } 204 | //------------------------------------------------------------------------------ 205 | 206 | unsigned long parseHex() { 207 | unsigned long result = 0L; 208 | char inp = '\0'; 209 | byte val = 0; 210 | 211 | while (inp != '\r' && inp != '#') { 212 | while (!Serial.available()); 213 | inp = Serial.read(); 214 | if (inp == '\r' || inp == '#') break; 215 | if (inp >= 'a' && inp <= 'f') 216 | inp = inp -'a' + 'A'; 217 | if ((inp >= '0' && inp <= '9') || 218 | (inp >= 'A' && inp <= 'F')) { 219 | Serial.print(inp); 220 | if (inp >= '0' && inp <= '9') val = inp - '0'; 221 | else val = inp - 'A' + 10; 222 | result = result * 16; 223 | result = result + val; 224 | } 225 | } 226 | Serial.println(); 227 | return result; 228 | } 229 | 230 | void help (void) { 231 | Serial.println(); 232 | Serial.println(F("r - read byte from address")); 233 | Serial.println(F("w - write byte to address")); 234 | Serial.println(F("d - delete from start address to end address")); 235 | Serial.println(F("l - list memory range")); 236 | Serial.println(F("p - test performance")); 237 | Serial.println(F("h - help message")); 238 | Serial.println(F("Finish all numeric inputs with '#'")); 239 | } 240 | 241 | //------------------------------------------------------------------------------ 242 | 243 | 244 | 245 | void setup(void) { 246 | #if I2C_CPUFREQ == (F_CPU/8) 247 | CPUSlowDown(); 248 | Serial.begin(38400); 249 | 250 | #else 251 | Serial.begin(115200); 252 | #endif 253 | Serial.println(F("\n\nTest program for EEPROM 24AA1025 (SoftI2CMaster)")); 254 | help(); 255 | } 256 | 257 | 258 | void loop(void) { 259 | char cmd; 260 | uint8_t byte; 261 | boolean noterror; 262 | unsigned long addr, toaddr; 263 | 264 | while (!Serial.available()); 265 | cmd = Serial.read(); 266 | switch (cmd) { 267 | case 'r': Serial.print(F("Read from addr: ")); 268 | addr = parseHex(); 269 | Serial.println(F("Reading...")); 270 | noterror = readEEPROM(addr,&byte); 271 | Serial.print(addr,HEX); 272 | Serial.print(F(": ")); 273 | if (byte < 0x10) Serial.print("0"); 274 | Serial.println(byte,HEX); 275 | if (!noterror) Serial.println(F("Error while reading")); 276 | break; 277 | case 'w': 278 | Serial.print(F("Write to addr: ")); 279 | addr = parseHex(); 280 | Serial.print(F("Value: ")); 281 | byte = parseHex(); 282 | Serial.println(F("Writing...")); 283 | noterror = writeEEPROM(addr,byte); 284 | if (!noterror) Serial.println(F("Error while reading")); 285 | break; 286 | case 'd': 287 | Serial.print(F("Delete from addr: ")); 288 | addr = parseHex(); 289 | Serial.print(F("to addr: ")); 290 | toaddr = parseHex(); 291 | Serial.print(F("Value: ")); 292 | byte = parseHex(); 293 | Serial.print(F("Deleting ... ")); 294 | noterror = deleteEEPROM(addr,toaddr,byte,false); 295 | Serial.println(F("...done")); 296 | if (!noterror) Serial.println(F("Error while deleting")); 297 | break; 298 | case 'l': 299 | Serial.print(F("List from addr: ")); 300 | addr = parseHex(); 301 | Serial.print(F("to addr: ")); 302 | toaddr = parseHex(); 303 | while (addr <= toaddr) { 304 | noterror = readEEPROM(addr,&byte); 305 | Serial.print(addr,HEX); 306 | Serial.print(F(": ")); 307 | if (byte < 0x10) Serial.print("0"); 308 | Serial.println(byte,HEX); 309 | if (!noterror) Serial.println(F("Error while reading")); 310 | addr++; 311 | } 312 | break; 313 | case 'p': 314 | noterror = performanceTest(); 315 | if (!noterror) Serial.println(F("Error while executing performance test")); 316 | break; 317 | case 'h': 318 | help(); 319 | break; 320 | case '\r': 321 | case '\n': 322 | case ' ': 323 | break; 324 | default: 325 | Serial.println(F("Unknown command")); 326 | Serial.println(); 327 | help(); 328 | } 329 | } 330 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SoftI2CMaster 2 | 3 | [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) 4 | [![Installation instructions](https://www.ardu-badge.com/badge/SoftI2CMaster.svg?)](https://www.ardu-badge.com/SoftI2CMaster) 5 | [![Commits since latest](https://img.shields.io/github/commits-since/felias-fogg/SoftI2CMaster/latest)](https://github.com/felias-fogg/SoftI2CMaster/commits/master) 6 | [![Build Status](https://github.com/felias-fogg/SoftI2CMaster/workflows/LibraryBuild/badge.svg)](https://github.com/felias-fogg/SoftI2CMaster/actions) 7 | ![Hit Counter](https://visitor-badge.laobi.icu/badge?page_id=felias-fogg_SoftI2CMaster) 8 | 9 | ## Why another I2C library? 10 | 11 | The standard I2C library for the Arduino is the 12 | [Wire Library](http://arduino.cc/en/Reference/Wire). While this library is sufficient most of the time when you want to communicate 13 | with devices, there are situations when it is not applicable: 14 | 15 | * the I2C pins SDA/SCL are in use already for other purposes, 16 | * the code shall run on an ATtiny processor with 1 MHz on arbitrary pins, 17 | * you are short on memory (flash and RAM), or 18 | * you do not want to use the implicitly enabled pull-up resistors because your devices are run with 3.3 volts. 19 | 20 | I adapted [Peter Fleury's I2C software library](http://www.peterfleury.epizy.com/avr-software.html#libs) that is written in AVR assembler, extremely light weight (just under 500 byte in flash) and very fast. Even on an ATtiny running with 1MHz, one can still operate the 21 | bus with 33 kHz, which implies that you can drive slave devices that use the SMBus protocol (which timeout if the the bus frequency is below 10 kHz). 22 | 23 | If you want a solution running on an ARM MCU (Due, Zero, Teensy 3.x), you want to use pins on port H or above on an ATmega256, or you want to use many different I2C buses, this library is not the right solution for you. In these cases, another bit-banging I2C library written in pure C++ could perhaps help you: [SlowSoftI2CMaster](https://github.com/felias-fogg/SlowSoftI2CMaster). 24 | 25 | ## Features 26 | 27 | This library has the following features: 28 | 29 | * supports only master mode 30 | * compatible with all 8-bit AVR MCUs 31 | * no bus arbitration (i.e., only one master allowed on bus) 32 | * clock stretching (by slaves) supported 33 | * timeout on clock stretching 34 | * timeout on ACK polling for busy devices (new!) 35 | * internal MCU pullup resistors can be used (new!) 36 | * can make use of almost any pin (except for pins on port H and above on large ATmegas) 37 | * very lightweight (roughly 500 bytes of flash and 0 byte of RAM, except for call stack) 38 | * it is not interrupt-driven 39 | * very fast (standard and fast mode on ATmega328, 33 kHz on ATtiny 40 | with 1 MHz CPU clock) 41 | * can be easily used in multi-file projects (new) 42 | * Optional Wire library compatible interface 43 | * GPL license 44 | 45 | 46 | ## Installation 47 | 48 | The simplest way to install this library is to use the [library manager](https://docs.arduino.cc/software/ide-v1/tutorials/installing-libraries). Alternatively, one can download the 49 | [zip file from GitHub](https://github.com/felias-fogg/SoftI2CMaster), uncompress, rename the directory to SoftI2CMaster and move it into 50 | the libraries folder. 51 | 52 | ## Importing the library 53 | 54 | In order to use the library, you have to import it using the include 55 | statement: 56 | 57 | #include 58 | 59 | In the program text *before* the include statement, some compile-time parameters have to be specified, such as which pins are used for the data (SDA) and clock (SCL) lines. These pins have to be specified in a way so that [port manipulation commands](https://create.arduino.cc/projecthub/Hack-star-Arduino/learn-arduino-port-manipulation-2022-10f9af) 60 | can be used. Instead of specifying the number of the digital pin (0-19), the *port* (PORTB, PORTC, PORTD) and the *port pin* has to be specified. The mapping is explained [here](https://create.arduino.cc/projecthub/Hack-star-Arduino/learn-arduino-port-manipulation-2022-10f9af). For example, if you want to use *digital pin 2* for *SCL* and *digital pin 14* (= analog pin 0) for *SDA*, you have to specify *port pin 2 of PORTD* for SCL and *port pin 0 of PORTC* for SDA: 61 | 62 | #define SCL_PIN 2 63 | #define SCL_PORT PORTD 64 | #define SDA_PIN 0 65 | #define SDA_PORT PORTC 66 | #include 67 | 68 | ## Using the library in multi-file projects 69 | 70 | If you want to use the library in a larger project consisting of multiple cpp files, then you may wonder how the library should be imported. Since the header file contains all the source code, importing the library in more than one source file will lead to linkage errors. In order to support the usage of the library in such a context, ArminJo came up with the solution of using another compile time constant that controls of whether only the function declarations are imported. If you put the following compile time constant definition before the `#include` directive 71 | 72 | ```c++ 73 | #define USE_SOFT_I2C_MASTER_H_AS_PLAIN_INCLUDE 74 | ``` 75 | 76 | then only the function declarations are included. In other words, in such a large project, you once include the header file without this definition and all the other times, you have to put the above definition before the #include directive. 77 | 78 | ## Configuration 79 | 80 | There are a few other constants that you can define in order to 81 | control the behavior of the library. You have to specify them before 82 | the include statement so that they can take effect. Note 83 | that this is different from the usual form of using libraries! This library is 84 | always compiled with your sketch and therefore the defines 85 | need to be specified before the inclusion of the library! 86 | 87 | #define I2C_HARDWARE 1 88 | Although this is basically a bit-banging library, there is the 89 | possibility to use the hardware support for I2C, if you happen 90 | to run this library on an MCU such as the ATmega328 that implements this. If this constant is 91 | set to 1, then the hardware registers are used (and you have to 92 | use the standard SDA and SCL pins). 93 | 94 | #define I2C_PULLUP 1 95 | With this definition you enable the internal pullup resistors of the 96 | MCU. Note that the internal pullups have around 50kΩ, which may be 97 | too high. This slows down the bus speed somewhat. 98 | Furthermore, when switching from HIGH to 99 | LOW (or the other way around), the bus lines will temporarily in a high impedance 100 | state. With low I2C frequencies, things will 101 | probably work. However, be careful when using this option and better check with a 102 | scope that things work out. 103 | 104 | #define I2C_TIMEOUT ... 105 | Since slave devices can stretch the low period of the clock 106 | indefinitely, they can lock up the MCU. In order to avoid this, one 107 | can define I2C\_TIMEOUT. Specify the number of 108 | milliseconds after which the I2C functions will time out. Possible 109 | values are 0 (no time out) to 10000 (i.e., 10 seconds). Enabling this 110 | option slows done the bus speed somewhat. 111 | 112 | #define I2C_MAXWAIT ... 113 | When waiting for a busy device, one may use the function 114 | i2c\_start\_wait(addr) (see below), which sends start 115 | commands until the device responds with an ACK. If the 116 | value of this constant is different from 0, then it specifies the 117 | maximal number of start commands to be sent. Default value is 1000. 118 | 119 | #define I2C_NOINTERRUPT 1 120 | With this definition you disable interrupts between issuing a start 121 | condition and terminating the transfer with a stop condition. Usually, 122 | this is not necessary. However, if you have an SMbus device that can 123 | timeout, one may want to use this feature. Note however, that in this 124 | case interrupts become unconditionally disabled when calling 125 | i2c\_start(...) und unconditionally enabled after calling i2c\_stop(). 126 | 127 | #define I2C_CPUFREQ ... 128 | If you are changing the CPU frequency dynamically using the clock 129 | prescaler register CLKPR and intend to call the I2C functions with a 130 | frequency different from F_CPU, then define this constant with the 131 | correct frequency. For instance, if you used a prescale factor of 8, 132 | then the following definition would be adequate: #define I2C\_CPUFREQ (F\_CPU/8) 133 | 134 | #define I2C_FASTMODE 1 135 | The *standard I2C bus frequency* is 100kHz. Often, however, devices permit for faster transfers up to 400kHz. If you want to allow for the higher frequency, then the above definition should be used. 136 | 137 | #define I2C_SLOWMODE 1 138 | In case you want to slow down the clock frequency to less than 25kHz, you can use this 139 | definition (in this case, do not define 140 | I2C\_FASTMODE!). This can help to make the communication 141 | more reliable. 142 | 143 | I have measured the maximal bus frequency under different processor 144 | speeds. The results are displayed in the following 145 | table. The left value is with I2C\_TIMEOUT and 146 | I2C\_PULLUP disabled. The right value is the bus 147 | frequency with both options enabled. Note that there is a high 148 | clock jitter (roughly 10-15%) because the clock is implemented by delay 149 | loops. This is not a problem for the I2C bus, though. However, the 150 | throughput might be lower than one would expect from the numbers in 151 | the table. 152 | 153 | 154 | 157 | 158 | 159 | 160 | 163 | 164 | 167 | 168 | 171 |
1 MHz 2 MHz 4 156 | MHz 8 MHz16 MHz
Slow mode (kHz) 23 21 24 22 24 23 24 23 24 23
Standard mode (kHz) 165 | 45 33 90 72 95 83 95 89 90 88
Fast mode (kHz) 169 | 45 33 90 72 180 140 370 290 370 330
172 | 173 | ## Interface 174 | 175 | The following functions are provided by the library: 176 | 177 | i2c_init() 178 | Initialize the I2C system. Must be called once in 179 | setup. Will return false if SDA or SCL is on 180 | a low level, which means that the bus is locked. Otherwise returns 181 | true. 182 | 183 | i2c_start(addr) 184 | Initiates a transfer to the slave device with the 8-bit I2C address 185 | *addr*. Note that this library uses the 8-bit addressing 186 | scheme different from the 7-bit scheme in the Wire library. 187 | In addition the least significant bit of *addr* must be specified as 188 | I2C\_WRITE (=0) or I2C\_READ (=1). Returns 189 | true if the addressed device replies with an 190 | ACK. Otherwise false is returned. 191 | 192 | i2c_start_wait(addr) 193 | Similar to the i2c\_start function. However, it tries 194 | repeatedly to start the transfer until the device sends an 195 | acknowledge. It will timeout after I2C\_MAXWAIT failed 196 | attempts to contact the device (if this value is different from 0). By 197 | default, this value is 1000. 198 | 199 | i2c_rep_start(addr) 200 | Sends a repeated start condition, i.e., it starts a new transfer 201 | without sending first a stop condition. Same return value as 202 | i2c\_start(). 203 | 204 | i2c_stop() 205 | Sends a stop condition and thereby releases the bus. No return value. 206 | 207 | i2c_write(byte) 208 | Sends a byte to the previously addressed device. Returns 209 | true if the device replies with an ACK, otherwise false. 210 | 211 | i2c_read(last) 212 | Requests to receive a byte from the slave device. If last 213 | is true, then a NAK is sent after receiving 214 | the byte finishing the read transfer sequence. The function returns 215 | the received byte. 216 | 217 | ## Example 218 | 219 | As a small example, let us consider reading one register from an I2C 220 | device, with an address space < 256 (i.e. one byte for addressing) 221 | 222 | // Simple sketch to read out one register of an I2C device 223 | #define SDA_PORT PORTC 224 | #define SDA_PIN 4 // = A4 225 | #define SCL_PORT PORTC 226 | #define SCL_PIN 5 // = A5 227 | #include 228 | 229 | #define I2C_7BITADDR 0x68 // DS1307 230 | #define MEMLOC 0x0A 231 | 232 | void setup(void) { 233 | Serial.begin(57600); 234 | if (!i2c_init()) // Initialize everything and check for bus lockup 235 | Serial.println("I2C init failed"); 236 | } 237 | 238 | void loop(void){ 239 | if (!i2c_start((I2C_7BITADDR<<1)|I2C_WRITE)) { // start transfer 240 | Serial.println("I2C device busy"); 241 | return; 242 | } 243 | i2c_write(MEMLOC); // send memory address 244 | i2c_rep_start((I2C_7BITADDR<<1)|I2C_READ); // restart for reading 245 | byte val = i2c_read(true); // read one byte and send NAK to terminate 246 | i2c_stop(); // send stop condition 247 | Serial.println(val); 248 | delay(1000); 249 | } 250 | 251 | ## I2CShell 252 | 253 | In the example directory, you find a much more elaborate example: 254 | I2CShell. This sketch can be used to interact with I2C 255 | devices similar in the way you can use the Bus Pirate. For example, 256 | you can type: 257 | 258 | [ 0xAE 0 0 [ 0xAF r:5 ] 259 | 260 | This will address the I2C device under the (8-bit) address 0xAE in write 261 | mode, set the reading register to 0, then opens the same device again 262 | in read mode and read 5 registers. A complete documentation of this 263 | program can be found in the 264 | [I2CShell example folder](https://github.com/felias-fogg/SoftI2CMaster/tree/master/examples/I2CShell). 265 | 266 | ## Alternative Interface 267 | 268 | Meanwhile, I have written a wrapper around SoftI2CMaster that emulates 269 | the [Wire library](http://arduino.cc/en/Reference/Wire) (master mode only). It is another C++-header file called SoftWire.h, 270 | which you need to include instead of SoftI2CMaster.h. The ports and pins have to be specified as described above: 271 | 272 | #define SDA_PORT ... 273 | ... 274 | #include 275 | ... 276 | setup() { 277 | Wire.begin() 278 | ... 279 | } 280 | 281 | This interface sacrifices some of the advantages of the original 282 | library, in particular its small footprint, but comes handy if you 283 | need a replacement of the original *Wire* library. The following section 284 | sketches the memory footprint of different I2C libraries. 285 | 286 | There are a few constants that you can define in order to 287 | control the behavior of the library. You have to specify them before 288 | the include statement so that they can take effect. Note 289 | that this is different from the usual form of libraries! This library is 290 | always compiled with your sketch and therefore the defines 291 | need to be specified before the inclusion of the library! 292 | 293 | #define I2C_RX_BUFFER_LENGTH 48 294 | The default buffer length is 32 byte like in the standard Arduino Wire or TWI library. 295 | But if some I2C device sends more then 32 byte, you can use this definition to increase 296 | the receiver buffer size. 297 | 298 | Finally, you can use this wrapper library in multi-file projects. By putting the following directive 299 | 300 | ``` 301 | #define USE_SOFTWIRE_H_AS_PLAIN_INCLUDE 302 | ``` 303 | 304 | before including the library, only the declaration part is included. 305 | 306 | ## Memory requirements 307 | 308 | In order to measure the memory requirements of the different 309 | libraries, I wrote a baseline sketch, which contains all necessary I2C 310 | calls for reading and writing an EEPROM device, and compiled it 311 | against a library with empty functions. This sketch was compared to sketches that imported all the other libraries. For the Wire-like libraries, I had to rewrite the sketch, 312 | but it has the same functionality. The memory requirements differ 313 | somewhat from ATmega to ATtiny, but the overall picture is 314 | similar. The take-home message is: If you are short on memory (flash 315 | or RAM), it 316 | makes sense to use the SoftI2CMaster library. 317 | 318 | 319 | 320 | 325 | 330 | 335 | 340 | 345 |
ATmega328
LibrarySoftI2C-SoftI2C-SoftI2C-Soft-SlowSoft-SlowSoft-USI-Tiny-Wire
MasterMasterMasterWireI2CMasterWireWireWire
OptionPullup+TimeoutHardware
Flash48256443410669741556--1972
RAM00066470--210
346 | 347 | 348 | 349 | 354 | 359 | 364 | 369 | 374 |
ATtiny85
LibrarySoftI2C-SoftI2C-SoftI2C-Soft-SlowSoft-SlowSoft-USI-Tiny-Wire
MasterMasterMasterWireI2CMasterWireWireWire
OptionPullup+TimeoutHardware
Flash428510-1002732129211081834-
RAM00-664704586-
375 | 376 | 377 | ## Shortcomings 378 | 379 | One shortcoming is that one cannot use port H and above on an ATmega256. The reason is that these ports are not addressable as I/O registers. 380 | 381 | Another shortcoming is, as mentioned, that the code runs only on AVR MCUs (because it uses 382 | assembler). If you want to use a software I2C library on the ARM 383 | platform, you could use https://github.com/felias-fogg/SlowSoftI2CMaster, which uses only C++ code. Because of this, it is much slower, but on a Genuino/Arduino Zero, the I2C bus runs with roughly 100kHz. There is also a Wire-like wrapper available for this library: https://github.com/felias-fogg/SlowSoftWire. 384 | 385 | 386 | 387 | -------------------------------------------------------------------------------- /examples/I2CShell/I2CShell.ino: -------------------------------------------------------------------------------- 1 | // -*- c++ -*- 2 | /* I2CShell 3 | * This is a simple program acting as a shell to interact with I2C devices, using the 4 | * syntax from Bus Pirate. The difference to the Bus Pirate is that we only start 5 | * executing after everything has been typed in. Further, a line has to be closed by ']', i.e. 6 | * the stop condition. If it doesn't, we will add it. 7 | * You can use the Arduino serial monitor or a terminal window to interact. 8 | * 9 | * V 0.9 (08-FEB-18) 10 | * - first full version working with SoftI2CMaster 11 | * V 1.0 (10-Feb-18) 12 | * - numerous bug fixes 13 | * - dynamic changes of pullups and clock frequency 14 | * - storing macros in EEPROM 15 | * V 1.1 (11-Feb-18) 16 | * - line editing added 17 | * - documentation completed 18 | * V 1.2 (12-Feb-18) 19 | * - changed the implementation of kill-rest-of-line 20 | * - added line number for T-command 21 | * - allowed now for 700 kHz as the maximum bus clock; works perfect, but 22 | * you definitely need low pullup resistors, the internal ones won't 23 | * work at this speed. 24 | * - some cleanup for the T command 25 | * V 1.3 (10-Nov-21) 26 | * - removed some unused variables 27 | * - fixed a if-condition from (token = NUM_TOK) to (token == NUM_TOK) line 677 28 | */ 29 | 30 | #define VERSION "1.3" 31 | 32 | // Something you have to edit! 33 | #define USEEEPROM 1 34 | #define I2C_HARDWARE 0 35 | 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #define HELPSTRING "Commands:\r\n" \ 43 | "H - help S - scan I2C bus\r\n" \ 44 | "T - print last exec trace T - print 20 cmds starting at \r\n"\ 45 | "L - list macros L - list macro\r\n" \ 46 | "P - show status of pullups P - enable/disable(1/0) pullups\r\n" \ 47 | "F - show current I2C frequency F - set I2C frequency in kHz\r\n" \ 48 | "= - define macro [ ... - I2C interaction\r\n" \ 49 | "I2C interaction syntax:\r\n" \ 50 | "[ - (repeated) start condition { - start, polling for ACK\r\n" \ 51 | "] - stop condition r - read byte\r\n" \ 52 | " - address or write byte : - repeat previous times\r\n" \ 53 | "& - microsecond pause % - millisecond pause\r\n" \ 54 | "() - macro call\r\n" \ 55 | "Editing commands:\r\n"\ 56 | "^A, UP - Go to start of line ^B,LEFT - go one char to back\r\n"\ 57 | "^D - delete current char ^E,DOWN - go to end of line\r\n"\ 58 | "^F,RIGHT- go one char forward ^H, DEL - delete last character\r\n"\ 59 | "^K - kill rest of line ^P - retrieve previous line\r\n"\ 60 | "$ - insert macro into line\r\n"\ 61 | " is a single digit between 0 and 9. is any number in decimal, hex,\r\n"\ 62 | "octal or binary using the usual notation, e.g., 0xFF, 0o77, 0b11.\r\n" \ 63 | "? denotes a 7-bit I2C read address, ! a write address." \ 64 | 65 | 66 | // constants for the I2C interface 67 | #define I2C_TIMEOUT 100 68 | #define I2C_PULLUP 1 69 | 70 | #ifdef __AVR_ATmega328P__ 71 | /* Corresponds to A4/A5 - the hardware I2C pins on Arduinos */ 72 | #define SDA_PORT PORTC 73 | #define SDA_PIN 4 74 | #define SCL_PORT PORTC 75 | #define SCL_PIN 5 76 | #define I2C_FASTMODE 1 77 | #else 78 | #define SDA_PORT PORTB 79 | #define SDA_PIN 0 80 | #define SCL_PORT PORTB 81 | #define SCL_PIN 2 82 | #define I2C_FASTMODE 1 83 | #endif 84 | 85 | #include 86 | 87 | // constants for this program 88 | #define LINELEN 80 89 | #define MAXCMDS 300 90 | #define MACROS 5 // note: each macro needs LINELEN space 91 | 92 | // magic code for EEPROM 93 | #define MAGICKEY 0xA15A372FUL 94 | 95 | // start of saving area for macros 96 | #define EEMACSTART 4 97 | 98 | // error codes 99 | #define EXECOVF_ERR -1 100 | #define REPZERO_ERR -2 101 | #define ILLCH_ERR -3 102 | #define NUMTL_ERR -4 103 | #define ILLMAC_ERR -5 104 | #define WRGMACNUM_ERR -6 105 | #define DBLREP_ERR -7 106 | #define STRTREP_ERR -8 107 | #define NOADDR_ERR -9 108 | #define UNKNWN_ERR -10 109 | 110 | // exec type (cmds & results) 111 | typedef enum { START, REPSTART, WSTART, WREPSTART, 112 | WRITE, WRITE_ACK, WRITE_NAK, 113 | READ_ACK, READ_NAK, PAUSE, LPAUSE, STOP, EOC, LOOP } exec_t; 114 | 115 | // token types 116 | typedef enum { EOL_TOK, START_TOK, WSTART_TOK, STOP_TOK, NUM_TOK, READ_TOK, 117 | WAIT_TOK, LWAIT_TOK, REPEAT_TOK, MAC_TOK, UNDEF_TOK } token_t; 118 | 119 | // global variables 120 | char line[LINELEN*2+1] = { '\0' }; 121 | exec_t cmds[MAXCMDS] = { EOC }; 122 | byte vals[MAXCMDS]; 123 | char macroline[MACROS][LINELEN+1]; 124 | char illegal_char; 125 | long illegal_num; 126 | int i2cfreq = (I2C_FASTMODE ? 400 : (I2C_SLOWMODE ? 25 : 100)); 127 | bool i2cpullups = (I2C_PULLUP != 0); 128 | 129 | /* ---------------------------- Main program ------------------------*/ 130 | void setup() 131 | { 132 | Serial.begin(57600); 133 | Serial.println(F("\n\n\rI2C Shell Version " VERSION)); 134 | if (!i2c_init()) { 135 | Serial.println(F("I2C bus is locked up or there are no pullups!")); 136 | } 137 | for (byte i=0; i < MACROS; i++) macroline[i][0] = '\0'; 138 | #if USEEEPROM 139 | getMacrosEEPROM(); 140 | for (byte i=0; i < MACROS; i++) macroline[i][LINELEN] = '\0'; 141 | #endif 142 | } 143 | 144 | void loop() 145 | { 146 | int lineres, errpos; 147 | Serial.print(F("I2C>")); 148 | readLine(line); 149 | switch (toupper(line[0])) { 150 | case 'H': 151 | help(); 152 | return; 153 | case 'L': 154 | list(line[1]); 155 | return; 156 | case 'S': 157 | scan(); 158 | return; 159 | case 'T': 160 | report(line, cmds, vals); 161 | return; 162 | case 'P': 163 | pullups(line[1]); 164 | return; 165 | case 'F': 166 | frequency(line); 167 | return; 168 | } 169 | lineres = parseLine(line, cmds, vals, errpos); 170 | if (lineres == 0) { 171 | execute(cmds, vals); 172 | report("", cmds, vals); 173 | } else if (lineres > 0) { 174 | if (lineres-1 < MACROS) storeMacro(lineres-1, line); 175 | else { 176 | Serial.println(F("Macro index in definition too large:")); 177 | Serial.println(lineres-1); 178 | } 179 | } else { 180 | for (int i=0; i < errpos+3; i++) Serial.print(" "); 181 | Serial.println("^"); 182 | switch(lineres) { 183 | case EXECOVF_ERR: Serial.print(F("Too many commands")); 184 | break; 185 | case REPZERO_ERR: Serial.print(F("Repeat counter of 0 is not allowed")); 186 | break; 187 | case ILLCH_ERR: Serial.print(F("Unrecognized character: '")); 188 | Serial.print(illegal_char); 189 | Serial.print(F("'")); 190 | break; 191 | case NUMTL_ERR: Serial.print(F("Number too large: ")); 192 | Serial.print(illegal_num); 193 | break; 194 | case ILLMAC_ERR: Serial.print(F("Ill-formed macro call")); 195 | break; 196 | case WRGMACNUM_ERR: Serial.print(F("Macro number too large")); 197 | break; 198 | case DBLREP_ERR: Serial.print(F("Double repetition is not allwed")); 199 | break; 200 | case STRTREP_ERR: Serial.print(F("Start repetition is not allowed")); 201 | break; 202 | case NOADDR_ERR: Serial.print(F("No address after start condition")); 203 | break; 204 | default: Serial.print(F("Unrecogized parsing error")); 205 | break; 206 | } 207 | Serial.println(); 208 | cmds[0] = EOC; 209 | } 210 | } 211 | 212 | /* ---------------------------- Read line & editing ------------------------*/ 213 | 214 | 215 | 216 | // read one line until a CR/LF is entered, do not accept more than LINELEN chars 217 | // implement a few basic line editing commands 218 | bool readLine(char *buf) 219 | { 220 | char next = '\0'; 221 | int i = 0, fill = 0; 222 | 223 | while (next != '\r' && next != '\n') { 224 | while (!Serial.available()); 225 | next = Serial.read(); 226 | if (next == '\x1b') { // filter out ESC-sequences 227 | while (!Serial.available()); 228 | next = Serial.read(); 229 | if (next == '[') { 230 | while (!Serial.available()); 231 | next = 0; 232 | switch(Serial.read()) { 233 | case 'A': next = 'A'-0x40; 234 | break; 235 | case 'B': next = 'E'-0x40; 236 | break; 237 | case 'C': next = 'F'-0x40; 238 | break; 239 | case 'D': next = 'B'-0x40; 240 | } 241 | } 242 | } 243 | if ('0' <= next && next < '0' + MACROS && i > 0) 244 | if (buf[i-1] == '$') { 245 | insertMacro(line, i, fill, next-'0'); 246 | continue; 247 | } 248 | switch (next) { 249 | case '\x7F': 250 | case '\b': 251 | if (i > 0) { 252 | i--; 253 | Serial.write('\b'); 254 | deleteChar(buf, i, fill); 255 | } 256 | break; 257 | case 'A'-0x40: // ^A - start of line 258 | moveCursor(line, i, fill, 0); 259 | break; 260 | case 'B'-0x40: // ^B - one char backwards 261 | if (i > 0) moveCursor(line, i, fill, i-1); 262 | break; 263 | case 'D'-0x40: // ^D - delete current char 264 | deleteChar(buf, i, fill); 265 | break; 266 | case 'E'-0x40: // ^E - end of line 267 | moveCursor(line, i, fill, fill); 268 | break; 269 | case 'F'-0x40: // ^F - one character forward 270 | if (i < fill) moveCursor(line, i, fill, i+1); 271 | break; 272 | case 'K'-0x40: // ^K - kill rest of line 273 | killRest(buf, i, fill); 274 | break; 275 | case 'P'-0x40: // ^P - previous line 276 | if (i == 0) { 277 | Serial.print(buf); 278 | while (i < LINELEN && buf[i]) i++; 279 | fill = i; 280 | } 281 | break; 282 | default: 283 | if (next >= ' ' && next < '\x7F' && fill < LINELEN) { 284 | insertChar(buf, i, fill, next); 285 | } 286 | break; 287 | } 288 | } 289 | buf[fill] = '\0'; 290 | Serial.print("\r\n"); 291 | delay(50); 292 | while (Serial.available() && (Serial.peek() == '\r' || Serial.peek() == '\n')) Serial.read(); 293 | return true; 294 | } 295 | 296 | void moveCursor(char *line, int &cursor, int &fill, int target) 297 | { 298 | if (target < 0 || target > fill) return; 299 | if (target < cursor) { 300 | while (target < cursor) { 301 | Serial.write('\b'); 302 | cursor--; 303 | } 304 | } else { 305 | while (target > cursor) { 306 | Serial.write(line[cursor]); 307 | cursor++; 308 | } 309 | } 310 | } 311 | 312 | 313 | void deleteChar(char *line, int &cursor, int &fill) 314 | { 315 | int i; 316 | for (i = cursor; i < fill-1; i++) line[i] = line[i+1]; 317 | line[fill-1] = ' '; 318 | i = cursor; 319 | moveCursor(line, cursor, fill, fill); 320 | moveCursor(line, cursor, fill, i); 321 | fill--; 322 | } 323 | 324 | 325 | void killRest(char *line, int &cursor, int &fill) 326 | { 327 | int i; 328 | for (i = cursor; i <= fill-1; i++) line[i] = ' '; 329 | i = cursor; 330 | moveCursor(line, cursor, fill, fill); 331 | moveCursor(line, cursor, fill, i); 332 | fill = i; 333 | } 334 | 335 | void insertChar(char *line, int &cursor, int &fill, char newch) 336 | { 337 | int i; 338 | if (fill >= LINELEN) return; 339 | for (i = fill; i >= cursor; i--) line[i+1] = line[i]; 340 | line[cursor] = newch; 341 | fill++; 342 | i = cursor; 343 | moveCursor(line, cursor, fill, fill); 344 | moveCursor(line, cursor, fill, i+1); 345 | } 346 | 347 | void insertMacro(char *line, int &cursor, int &fill, int macid) 348 | { 349 | int i=0; 350 | moveCursor(line, cursor, fill, cursor-1); 351 | deleteChar(line, cursor, fill); 352 | while (macroline[macid][i] != '\0' && i < LINELEN) 353 | insertChar(line, cursor, fill, macroline[macid][i++]); 354 | } 355 | 356 | /* ---------------------------- Parsing input line ------------------------*/ 357 | 358 | 359 | int parseLine(char *buf, exec_t *cmds, byte *vals, int &lineix) 360 | { 361 | bool busreleased = true; 362 | int execix = 0; 363 | int result; 364 | 365 | lineix = 0; 366 | result = parseLineHelper(buf, cmds, vals, lineix, execix, busreleased, false); 367 | 368 | if (result >= 0) { 369 | execix = 0; 370 | while (cmds[execix] != EOC) { 371 | if (cmds[execix] == READ_ACK) 372 | if (stopFollows(cmds, execix+1)) 373 | cmds[execix] = READ_NAK; 374 | execix++; 375 | } 376 | } 377 | 378 | return result; 379 | } 380 | 381 | bool stopFollows(exec_t *cmds, int index) 382 | { 383 | while (cmds[index] == LOOP || cmds[index] == PAUSE) index++; 384 | if (cmds[index] == READ_ACK) return false; 385 | return true; 386 | } 387 | 388 | 389 | int parseLineHelper(char *buf, exec_t *cmds, byte *vals, int &lineix, int &execix, bool &busreleased, bool recursive) 390 | { 391 | token_t token = UNDEF_TOK, last = UNDEF_TOK, beforelast = UNDEF_TOK; 392 | long value = 0; 393 | int macindex = 0; 394 | int maclineix, maccall, repeat; 395 | exec_t cmd; 396 | 397 | if (buf[0] >= '0' && buf[0] <= '9' && buf[1] == '=') { // macro def 398 | macindex = buf[0] - '0' + 1; 399 | lineix = 2; 400 | } 401 | 402 | while (true) { 403 | beforelast = last; 404 | last = token; 405 | token = nextToken(buf, lineix, value); 406 | switch(token) { 407 | case EOL_TOK: 408 | if (recursive) return 0; 409 | if (!busreleased) { 410 | if (execix > MAXCMDS-2) return EXECOVF_ERR; 411 | cmds[execix++] = STOP; 412 | } else { 413 | if (execix > MAXCMDS-1) return EXECOVF_ERR; 414 | } 415 | cmds[execix++] = EOC; 416 | return macindex; 417 | case START_TOK: 418 | if (execix > MAXCMDS-3) return EXECOVF_ERR; // reserve one for EOC, one for STOP 419 | if (busreleased) cmds[execix++] = START; 420 | else cmds[execix++] = REPSTART; 421 | busreleased = false; 422 | break; 423 | case WSTART_TOK: 424 | if (execix > MAXCMDS-3) return EXECOVF_ERR; // reserve one for EOC, one for STOP 425 | if (busreleased) cmds[execix++] = WSTART; 426 | else cmds[execix++] = WREPSTART; 427 | busreleased = false; 428 | break; 429 | case STOP_TOK: 430 | if (execix > MAXCMDS-2) return EXECOVF_ERR; // reserve one for EOC 431 | cmds[execix++] = STOP; 432 | busreleased = true; 433 | break; 434 | case NUM_TOK: 435 | if (value < 0 || value > 255) { 436 | illegal_num = value; 437 | return NUMTL_ERR; 438 | } 439 | if (execix > 0) { 440 | if (cmds[execix-1] == LOOP && vals[execix-1] == 0) { 441 | if (value == 0) { 442 | return REPZERO_ERR; 443 | } else { 444 | vals[execix-1] = value; 445 | value = -1; 446 | } 447 | } 448 | } 449 | if (value >= 0) { 450 | if (execix > MAXCMDS-3) return EXECOVF_ERR; // reserve one for EOC, one for STOP 451 | cmds[execix] = WRITE; 452 | vals[execix++] = value; 453 | } 454 | break; 455 | case READ_TOK: 456 | if (execix > MAXCMDS-3) return EXECOVF_ERR; // reserve one for EOC, one for STOP 457 | cmds[execix++] = READ_ACK; 458 | break; 459 | case WAIT_TOK: 460 | if (execix > MAXCMDS-3) return EXECOVF_ERR; // reserve one for EOC, one for STOP 461 | cmds[execix++] = PAUSE; 462 | break; 463 | case LWAIT_TOK: 464 | if (execix > MAXCMDS-3) return EXECOVF_ERR; // reserve one for EOC, one for STOP 465 | cmds[execix++] = LPAUSE; 466 | break; 467 | case REPEAT_TOK: 468 | if (execix > MAXCMDS-3) return EXECOVF_ERR; // reserve one for EOC, one for STOP 469 | if (execix > 0) { 470 | if (cmds[execix-1] == LOOP || beforelast == REPEAT_TOK) return DBLREP_ERR; 471 | if (cmds[execix-1] == START) return STRTREP_ERR; 472 | if (cmds[execix-1] == REPSTART) return STRTREP_ERR; 473 | } 474 | cmds[execix] = LOOP; 475 | vals[execix++] = 0; 476 | break; 477 | case MAC_TOK: 478 | maclineix = 0; 479 | if (value >= MACROS) return WRGMACNUM_ERR; 480 | maccall = parseLineHelper(macroline[value], cmds, vals, maclineix, execix, busreleased, true); 481 | if (maccall < 0) return maccall; 482 | break; 483 | case UNDEF_TOK: 484 | return ILLCH_ERR; 485 | break; 486 | default: 487 | return UNKNWN_ERR; 488 | break; 489 | } 490 | if (execix >= 2 && cmds[execix-1] == LOOP && vals[execix-1] > 0 && 491 | (cmds[execix-2] == READ_ACK || cmds[execix-2] == WRITE)) { 492 | // unfold read and write commands! 493 | repeat = vals[execix-1]; 494 | cmd = cmds[execix-2]; 495 | value = vals[execix-2]; 496 | execix--; 497 | if (execix + repeat - 1 > MAXCMDS-3) return EXECOVF_ERR; 498 | for (byte i=0; i= 2 && (cmds[execix-2] == START || cmds[execix-2] == REPSTART) && 504 | cmds[execix-1] != WRITE) 505 | return NOADDR_ERR; 506 | } 507 | } 508 | 509 | token_t nextToken(char *buf, int &i, long &value) 510 | { 511 | char nextch; 512 | token_t token; 513 | value = 0; 514 | while (buf[i] == ' ' || buf[i] == '\t' || buf[i] == ',') i++; 515 | nextch = toupper(buf[i]); 516 | if (nextch >= '0' && nextch <= '9') token = NUM_TOK; 517 | else { 518 | switch(nextch) { 519 | case '\0': token = EOL_TOK; break; 520 | case '[': token = START_TOK; break; 521 | case '{': token = WSTART_TOK; break; 522 | case ']': token = STOP_TOK; break; 523 | case 'R': token = READ_TOK; break; 524 | case '&': token = WAIT_TOK; break; 525 | case '%': token = LWAIT_TOK; break; 526 | case ':': token = REPEAT_TOK; break; 527 | case '(': token = MAC_TOK; break; 528 | default: token = UNDEF_TOK; illegal_char = buf[i]; break; 529 | } 530 | } 531 | if (token == NUM_TOK) value = parseNum(buf, i); 532 | else if (token == MAC_TOK) value = parseMac(buf, i); 533 | else i++; 534 | return token; 535 | } 536 | 537 | long parseNum(char *buf, int &i) 538 | { 539 | long result = 0; 540 | byte base = 10; 541 | 542 | if (buf[i] == '0') { 543 | switch (toupper(buf[i+1])) { 544 | case 'X': 545 | base = 16; 546 | i += 2; 547 | break; 548 | case 'O': 549 | base = 8; 550 | i += 2; 551 | break; 552 | case 'B': 553 | base = 2; 554 | i += 2; 555 | break; 556 | } 557 | } 558 | while (conv2digit(buf[i]) < base) 559 | result = result*base + conv2digit(buf[i++]); 560 | if (buf[i] == '?' || buf[i] == '!') 561 | result = (result<<1) + ((buf[i++] == '?') ? 1 : 0); 562 | return result; 563 | } 564 | 565 | byte conv2digit(char c) 566 | { 567 | if ('0' <= c && c <= '9') return c - '0'; 568 | else if ('A' <= toupper(c) && toupper(c) <= 'F') return toupper(c) - 'A' + 10; 569 | else return 255; 570 | } 571 | 572 | int parseMac(char *buf, int &i) 573 | { 574 | if (buf[i+1] < '0' || buf[i+1] > '9' || buf[i+2] != ')') return ILLMAC_ERR; 575 | i += 3; 576 | return (buf[i-2] - '0'); 577 | } 578 | 579 | 580 | /* ---------------------------- Execution & reporting ------------------------*/ 581 | 582 | 583 | void execute(exec_t *cmds, byte *vals) 584 | { 585 | int i = 0; 586 | bool ack; 587 | while (true) { 588 | switch(cmds[i]) { 589 | case START: 590 | i++; 591 | if (cmds[i] == WRITE) { 592 | ack = i2c_start(vals[i]); 593 | cmds[i++] = (ack ? WRITE_ACK : WRITE_NAK); 594 | } 595 | break; 596 | case REPSTART: 597 | i++; 598 | if (cmds[i] == WRITE) { 599 | ack = i2c_rep_start(vals[i]); 600 | cmds[i++] = (ack ? WRITE_ACK : WRITE_NAK); 601 | } 602 | break; 603 | case WSTART: 604 | i++; 605 | if (cmds[i] == WRITE) { 606 | vals[i-1] = 0; 607 | ack = false; 608 | while (vals[i-1] < 255 && !ack) { 609 | ack = i2c_start(vals[i]); 610 | if (!ack) i2c_stop(); 611 | vals[i-1]++; 612 | } 613 | vals[i-1]--; 614 | cmds[i++] = (ack ? WRITE_ACK : WRITE_NAK); 615 | } 616 | break; 617 | case WREPSTART: 618 | i++; 619 | if (cmds[i] == WRITE) { 620 | vals[i-1] = 0; 621 | ack = false; 622 | while (vals[i-1] < 255 && !ack) { 623 | ack = i2c_rep_start(vals[i]); 624 | if (!ack) i2c_stop(); 625 | vals[i-1]++; 626 | } 627 | vals[i-1]--; 628 | cmds[i++] = (ack ? WRITE_ACK : WRITE_NAK); 629 | } 630 | break; 631 | case WRITE: 632 | ack = i2c_write(vals[i]); 633 | cmds[i++] = (ack ? WRITE_ACK : WRITE_NAK); 634 | break; 635 | case READ_ACK: 636 | vals[i++] = i2c_read(false); 637 | break; 638 | case READ_NAK: 639 | vals[i++] = i2c_read(true); 640 | break; 641 | case PAUSE: 642 | i++; 643 | if (cmds[i] == LOOP) delayMicroseconds(vals[i++]); 644 | else delayMicroseconds(1); 645 | break; 646 | case LPAUSE: 647 | i++; 648 | if (cmds[i] == LOOP) delay(vals[i++]); 649 | else delay(1); 650 | break; 651 | case STOP: 652 | i++; 653 | if (cmds[i] == LOOP) { 654 | for (byte i=0; i < vals[i]; i++) { 655 | i2c_stop(); 656 | delayMicroseconds(1); 657 | } 658 | i++; 659 | } else i2c_stop(); 660 | break; 661 | case LOOP: 662 | break; 663 | case EOC: 664 | delay(200); // decouple from console output! 665 | return; 666 | } 667 | } 668 | } 669 | 670 | void report(char *line, exec_t *cmds, byte *vals) 671 | { 672 | int i = 0; 673 | bool nostart; 674 | int startline = 0; 675 | int stopline = 0; 676 | long val; 677 | int ix = 1; 678 | token_t token; 679 | if (strlen(line) > 1) { 680 | token = nextToken(line, ix, val); 681 | if (token == NUM_TOK) { 682 | startline = val; 683 | stopline = startline + 19; 684 | } 685 | } 686 | while (true) { 687 | if (i >= startline && (i <= stopline || stopline == 0)) { 688 | switch(cmds[i]) { 689 | case START: 690 | Serial.print(F("Start: ")); 691 | break; 692 | case REPSTART: 693 | Serial.print(F("Rep. start: ")); 694 | break; 695 | case WSTART: 696 | Serial.print(F("Start (")); 697 | Serial.print(vals[i]); 698 | Serial.print(F(" NAKs): ")); 699 | break; 700 | case WREPSTART: 701 | Serial.print(F("Rep. start (")); 702 | Serial.print(vals[i]); 703 | Serial.print(F(" NAKs): ")); 704 | break; 705 | case WRITE_ACK: 706 | case WRITE_NAK: 707 | nostart = false; 708 | if (i == 0 || (cmds[i-1] != START && cmds[i-1] != REPSTART && cmds[i-1] != WSTART && cmds[i-1] != WREPSTART)) { 709 | Serial.print(F("Write: ")); 710 | nostart = true; 711 | } 712 | Serial.print(F("0x")); 713 | if (vals[i] < 0x10) Serial.print(0); 714 | Serial.print(vals[i], HEX); 715 | if (!nostart) { 716 | Serial.print(F(" (0x")); 717 | if ((vals[i]>>1) < 0x10) Serial.print(0); 718 | Serial.print((vals[i]>>1), HEX); 719 | Serial.print(((vals[i])%2 == 0 ? "!" : "?")); 720 | Serial.print(F(")")); 721 | } 722 | Serial.println(((cmds[i] == WRITE_ACK ? " + ACK" : " + NAK"))); 723 | break; 724 | case READ_ACK: 725 | case READ_NAK: 726 | Serial.print(F("Read: 0x")); 727 | if (vals[i] < 0x10) Serial.print(0); 728 | Serial.print(vals[i], HEX); 729 | Serial.println(((cmds[i] == READ_ACK ? " + ACK" : " + NAK"))); 730 | break; 731 | case LPAUSE: 732 | case PAUSE: 733 | if (cmds[i] == PAUSE) 734 | Serial.print(F("msec delay")); 735 | else 736 | Serial.print(F("\u03BC" "sec delay")); 737 | if (cmds[i+1] == LOOP) { 738 | Serial.print(F(": ")); 739 | Serial.print(vals[i+1]); 740 | Serial.print(F(" repetitions")); 741 | } 742 | Serial.println(); 743 | break; 744 | case STOP: 745 | Serial.print(F("Stop")); 746 | if (cmds[i+1] == LOOP) { 747 | Serial.print(F(": ")); 748 | Serial.print(vals[i+1]); 749 | Serial.print(F(" repetitions")); 750 | } 751 | Serial.println(); 752 | break; 753 | case EOC: 754 | return; 755 | break; 756 | } 757 | } 758 | if (cmds[i++] == EOC) return; 759 | } 760 | } 761 | 762 | /* ---------------------------- Shell commands ------------------------*/ 763 | 764 | 765 | void storeMacro(int macnum, char *line) 766 | { 767 | strncpy(macroline[macnum], &(line[2]), LINELEN+1); 768 | #if USEEEPROM 769 | putMacrosEEPROM(); 770 | #endif 771 | } 772 | 773 | 774 | void list(char index) 775 | { 776 | byte i = index - '0'; 777 | if (i >= 0 && i < MACROS) { 778 | Serial.print(i); 779 | Serial.print(F("=")); 780 | Serial.println(macroline[i]); 781 | } else { 782 | for (i=0; i < MACROS; i++) { 783 | Serial.print(i); 784 | Serial.print(F("=")); 785 | Serial.println(macroline[i]); 786 | } 787 | } 788 | } 789 | 790 | 791 | void help() { 792 | Serial.println(F("\nI2C Shell Version " VERSION)); 793 | Serial.println(F(HELPSTRING)); 794 | } 795 | 796 | 797 | 798 | void scan() 799 | { 800 | Serial.println(F("Scanning ...")); 801 | Serial.println(F(" 8-bit 7-bit addr")); 802 | for (int addr = 0; addr < 256; addr = addr+1) { 803 | if (i2c_start(addr)) { 804 | if (addr%2 == 0) i2c_write(0); 805 | else i2c_read(true); 806 | i2c_stop(); 807 | Serial.print(F(" 0x")); 808 | if (addr <= 0xF) Serial.print(0); 809 | Serial.print(addr,HEX); 810 | Serial.print(F(" 0x")); 811 | if (addr>>1 <= 0xF) Serial.print(0); 812 | Serial.print((addr>>1),HEX); 813 | Serial.println((addr%2 == 0 ? "!" : "?")); 814 | delay(200); // 815 | } else i2c_stop(); 816 | } 817 | } 818 | 819 | void pullups(char arg) 820 | { 821 | if (arg == '\0') { 822 | Serial.print(F("Pullups are currently ")); 823 | if (i2cpullups) Serial.println(F("enabled")); 824 | else Serial.println(F("disabled")); 825 | return; 826 | } 827 | #if I2C_HARDWARE 828 | if (arg == '1') { // enable pullups 829 | digitalWrite(SDA, 1); 830 | digitalWrite(SCL, 1); 831 | Serial.println(F("Pullups enabled")); 832 | } else if (arg == '0') { // disable pullups 833 | digitalWrite(SDA, 0); 834 | digitalWrite(SCL, 0); 835 | Serial.println(F("Pullups disabled")); 836 | } else { 837 | Serial.println(F("Specify 0 or 1 with P command or append nothing")); 838 | } 839 | #else 840 | Serial.println(F("Set I2C_HARDWARE constant to 1 in sketch")); 841 | Serial.println(F("when you want to change pullups dynamically")); 842 | #endif 843 | } 844 | 845 | void frequency(char *line) 846 | { 847 | token_t token; 848 | long value; 849 | int ix = 1; 850 | #if I2C_HARDWARE 851 | int bitrate; 852 | #endif 853 | 854 | token = nextToken(line, ix, value); 855 | if (token != NUM_TOK) { 856 | Serial.print(F("I2C clock frequency is ")); 857 | Serial.print(i2cfreq); 858 | Serial.println(F(" kHz")); 859 | return; 860 | } 861 | #if I2C_HARDWARE 862 | if (value < 1 || value > 700) { 863 | Serial.println(F("Cannot set I2C clock frequency lower than 1 or higher than 700 kHz")); 864 | return; 865 | } 866 | i2cfreq = value; 867 | bitrate = (I2C_CPUFREQ/(value*1000UL)-16)/2; 868 | if (bitrate < 3) { 869 | Serial.println(F("Requested frequency is to high!")); 870 | return; 871 | } 872 | Serial.print(F("I2C clock frequency set to ")); 873 | Serial.print(i2cfreq); 874 | Serial.println(F(" kHz")); 875 | if (bitrate <= 255) { 876 | TWSR = 0; 877 | TWBR = bitrate; 878 | return; 879 | } 880 | bitrate = bitrate/4; 881 | if (bitrate <= 255) { 882 | TWSR = (1< 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS -------------------------------------------------------------------------------- /src/SoftI2CMaster.h: -------------------------------------------------------------------------------- 1 | /* Arduino SoftI2C library. 2 | * 3 | * Version 2.1.8 4 | * 5 | * Copyright (C) 2013-2021, Bernhard Nebel and Peter Fleury 6 | * 7 | * This is a very fast and very light-weight software I2C-master library 8 | * written in assembler. It is based on Peter Fleury's I2C software 9 | * library: http://homepage.hispeed.ch/peterfleury/avr-software.html 10 | * Recently, the hardware implementation has been added to the code, 11 | * which can be enabled by defining I2C_HARDWARE. 12 | * 13 | * This file is part of SoftI2CMaster https://github.com/felias-fogg/SoftI2CMaster. 14 | * 15 | * This Library is free software: you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation, either version 3 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * This Library is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with the Arduino I2cMaster Library. If not, see 27 | * . 28 | */ 29 | 30 | /* In order to use the library, you need to define SDA_PIN, SCL_PIN, 31 | * SDA_PORT and SCL_PORT before including this file. Have a look at 32 | * http://www.arduino.cc/en/Reference/PortManipulation for finding out 33 | * which values to use. For example, if you use digital pin 3 (corresponding 34 | * to PD3) for SDA and digital pin 13 (corresponding to PB5) 35 | * for SCL on a standard Arduino, 36 | * you have to use the following definitions: 37 | * #define SDA_PIN 3 38 | * #define SDA_PORT PORTD 39 | * #define SCL_PIN 5 40 | * #define SCL_PORT PORTB 41 | * 42 | * Alternatively, you can define the compile time constant I2C_HARDWARE, 43 | * in which case the TWI hardware is used. In this case you have to use 44 | * the standard SDA/SCL pins (and, of course, the chip needs to support 45 | * this). 46 | * 47 | * You can also define the following constants (see also below): 48 | ' - I2C_PULLUP = 1 meaning that internal pullups should be used 49 | * - I2C_CPUFREQ, when changing CPU clock frequency dynamically 50 | * - I2C_FASTMODE = 1 meaning that the I2C bus allows speeds up to 400 kHz 51 | * - I2C_SLOWMODE = 1 meaning that the I2C bus will allow only up to 25 kHz 52 | * - I2C_NOINTERRUPT = 1 in order to prohibit interrupts while 53 | * communicating (see below). This can be useful if you use the library 54 | * for communicating with SMbus devices, which have timeouts. 55 | * Note, however, that interrupts are disabled from issuing a start condition 56 | * until issuing a stop condition. So use this option with care! 57 | * - I2C_TIMEOUT = 0..10000 msec in order to return from the I2C functions 58 | * in case of a I2C bus lockup (i.e., SCL constantly low). 0 means no timeout. 59 | * - I2C_MAXWAIT = 0..32767 number of retries in i2c_start_wait. 0 means never stop. 60 | */ 61 | 62 | /* Changelog: 63 | * * Version 2.1.8 64 | * - ArminJo: Included MACRO USE_SOFT_I2C_MASTER_H_AS_PLAIN_INCLUDE 65 | * Version 2.1.7 66 | * - ArminJo: replaced all calls and jmps by rcalls and rjmps for CPUs not having call and jmp 67 | * Version 2.1.6 68 | * - adapted SlowSoftWire to make it comparable to SlowSoftI2C (and a few other minor things) 69 | * Version 2.1.5 70 | * - replaced all rcalls and rjmps by calls and jmps 71 | * Version 2.1.4 72 | * - fixed bug in Softwire conerning repeated starts 73 | * Version 2.1.3 74 | * - removed WireEmu and fixed bug in Eeprom24AA1025SoftI2C.ino 75 | * Version 2.1 76 | * - added conditional to check whether it is the right MCU type 77 | * Version 2.0 78 | * - added hardware support as well. 79 | * Version 1.4: 80 | * - added "maximum retry" in i2c_start_wait in order to avoid lockup 81 | * - added "internal pullups", but be careful since the option stretches the I2C specs 82 | * Version 1.3: 83 | * - added "__attribute__ ((used))" for all functions declared with "__attribute__ ((noinline))" 84 | * Now the module is also usable in Arduino 1.6.11+ 85 | * Version 1.2: 86 | * - added pragma to avoid "unused parameter warnings" (suggestion by Walter) 87 | * - replaced wrong license file 88 | * Version 1.1: 89 | * - removed I2C_CLOCK_STRETCHING 90 | * - added I2C_TIMEOUT time in msec (0..10000) until timeout or 0 if no timeout 91 | * - changed i2c_init to return true if and only if both SDA and SCL are high 92 | * - changed interrupt disabling so that the previous IRQ state is restored 93 | * Version 1.0: basic functionality 94 | */ 95 | 96 | #ifndef __AVR_ARCH__ 97 | #error "Not an AVR MCU! Use 'SlowSoftI2CMaster' library instead of 'SoftI2CMaster'!" 98 | #else 99 | 100 | #ifndef _SOFTI2C_HPP 101 | #define _SOFTI2C_HPP 1 102 | 103 | #include 104 | #include 105 | #include 106 | 107 | // Init function. Needs to be called once in the beginning. 108 | // Returns false if SDA or SCL are low, which probably means 109 | // a I2C bus lockup or that the lines are not pulled up. 110 | bool __attribute__ ((noinline)) i2c_init(void) __attribute__ ((used)); 111 | 112 | // Start transfer function: is the 8-bit I2C address (including the R/W 113 | // bit). 114 | // Return: true if the slave replies with an "acknowledge", false otherwise 115 | bool __attribute__ ((noinline)) i2c_start(uint8_t addr) __attribute__ ((used)); 116 | 117 | // Similar to start function, but wait for an ACK! Will timeout if I2C_MAXWAIT > 0. 118 | bool __attribute__ ((noinline)) i2c_start_wait(uint8_t addr) __attribute__ ((used)); 119 | 120 | // Repeated start function: After having claimed the bus with a start condition, 121 | // you can address another or the same chip again without an intervening 122 | // stop condition. 123 | // Return: true if the slave replies with an "acknowledge", false otherwise 124 | bool __attribute__ ((noinline)) i2c_rep_start(uint8_t addr) __attribute__ ((used)); 125 | 126 | // Issue a stop condition, freeing the bus. 127 | void __attribute__ ((noinline)) i2c_stop(void) asm("ass_i2c_stop") __attribute__ ((used)); 128 | 129 | // Write one byte to the slave chip that had been addressed 130 | // by the previous start call. is the byte to be sent. 131 | // Return: true if the slave replies with an "acknowledge", false otherwise 132 | bool __attribute__ ((noinline)) i2c_write(uint8_t value) asm("ass_i2c_write") __attribute__ ((used)); 133 | 134 | // Read one byte. If is true, we send a NAK after having received 135 | // the byte in order to terminate the read sequence. 136 | uint8_t __attribute__ ((noinline)) i2c_read(bool last) __attribute__ ((used)); 137 | 138 | #if !defined(USE_SOFT_I2C_MASTER_H_AS_PLAIN_INCLUDE) 139 | /* 140 | * The implementation part of the header only library starts here 141 | */ 142 | #pragma GCC diagnostic push 143 | 144 | #pragma GCC diagnostic ignored "-Wunused-parameter" 145 | 146 | // If you want to use the TWI hardware, you have to define I2C_HARDWARE to be 1 147 | #ifndef I2C_HARDWARE 148 | #define I2C_HARDWARE 0 149 | #endif 150 | 151 | #if I2C_HARDWARE 152 | #ifndef TWDR 153 | #error This chip does not support hardware I2C. Please undefine I2C_HARDWARE 154 | #endif 155 | #endif 156 | 157 | // You can set I2C_CPUFREQ independently of F_CPU if you 158 | // change the CPU frequency on the fly. If you do not define it, 159 | // it will use the value of F_CPU 160 | #ifndef I2C_CPUFREQ 161 | #define I2C_CPUFREQ F_CPU 162 | #endif 163 | 164 | // If I2C_FASTMODE is set to 1, then the highest possible frequency below 400kHz 165 | // is selected. Be aware that not all slave chips may be able to deal with that! 166 | #ifndef I2C_FASTMODE 167 | #define I2C_FASTMODE 0 168 | #endif 169 | 170 | // If I2C_FASTMODE is not defined or defined to be 0, then you can set 171 | // I2C_SLOWMODE to 1. In this case, the I2C frequency will not be higher 172 | // than 25KHz. This could be useful for problematic buses with high pull-ups 173 | // and high capacitance. 174 | #ifndef I2C_SLOWMODE 175 | #define I2C_SLOWMODE 0 176 | #endif 177 | 178 | // If I2C_PULLUP is set to 1, then the internal pull-up resistors are used. 179 | // This does not conform with the I2C specs, since the bus lines will be 180 | // temporarily in high-state and the internal resistors have roughly 50k. 181 | // With low bus speeds und short buses it usually works, though (hopefully). 182 | #ifndef I2C_PULLUP 183 | #define I2C_PULLUP 0 184 | #endif 185 | 186 | // if I2C_NOINTERRUPT is 1, then the I2C routines are not interruptible. 187 | // This is most probably only necessary if you are using a 1MHz system clock, 188 | // you are communicating with a SMBus device, and you want to avoid timeouts. 189 | // Be aware that the interrupt bit is enabled after each call. So the 190 | // I2C functions should not be called in interrupt routines or critical regions. 191 | #ifndef I2C_NOINTERRUPT 192 | #define I2C_NOINTERRUPT 0 193 | #endif 194 | 195 | // I2C_TIMEOUT can be set to a value between 1 and 10000. 196 | // If it is defined and nonzero, it leads to a timeout if the 197 | // SCL is low longer than I2C_TIMEOUT milliseconds, i.e., max timeout is 10 sec 198 | #ifndef I2C_TIMEOUT 199 | #define I2C_TIMEOUT 0 200 | #else 201 | #if I2C_TIMEOUT > 10000 202 | #error I2C_TIMEOUT is too large 203 | #endif 204 | #endif 205 | 206 | // I2C_MAXWAIT can be set to any value between 0 and 32767. 0 means no time out. 207 | #ifndef I2C_MAXWAIT 208 | #define I2C_MAXWAIT 500 209 | #else 210 | #if I2C_MAXWAIT > 32767 || I2C_MAXWAIT < 0 211 | #error Illegal I2C_MAXWAIT value 212 | #endif 213 | #endif 214 | 215 | #define I2C_TIMEOUT_DELAY_LOOPS (I2C_CPUFREQ/1000UL)*I2C_TIMEOUT/4000UL 216 | #if I2C_TIMEOUT_DELAY_LOOPS < 1 217 | #define I2C_MAX_STRETCH 1 218 | #else 219 | #if I2C_TIMEOUT_DELAY_LOOPS > 60000UL 220 | #define I2C_MAX_STRETCH 60000UL 221 | #else 222 | #define I2C_MAX_STRETCH I2C_TIMEOUT_DELAY_LOOPS 223 | #endif 224 | #endif 225 | 226 | #if I2C_FASTMODE 227 | #define I2C_DELAY_COUNTER (((I2C_CPUFREQ/350000L)/2-18)/3) 228 | #define SCL_CLOCK 400000UL 229 | #else 230 | #if I2C_SLOWMODE 231 | #define I2C_DELAY_COUNTER (((I2C_CPUFREQ/23500L)/2-18)/3) 232 | #define SCL_CLOCK 25000UL 233 | #else 234 | #define I2C_DELAY_COUNTER (((I2C_CPUFREQ/90000L)/2-18)/3) 235 | #define SCL_CLOCK 100000UL 236 | #endif 237 | #endif 238 | 239 | // constants for reading & writing 240 | #define I2C_READ 1 241 | #define I2C_WRITE 0 242 | 243 | #if !I2C_HARDWARE 244 | // map the IO register back into the IO address space 245 | #define SDA_DDR (_SFR_IO_ADDR(SDA_PORT) - 1) 246 | #define SCL_DDR (_SFR_IO_ADDR(SCL_PORT) - 1) 247 | #define SDA_OUT _SFR_IO_ADDR(SDA_PORT) 248 | #define SCL_OUT _SFR_IO_ADDR(SCL_PORT) 249 | #define SDA_IN (_SFR_IO_ADDR(SDA_PORT) - 2) 250 | #define SCL_IN (_SFR_IO_ADDR(SCL_PORT) - 2) 251 | 252 | #ifndef __tmp_reg__ 253 | #define __tmp_reg__ 0 254 | #endif 255 | 256 | // Internal delay functions. 257 | void __attribute__ ((noinline)) i2c_delay_half(void) asm("ass_i2c_delay_half") __attribute__ ((used)); 258 | void __attribute__ ((noinline)) i2c_wait_scl_high(void) asm("ass_i2c_wait_scl_high") __attribute__ ((used)); 259 | 260 | void i2c_delay_half(void) 261 | { // function call 3 cycles => 3C 262 | #if I2C_DELAY_COUNTER < 1 263 | __asm__ __volatile__ (" ret"); 264 | // 7 cycles for call and return 265 | #else 266 | __asm__ __volatile__ 267 | ( 268 | " ldi r25, %[DELAY] ;load delay constant ;; 4C \n\t" 269 | "_Lidelay: \n\t" 270 | " dec r25 ;decrement counter ;; 4C+xC \n\t" 271 | " brne _Lidelay ;;5C+(x-1)2C+xC\n\t" 272 | " ret ;; 9C+(x-1)2C+xC = 7C+xC" 273 | : : [DELAY] "M" I2C_DELAY_COUNTER : "r25"); 274 | // 7 cycles + 3 times x cycles 275 | #endif 276 | } 277 | 278 | void i2c_wait_scl_high(void) 279 | { 280 | #if I2C_TIMEOUT <= 0 281 | __asm__ __volatile__ 282 | ("_Li2c_wait_stretch: \n\t" 283 | " sbis %[SCLIN],%[SCLPIN] ;wait for SCL high \n\t" 284 | #if __AVR_HAVE_JMP_CALL__ 285 | " jmp _Li2c_wait_stretch \n\t" 286 | #else 287 | " rjmp _Li2c_wait_stretch \n\t" 288 | #endif 289 | " cln ;signal: no timeout \n\t" 290 | " ret " 291 | : : [SCLIN] "I" (SCL_IN), [SCLPIN] "I" (SCL_PIN)); 292 | #else 293 | __asm__ __volatile__ 294 | ( " ldi r27, %[HISTRETCH] ;load delay counter \n\t" 295 | " ldi r26, %[LOSTRETCH] \n\t" 296 | "_Lwait_stretch: \n\t" 297 | " clr __tmp_reg__ ;do next loop 255 times \n\t" 298 | "_Lwait_stretch_inner_loop: \n\t" 299 | #if __AVR_HAVE_JMP_CALL__ 300 | " call _Lcheck_scl_level ;call check function ;; 12C \n\t" 301 | #else 302 | " rcall _Lcheck_scl_level ;call check function ;; 12C \n\t" 303 | #endif 304 | " brpl _Lstretch_done ;done if N=0 ;; +1 = 13C\n\t" 305 | " dec __tmp_reg__ ;dec inner loop counter;; +1 = 14C\n\t" 306 | " brne _Lwait_stretch_inner_loop ;; +2 = 16C\n\t" 307 | " sbiw r26,1 ;dec outer loop counter \n\t" 308 | " brne _Lwait_stretch ;continue with outer loop \n\t" 309 | " sen ;timeout -> set N-bit=1 \n\t" 310 | #if __AVR_HAVE_JMP_CALL__ 311 | " jmp _Lwait_return ;and return with N=1\n\t" 312 | #else 313 | " rjmp _Lwait_return ;and return with N=1\n\t" 314 | #endif 315 | "_Lstretch_done: ;SCL=1 sensed \n\t" 316 | " cln ;OK -> clear N-bit \n\t" 317 | #if __AVR_HAVE_JMP_CALL__ 318 | " jmp _Lwait_return ; and return with N=0 \n\t" 319 | #else 320 | " rjmp _Lwait_return ; and return with N=0 \n\t" 321 | #endif 322 | "_Lcheck_scl_level: ;; call = 3C\n\t" 323 | " cln ;; +1C = 4C \n\t" 324 | " sbic %[SCLIN],%[SCLPIN] ;skip if SCL still low ;; +2C = 6C \n\t" 325 | #if __AVR_HAVE_JMP_CALL__ 326 | " jmp _Lscl_high ;; +0C = 6C \n\t" 327 | #else 328 | " rjmp _Lscl_high ;; +0C = 6C \n\t" 329 | #endif 330 | " sen ;; +1 = 7C\n\t " 331 | "_Lscl_high: " 332 | " nop ;; +1C = 8C \n\t" 333 | " ret ;return N-Bit=1 if low ;; +4 = 12C\n\t" 334 | 335 | "_Lwait_return:" 336 | : : [SCLIN] "I" (SCL_IN), [SCLPIN] "I" (SCL_PIN), 337 | [HISTRETCH] "M" (I2C_MAX_STRETCH>>8), 338 | [LOSTRETCH] "M" (I2C_MAX_STRETCH&0xFF) 339 | : "r26", "r27"); 340 | #endif 341 | } 342 | #endif // !I2C_HARDWARE 343 | 344 | bool i2c_init(void) 345 | #if I2C_HARDWARE 346 | { 347 | #if __has_include("digitalWriteFast.h") 348 | #include "digitalWriteFast.h" 349 | # if I2C_PULLUP 350 | digitalWriteFast(SDA, 1); 351 | digitalWriteFast(SCL, 1); 352 | # else 353 | digitalWriteFast(SDA, 0); 354 | digitalWriteFast(SCL, 0); 355 | # endif 356 | #else 357 | # if I2C_PULLUP 358 | digitalWrite(SDA, 1); 359 | digitalWrite(SCL, 1); 360 | # else 361 | digitalWrite(SDA, 0); 362 | digitalWrite(SCL, 0); 363 | # endif 364 | #endif 365 | #if ((I2C_CPUFREQ/SCL_CLOCK)-16)/2 < 250 366 | TWSR = 0; /* no prescaler */ 367 | TWBR = ((I2C_CPUFREQ/SCL_CLOCK)-16)/2; /* must be > 10 for stable operation */ 368 | #else 369 | TWSR = (1< I2C_TIMEOUT) return false; 421 | #endif 422 | } 423 | 424 | // check value of TWI Status Register. Mask prescaler bits. 425 | twst = TW_STATUS & 0xF8; 426 | if ( (twst != TW_START) && (twst != TW_REP_START)) return false; 427 | 428 | // send device address 429 | TWDR = addr; 430 | TWCR = (1< I2C_TIMEOUT) return false; 436 | #endif 437 | } 438 | 439 | // check value of TWI Status Register. Mask prescaler bits. 440 | twst = TW_STATUS & 0xF8; 441 | if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return false; 442 | 443 | return true; 444 | } 445 | #else 446 | { 447 | __asm__ __volatile__ 448 | ( 449 | #if I2C_NOINTERRUPT 450 | " cli ;clear IRQ bit \n\t" 451 | #endif 452 | " sbis %[SCLIN],%[SCLPIN] ;check for clock stretching slave\n\t" 453 | #if __AVR_HAVE_JMP_CALL__ 454 | " call ass_i2c_wait_scl_high ;wait until SCL=H\n\t" 455 | #else 456 | " rcall ass_i2c_wait_scl_high ;wait until SCL=H\n\t" 457 | #endif 458 | #if I2C_PULLUP 459 | " cbi %[SDAOUT],%[SDAPIN] ;disable pull-up \n\t" 460 | #endif 461 | " sbi %[SDADDR],%[SDAPIN] ;force SDA low \n\t" 462 | #if __AVR_HAVE_JMP_CALL__ 463 | " call ass_i2c_delay_half ;wait T/2 \n\t" 464 | " call ass_i2c_write ;now write address \n\t" 465 | #else 466 | " rcall ass_i2c_delay_half ;wait T/2 \n\t" 467 | " rcall ass_i2c_write ;now write address \n\t" 468 | #endif 469 | " ret" 470 | : : [SDADDR] "I" (SDA_DDR), [SDAPIN] "I" (SDA_PIN), 471 | [SDAOUT] "I" (SDA_OUT), [SCLOUT] "I" (SCL_OUT), 472 | [SCLIN] "I" (SCL_IN),[SCLPIN] "I" (SCL_PIN)); 473 | return true; // we never return here! 474 | } 475 | #endif 476 | 477 | bool i2c_rep_start(uint8_t addr) 478 | #if I2C_HARDWARE 479 | { 480 | return i2c_start(addr); 481 | } 482 | #else 483 | { 484 | __asm__ __volatile__ 485 | 486 | ( 487 | #if I2C_NOINTERRUPT 488 | " cli \n\t" 489 | #endif 490 | #if I2C_PULLUP 491 | " cbi %[SCLOUT],%[SCLPIN] ;disable SCL pull-up \n\t" 492 | #endif 493 | " sbi %[SCLDDR],%[SCLPIN] ;force SCL low \n\t" 494 | #if __AVR_HAVE_JMP_CALL__ 495 | " call ass_i2c_delay_half ;delay T/2 \n\t" 496 | #else 497 | " rcall ass_i2c_delay_half ;delay T/2 \n\t" 498 | #endif 499 | " cbi %[SDADDR],%[SDAPIN] ;release SDA \n\t" 500 | #if I2C_PULLUP 501 | " sbi %[SDAOUT],%[SDAPIN] ;enable SDA pull-up \n\t" 502 | #endif 503 | #if __AVR_HAVE_JMP_CALL__ 504 | " call ass_i2c_delay_half ;delay T/2 \n\t" 505 | #else 506 | " rcall ass_i2c_delay_half ;delay T/2 \n\t" 507 | #endif 508 | " cbi %[SCLDDR],%[SCLPIN] ;release SCL \n\t" 509 | #if I2C_PULLUP 510 | " sbi %[SCLOUT],%[SCLPIN] ;enable SCL pull-up \n\t" 511 | #endif 512 | #if __AVR_HAVE_JMP_CALL__ 513 | " call ass_i2c_delay_half ;delay T/2 \n\t" 514 | #else 515 | " rcall ass_i2c_delay_half ;delay T/2 \n\t" 516 | #endif 517 | " sbis %[SCLIN],%[SCLPIN] ;check for clock stretching slave\n\t" 518 | #if __AVR_HAVE_JMP_CALL__ 519 | " call ass_i2c_wait_scl_high ;wait until SCL=H\n\t" 520 | #else 521 | " rcall ass_i2c_wait_scl_high ;wait until SCL=H\n\t" 522 | #endif 523 | #if I2C_PULLUP 524 | " cbi %[SDAOUT],%[SDAPIN] ;disable SDA pull-up\n\t" 525 | #endif 526 | " sbi %[SDADDR],%[SDAPIN] ;force SDA low \n\t" 527 | #if __AVR_HAVE_JMP_CALL__ 528 | " call ass_i2c_delay_half ;delay T/2 \n\t" 529 | " call ass_i2c_write \n\t" 530 | #else 531 | " rcall ass_i2c_delay_half ;delay T/2 \n\t" 532 | " rcall ass_i2c_write \n\t" 533 | #endif 534 | " ret" 535 | : : [SCLDDR] "I" (SCL_DDR), [SCLPIN] "I" (SCL_PIN), 536 | [SCLIN] "I" (SCL_IN), [SCLOUT] "I" (SCL_OUT), [SDAOUT] "I" (SDA_OUT), 537 | [SDADDR] "I" (SDA_DDR), [SDAPIN] "I" (SDA_PIN)); 538 | return true; // just to fool the compiler 539 | } 540 | #endif 541 | 542 | bool i2c_start_wait(uint8_t addr) 543 | #if I2C_HARDWARE 544 | { 545 | uint8_t twst; 546 | uint16_t maxwait = I2C_MAXWAIT; 547 | #if I2C_TIMEOUT 548 | uint32_t start = millis(); 549 | #endif 550 | 551 | while (true) { 552 | // send START condition 553 | TWCR = (1< I2C_TIMEOUT) return false; 559 | #endif 560 | } 561 | 562 | // check value of TWI Status Register. Mask prescaler bits. 563 | twst = TW_STATUS & 0xF8; 564 | if ( (twst != TW_START) && (twst != TW_REP_START)) continue; 565 | 566 | // send device address 567 | TWDR = addr; 568 | TWCR = (1< I2C_TIMEOUT) return false; 574 | #endif 575 | } 576 | 577 | // check value of TWI Status Register. Mask prescaler bits. 578 | twst = TW_STATUS & 0xF8; 579 | if ( (twst == TW_MT_SLA_NACK )||(twst ==TW_MR_DATA_NACK) ) 580 | { 581 | /* device busy, send stop condition to terminate write operation */ 582 | TWCR = (1< I2C_TIMEOUT) return false; 588 | #endif 589 | } 590 | 591 | if (maxwait && --maxwait == 0) return false; 592 | 593 | continue; 594 | } 595 | //if( twst != TW_MT_SLA_ACK) return 1; 596 | return true; 597 | } 598 | } 599 | #else 600 | { 601 | __asm__ __volatile__ 602 | ( 603 | " push r24 ;save original parameter \n\t" 604 | #if I2C_MAXWAIT 605 | " ldi r31, %[HIMAXWAIT] ;load max wait counter \n\t" 606 | " ldi r30, %[LOMAXWAIT] ;load low byte \n\t" 607 | #endif 608 | "_Li2c_start_wait1: \n\t" 609 | " pop r24 ;restore original parameter\n\t" 610 | " push r24 ;and save again \n\t" 611 | #if I2C_NOINTERRUPT 612 | " cli ;disable interrupts \n\t" 613 | #endif 614 | " sbis %[SCLIN],%[SCLPIN] ;check for clock stretching slave\n\t" 615 | #if __AVR_HAVE_JMP_CALL__ 616 | " call ass_i2c_wait_scl_high ;wait until SCL=H\n\t" 617 | #else 618 | " rcall ass_i2c_wait_scl_high ;wait until SCL=H\n\t" 619 | #endif 620 | #if I2C_PULLUP 621 | " cbi %[SDAOUT],%[SDAPIN] ;disable pull-up \n\t" 622 | #endif 623 | " sbi %[SDADDR],%[SDAPIN] ;force SDA low \n\t" 624 | #if __AVR_HAVE_JMP_CALL__ 625 | " call ass_i2c_delay_half ;delay T/2 \n\t" 626 | " call ass_i2c_write ;write address \n\t" 627 | #else 628 | " rcall ass_i2c_delay_half ;delay T/2 \n\t" 629 | " rcall ass_i2c_write ;write address \n\t" 630 | #endif 631 | " tst r24 ;if device not busy -> done \n\t" 632 | " brne _Li2c_start_wait_done \n\t" 633 | #if __AVR_HAVE_JMP_CALL__ 634 | " call ass_i2c_stop ;terminate write & enable IRQ \n\t" 635 | #else 636 | " rcall ass_i2c_stop ;terminate write & enable IRQ \n\t" 637 | #endif 638 | #if I2C_MAXWAIT 639 | " sbiw r30,1 ;decrement max wait counter\n\t" 640 | " breq _Li2c_start_wait_done ;if zero reached, exit with false -> r24 already zero!\n\t" 641 | #endif 642 | #if __AVR_HAVE_JMP_CALL__ 643 | " jmp _Li2c_start_wait1 ;device busy, poll ack again \n\t" 644 | #else 645 | " rjmp _Li2c_start_wait1 ;device busy, poll ack again \n\t" 646 | #endif 647 | "_Li2c_start_wait_done: \n\t" 648 | " clr r25 ;clear high byte of return value\n\t" 649 | " pop __tmp_reg__ ;pop off orig argument \n\t" 650 | " ret " 651 | : : [SDADDR] "I" (SDA_DDR), [SDAPIN] "I" (SDA_PIN), [SDAOUT] "I" (SDA_OUT), 652 | [SCLIN] "I" (SCL_IN), [SCLPIN] "I" (SCL_PIN), 653 | [HIMAXWAIT] "M" (I2C_MAXWAIT>>8), 654 | [LOMAXWAIT] "M" (I2C_MAXWAIT&0xFF) 655 | : "r30", "r31" ); 656 | return true; // fooling the compiler 657 | } 658 | #endif 659 | 660 | void i2c_stop(void) 661 | #if I2C_HARDWARE 662 | { 663 | #if I2C_TIMEOUT 664 | uint32_t start = millis(); 665 | #endif 666 | /* send stop condition */ 667 | TWCR = (1< I2C_TIMEOUT) return; 673 | #endif 674 | } 675 | } 676 | #else 677 | { 678 | __asm__ __volatile__ 679 | ( 680 | #if I2C_PULLUP 681 | " cbi %[SCLOUT],%[SCLPIN] ;disable SCL pull-up \n\t" 682 | #endif 683 | " sbi %[SCLDDR],%[SCLPIN] ;force SCL low \n\t" 684 | #if I2C_PULLUP 685 | " cbi %[SDAOUT],%[SDAPIN] ;disable pull-up \n\t" 686 | #endif 687 | " sbi %[SDADDR],%[SDAPIN] ;force SDA low \n\t" 688 | #if __AVR_HAVE_JMP_CALL__ 689 | " call ass_i2c_delay_half ;T/2 delay \n\t" 690 | #else 691 | " rcall ass_i2c_delay_half ;T/2 delay \n\t" 692 | #endif 693 | " cbi %[SCLDDR],%[SCLPIN] ;release SCL \n\t" 694 | #if I2C_PULLUP 695 | " sbi %[SCLOUT],%[SCLPIN] ;enable SCL pull-up \n\t" 696 | #endif 697 | #if __AVR_HAVE_JMP_CALL__ 698 | " call ass_i2c_delay_half ;T/2 delay \n\t" 699 | #else 700 | " rcall ass_i2c_delay_half ;T/2 delay \n\t" 701 | #endif 702 | " sbis %[SCLIN],%[SCLPIN] ;check for clock stretching slave\n\t" 703 | #if __AVR_HAVE_JMP_CALL__ 704 | " call ass_i2c_wait_scl_high ;wait until SCL=H\n\t" 705 | #else 706 | " rcall ass_i2c_wait_scl_high ;wait until SCL=H\n\t" 707 | #endif 708 | " cbi %[SDADDR],%[SDAPIN] ;release SDA \n\t" 709 | #if I2C_PULLUP 710 | " sbi %[SDAOUT],%[SDAPIN] ;enable SDA pull-up \n\t" 711 | #endif 712 | #if __AVR_HAVE_JMP_CALL__ 713 | " call ass_i2c_delay_half \n\t" 714 | #else 715 | " rcall ass_i2c_delay_half \n\t" 716 | #endif 717 | #if I2C_NOINTERRUPT 718 | " sei ;enable interrupts again!\n\t" 719 | #endif 720 | : : [SCLDDR] "I" (SCL_DDR), [SCLPIN] "I" (SCL_PIN), [SCLIN] "I" (SCL_IN), 721 | [SDAOUT] "I" (SDA_OUT), [SCLOUT] "I" (SCL_OUT), 722 | [SDADDR] "I" (SDA_DDR), [SDAPIN] "I" (SDA_PIN)); 723 | } 724 | #endif 725 | 726 | 727 | bool i2c_write(uint8_t value) 728 | #if I2C_HARDWARE 729 | { 730 | uint8_t twst; 731 | #if I2C_TIMEOUT 732 | uint32_t start = millis(); 733 | #endif 734 | 735 | 736 | // send data to the previously addressed device 737 | TWDR = value; 738 | TWCR = (1< I2C_TIMEOUT) return false; 744 | #endif 745 | } 746 | 747 | // check value of TWI Status Register. Mask prescaler bits 748 | twst = TW_STATUS & 0xF8; 749 | if( twst != TW_MT_DATA_ACK) return false; 750 | return true; 751 | } 752 | #else 753 | { 754 | __asm__ __volatile__ 755 | ( 756 | " sec ;set carry flag \n\t" 757 | " rol r24 ;shift in carry and shift out MSB \n\t" 758 | #if __AVR_HAVE_JMP_CALL__ 759 | " jmp _Li2c_write_first \n\t" 760 | #else 761 | " rjmp _Li2c_write_first \n\t" 762 | #endif 763 | "_Li2c_write_bit:\n\t" 764 | " lsl r24 ;left shift into carry ;; 1C\n\t" 765 | "_Li2c_write_first:\n\t" 766 | " breq _Li2c_get_ack ;jump if TXreg is empty;; +1 = 2C \n\t" 767 | #if I2C_PULLUP 768 | " cbi %[SCLOUT],%[SCLPIN] ;disable SCL pull-up \n\t" 769 | #endif 770 | " sbi %[SCLDDR],%[SCLPIN] ;force SCL low ;; +2 = 4C \n\t" 771 | " nop \n\t" 772 | " nop \n\t" 773 | " nop \n\t" 774 | " brcc _Li2c_write_low ;;+1/+2=5/6C\n\t" 775 | " nop ;; +1 = 7C \n\t" 776 | " cbi %[SDADDR],%[SDAPIN] ;release SDA ;; +2 = 9C \n\t" 777 | #if I2C_PULLUP 778 | " sbi %[SDAOUT],%[SDAPIN] ;enable SDA pull-up \n\t" 779 | #endif 780 | #if __AVR_HAVE_JMP_CALL__ 781 | " jmp _Li2c_write_high ;; +2 = 11C \n\t" 782 | #else 783 | " rjmp _Li2c_write_high ;; +2 = 11C \n\t" 784 | #endif 785 | "_Li2c_write_low: \n\t" 786 | #if I2C_PULLUP 787 | " cbi %[SDAOUT],%[SDAPIN] ;disable pull-up \n\t" 788 | #endif 789 | " sbi %[SDADDR],%[SDAPIN] ;force SDA low ;; +2 = 9C \n\t" 790 | #if __AVR_HAVE_JMP_CALL__ 791 | " jmp _Li2c_write_high ;;+2 = 11C \n\t" 792 | #else 793 | " rjmp _Li2c_write_high ;;+2 = 11C \n\t" 794 | #endif 795 | "_Li2c_write_high: \n\t" 796 | #if I2C_DELAY_COUNTER >= 1 797 | #if __AVR_HAVE_JMP_CALL__ 798 | " call ass_i2c_delay_half ;delay T/2 ;;+X = 11C+X\n\t" 799 | #else 800 | " rcall ass_i2c_delay_half ;delay T/2 ;;+X = 11C+X\n\t" 801 | #endif 802 | #endif 803 | " cbi %[SCLDDR],%[SCLPIN] ;release SCL ;;+2 = 13C+X\n\t" 804 | #if I2C_PULLUP 805 | " sbi %[SCLOUT],%[SCLPIN] ;enable SCL pull-up \n\t" 806 | #endif 807 | " cln ;clear N-bit ;;+1 = 14C+X\n\t" 808 | " nop \n\t" 809 | " nop \n\t" 810 | " nop \n\t" 811 | " sbis %[SCLIN],%[SCLPIN] ;check for SCL high ;;+2 = 16C+X\n\t" 812 | #if __AVR_HAVE_JMP_CALL__ 813 | " call ass_i2c_wait_scl_high \n\t" 814 | #else 815 | " rcall ass_i2c_wait_scl_high \n\t" 816 | #endif 817 | " brpl _Ldelay_scl_high ;;+2 = 18C+X\n\t" 818 | "_Li2c_write_return_false: \n\t" 819 | " clr r24 ; return false because of timeout \n\t" 820 | #if __AVR_HAVE_JMP_CALL__ 821 | " jmp _Li2c_write_return \n\t" 822 | #else 823 | " rjmp _Li2c_write_return \n\t" 824 | #endif 825 | "_Ldelay_scl_high: \n\t" 826 | #if I2C_DELAY_COUNTER >= 1 827 | #if __AVR_HAVE_JMP_CALL__ 828 | " call ass_i2c_delay_half ;delay T/2 ;;+X= 18C+2X\n\t" 829 | #else 830 | " rcall ass_i2c_delay_half ;delay T/2 ;;+X= 18C+2X\n\t" 831 | #endif 832 | #endif 833 | #if __AVR_HAVE_JMP_CALL__ 834 | " jmp _Li2c_write_bit \n\t" 835 | #else 836 | " rjmp _Li2c_write_bit \n\t" 837 | #endif 838 | " ;; +2 = 20C +2X for one bit-loop \n\t" 839 | "_Li2c_get_ack: \n\t" 840 | #if I2C_PULLUP 841 | " cbi %[SCLOUT],%[SCLPIN] ;disable SCL pull-up \n\t" 842 | #endif 843 | " sbi %[SCLDDR],%[SCLPIN] ;force SCL low ;; +2 = 5C \n\t" 844 | " nop \n\t" 845 | " nop \n\t" 846 | " cbi %[SDADDR],%[SDAPIN] ;release SDA ;;+2 = 7C \n\t" 847 | #if I2C_PULLUP 848 | " sbi %[SDAOUT],%[SDAPIN] ;enable SDA pull-up \n\t" 849 | #endif 850 | #if I2C_DELAY_COUNTER >= 1 851 | #if __AVR_HAVE_JMP_CALL__ 852 | " call ass_i2c_delay_half ;delay T/2 ;; +X = 7C+X \n\t" 853 | #else 854 | " rcall ass_i2c_delay_half ;delay T/2 ;; +X = 7C+X \n\t" 855 | #endif 856 | #endif 857 | " clr r25 ;; 17C+2X \n\t" 858 | " clr r24 ;return 0 ;; 14C + X \n\t" 859 | " cbi %[SCLDDR],%[SCLPIN] ;release SCL ;; +2 = 9C+X\n\t" 860 | #if I2C_PULLUP 861 | " sbi %[SCLOUT],%[SCLPIN] ;enable SCL pull-up \n\t" 862 | #endif 863 | "_Li2c_ack_wait: \n\t" 864 | " cln ; clear N-bit ;; 10C + X\n\t" 865 | " nop \n\t" 866 | " sbis %[SCLIN],%[SCLPIN] ;wait SCL high ;; 12C + X \n\t" 867 | #if __AVR_HAVE_JMP_CALL__ 868 | " call ass_i2c_wait_scl_high \n\t" 869 | #else 870 | " rcall ass_i2c_wait_scl_high \n\t" 871 | #endif 872 | " brmi _Li2c_write_return_false ;; 13C + X \n\t " 873 | " sbis %[SDAIN],%[SDAPIN] ;if SDA hi -> return 0 ;; 15C + X \n\t" 874 | " ldi r24,1 ;return true ;; 16C + X \n\t" 875 | #if I2C_DELAY_COUNTER >= 1 876 | #if __AVR_HAVE_JMP_CALL__ 877 | " call ass_i2c_delay_half ;delay T/2 ;; 16C + 2X \n\t" 878 | #else 879 | " rcall ass_i2c_delay_half ;delay T/2 ;; 16C + 2X \n\t" 880 | #endif 881 | #endif 882 | "_Li2c_write_return: \n\t" 883 | " nop \n\t " 884 | " nop \n\t " 885 | #if I2C_PULLUP 886 | " cbi %[SCLOUT],%[SCLPIN] ;disable SCL pull-up \n\t" 887 | #endif 888 | " sbi %[SCLDDR],%[SCLPIN] ;force SCL low so SCL=H is short\n\t" 889 | " ret \n\t" 890 | " ;; + 4 = 17C + 2X for acknowldge bit" 891 | :: 892 | [SCLDDR] "I" (SCL_DDR), [SCLPIN] "I" (SCL_PIN), [SCLIN] "I" (SCL_IN), 893 | [SDAOUT] "I" (SDA_OUT), [SCLOUT] "I" (SCL_OUT), 894 | [SDADDR] "I" (SDA_DDR), [SDAPIN] "I" (SDA_PIN), [SDAIN] "I" (SDA_IN)); 895 | return true; // fooling the compiler 896 | } 897 | #endif 898 | 899 | uint8_t i2c_read(bool last) 900 | #if I2C_HARDWARE 901 | { 902 | #if I2C_TIMEOUT 903 | uint32_t start = millis(); 904 | #endif 905 | 906 | TWCR = (1< I2C_TIMEOUT) return 0xFF; 910 | #endif 911 | } 912 | return TWDR; 913 | } 914 | #else 915 | { 916 | __asm__ __volatile__ 917 | ( 918 | " ldi r23,0x01 \n\t" 919 | "_Li2c_read_bit: \n\t" 920 | #if I2C_PULLUP 921 | " cbi %[SCLOUT],%[SCLPIN] ;disable SCL pull-up \n\t" 922 | #endif 923 | " sbi %[SCLDDR],%[SCLPIN] ;force SCL low ;; 2C \n\t" 924 | " cbi %[SDADDR],%[SDAPIN] ;release SDA(prev. ACK);; 4C \n\t" 925 | #if I2C_PULLUP 926 | " sbi %[SDAOUT],%[SDAPIN] ;enable SDA pull-up \n\t" 927 | #endif 928 | " nop \n\t" 929 | " nop \n\t" 930 | " nop \n\t" 931 | #if I2C_DELAY_COUNTER >= 1 932 | #if __AVR_HAVE_JMP_CALL__ 933 | " call ass_i2c_delay_half ;delay T/2 ;; 4C+X \n\t" 934 | #else 935 | " rcall ass_i2c_delay_half ;delay T/2 ;; 4C+X \n\t" 936 | #endif 937 | #endif 938 | " cbi %[SCLDDR],%[SCLPIN] ;release SCL ;; 6C + X \n\t" 939 | #if I2C_PULLUP 940 | " sbi %[SCLOUT],%[SCLPIN] ;enable SCL pull-up \n\t" 941 | #endif 942 | #if I2C_DELAY_COUNTER >= 1 943 | #if __AVR_HAVE_JMP_CALL__ 944 | " call ass_i2c_delay_half ;delay T/2 ;; 6C + 2X \n\t" 945 | #else 946 | " rcall ass_i2c_delay_half ;delay T/2 ;; 6C + 2X \n\t" 947 | #endif 948 | #endif 949 | " cln ; clear N-bit ;; 7C + 2X \n\t" 950 | " nop \n\t " 951 | " nop \n\t " 952 | " nop \n\t " 953 | " sbis %[SCLIN], %[SCLPIN] ;check for SCL high ;; 9C +2X \n\t" 954 | #if __AVR_HAVE_JMP_CALL__ 955 | " call ass_i2c_wait_scl_high \n\t" 956 | #else 957 | " rcall ass_i2c_wait_scl_high \n\t" 958 | #endif 959 | " brmi _Li2c_read_return ;return if timeout ;; 10C + 2X\n\t" 960 | " clc ;clear carry flag ;; 11C + 2X\n\t" 961 | " sbic %[SDAIN],%[SDAPIN] ;if SDA is high ;; 11C + 2X\n\t" 962 | " sec ;set carry flag ;; 12C + 2X\n\t" 963 | " rol r23 ;store bit ;; 13C + 2X\n\t" 964 | " brcc _Li2c_read_bit ;while receiv reg not full \n\t" 965 | " ;; 15C + 2X for one bit loop \n\t" 966 | 967 | "_Li2c_put_ack: \n\t" 968 | #if I2C_PULLUP 969 | " cbi %[SCLOUT],%[SCLPIN] ;disable SCL pull-up \n\t" 970 | #endif 971 | " sbi %[SCLDDR],%[SCLPIN] ;force SCL low ;; 2C \n\t" 972 | " cpi r24,0 ;; 3C \n\t" 973 | " breq _Li2c_put_ack_low ;if (ack=0) ;; 5C \n\t" 974 | " cbi %[SDADDR],%[SDAPIN] ;release SDA \n\t" 975 | #if I2C_PULLUP 976 | " sbi %[SDAOUT],%[SDAPIN] ;enable SDA pull-up \n\t" 977 | #endif 978 | #if __AVR_HAVE_JMP_CALL__ 979 | " jmp _Li2c_put_ack_high \n\t" 980 | #else 981 | " rjmp _Li2c_put_ack_high \n\t" 982 | #endif 983 | "_Li2c_put_ack_low: ;else \n\t" 984 | #if I2C_PULLUP 985 | " cbi %[SDAOUT],%[SDAPIN] ;disable pull-up \n\t" 986 | #endif 987 | " sbi %[SDADDR],%[SDAPIN] ;force SDA low ;; 7C \n\t" 988 | "_Li2c_put_ack_high: \n\t" 989 | " nop \n\t " 990 | " nop \n\t " 991 | " nop \n\t " 992 | #if I2C_DELAY_COUNTER >= 1 993 | #if __AVR_HAVE_JMP_CALL__ 994 | " call ass_i2c_delay_half ;delay T/2 ;; 7C + X \n\t" 995 | #else 996 | " rcall ass_i2c_delay_half ;delay T/2 ;; 7C + X \n\t" 997 | #endif 998 | #endif 999 | " cbi %[SCLDDR],%[SCLPIN] ;release SCL ;; 9C +X \n\t" 1000 | #if I2C_PULLUP 1001 | " sbi %[SCLOUT],%[SCLPIN] ;enable SCL pull-up \n\t" 1002 | #endif 1003 | " cln ;clear N ;; +1 = 10C\n\t" 1004 | " nop \n\t " 1005 | " nop \n\t " 1006 | " sbis %[SCLIN],%[SCLPIN] ;wait SCL high ;; 12C + X\n\t" 1007 | #if __AVR_HAVE_JMP_CALL__ 1008 | " call ass_i2c_wait_scl_high \n\t" 1009 | #else 1010 | " rcall ass_i2c_wait_scl_high \n\t" 1011 | #endif 1012 | #if I2C_DELAY_COUNTER >= 1 1013 | #if __AVR_HAVE_JMP_CALL__ 1014 | " call ass_i2c_delay_half ;delay T/2 ;; 11C + 2X\n\t" 1015 | #else 1016 | " rcall ass_i2c_delay_half ;delay T/2 ;; 11C + 2X\n\t" 1017 | #endif 1018 | #endif 1019 | "_Li2c_read_return: \n\t" 1020 | " nop \n\t " 1021 | " nop \n\t " 1022 | #if I2C_PULLUP 1023 | " cbi %[SCLOUT],%[SCLPIN] ;disable SCL pull-up \n\t" 1024 | #endif 1025 | "sbi %[SCLDDR],%[SCLPIN] ;force SCL low so SCL=H is short\n\t" 1026 | " mov r24,r23 ;; 12C + 2X \n\t" 1027 | " clr r25 ;; 13 C + 2X\n\t" 1028 | " ret ;; 17C + X" 1029 | :: 1030 | [SCLDDR] "I" (SCL_DDR), [SCLPIN] "I" (SCL_PIN), [SCLIN] "I" (SCL_IN), 1031 | [SDAOUT] "I" (SDA_OUT), [SCLOUT] "I" (SCL_OUT), 1032 | [SDADDR] "I" (SDA_DDR), [SDAPIN] "I" (SDA_PIN), [SDAIN] "I" (SDA_IN) 1033 | ); 1034 | return ' '; // fool the compiler! 1035 | } 1036 | #endif 1037 | 1038 | #pragma GCC diagnostic pop 1039 | 1040 | #endif // !defined(USE_SOFT_I2C_MASTER_H_AS_PLAIN_INCLUDE) 1041 | #endif // #ifndef _SOFTI2C_HPP 1042 | #endif // #ifndef __AVR_ARCH__ 1043 | #pragma once 1044 | --------------------------------------------------------------------------------