├── TinyWireS ├── avr_usi_i2c_master.pdf ├── avr_usi_i2c_slave.pdf ├── keywords.txt ├── TinyWireS.h ├── usiTwiSlave.h ├── TinyWireS.cpp ├── examples │ ├── TinyWireS_Stress_Slave │ │ └── TinyWireS_Stress_Slave.ino │ ├── TinyWireS_Stress_Master │ │ └── TinyWireS_Stress_Master.ino │ ├── attiny85_i2c_slave │ │ └── attiny85_i2c_slave.ino │ ├── attiny85_i2c_analog │ │ └── attiny85_i2c_analog.ino │ └── attiny85_i2c_slave_task │ │ └── attiny85_i2c_slave_task.ino └── usiTwiSlave.c └── README.md /TinyWireS/avr_usi_i2c_master.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hean01/TinyWire/master/TinyWireS/avr_usi_i2c_master.pdf -------------------------------------------------------------------------------- /TinyWireS/avr_usi_i2c_slave.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hean01/TinyWire/master/TinyWireS/avr_usi_i2c_slave.pdf -------------------------------------------------------------------------------- /TinyWireS/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For TinyWireS 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | ####################################### 10 | # Methods and Functions (KEYWORD2) 11 | ####################################### 12 | 13 | begin KEYWORD2 14 | send KEYWORD2 15 | available KEYWORD2 16 | receive KEYWORD2 17 | 18 | ####################################### 19 | # Instances (KEYWORD2) 20 | ####################################### 21 | 22 | TinyWireS KEYWORD2 23 | 24 | ####################################### 25 | # Constants (LITERAL1) 26 | ####################################### 27 | 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Arduino TinyWire Slave Library 2 | 3 | Originals from 4 | 5 | Modified to support ATtiny44/84 6 | 7 | ## NOTE about reliable communication 8 | 9 | Since (most of) the ATTinys lack TWI module for implementing all the nitty-gritty of I2C in hardware 10 | they will have to do some clock-stretching (at least if run at 8MHz, you may get away with more on higher clock speeds) 11 | as specified in the I2C protocol. However some (especially "bit-banged") master implementations do not 12 | support clock-streching (looking at you Bus pirate 3.x and [RPI][rpibug]), you will not get reliable communication 13 | unless your master supports the full I2C protocol spec. There is a [library][pigpio] which can bit-bang I2C correctly on RPI, use that instead of the [buggy hardware][rpibug] (thanks to @brendanarnold for [that tip][pigtip]). 14 | 15 | You can use my [Arduino based I2C master][i2crepl] to test your TinyWire code, this uses Bus Pirate semantics 16 | with Arduinos TWI hardware that is known to implement I2C properly. 17 | 18 | [i2crepl]: https://github.com/rambo/I2C/blob/master/examples/i2crepl/i2crepl.ino 19 | [rpibug]: http://www.advamation.com/knowhow/raspberrypi/rpi-i2c-bug.html 20 | [pigpio]: http://abyz.co.uk/rpi/pigpio/python.html#bb_i2c_zip 21 | [pigtip]: https://github.com/rambo/TinyWire/issues/14#issuecomment-125325081 22 | 23 | ## delayMicroseconds 24 | 25 | See this issue: (remember to declare the function void if you copy-paste it verbatim) 26 | -------------------------------------------------------------------------------- /TinyWireS/TinyWireS.h: -------------------------------------------------------------------------------- 1 | /* 2 | TinyWireS.h - a wrapper class for Don Blake's usiTwiSlave routines. 3 | Provides TWI/I2C Slave functionality on ATtiny processers in Arduino environment. 4 | 1/23/2011 BroHogan - brohoganx10 at gmail dot com 5 | 6 | Major credit and thanks to Don Blake for his usiTwiSlave code which makes this possible 7 | http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=51467&start=all&postdays=0&postorder=asc 8 | (Changed #define USI_START_COND_INT USISIF (was USICIF) in usiTwiSlave.h) 9 | 10 | NOTE! - It's very important to use pullups on the SDA & SCL lines! More so than with the Wire lib. 11 | Current Rx & Tx buffers set at 32 bytes - see usiTwiSlave.h 12 | 13 | USAGE is modeled after the standard Wire library . . . 14 | Put in setup(): 15 | TinyWireS.begin(I2C_SLAVE_ADDR); // initialize I2C lib & setup slave's address (7 bit - same as Wire) 16 | 17 | To Receive: 18 | someByte = TinyWireS.available(){ // returns the number of bytes in the received buffer 19 | someByte = TinyWireS.receive(){ // returns the next byte in the received buffer 20 | 21 | To Send: 22 | TinyWireS.send(uint8_t data){ // sends a requested byte to master 23 | 24 | TODO: (by others!) 25 | - onReceive and onRequest handlers are not implimented. 26 | - merge this class with TinyWireM for master & slave support in one library 27 | 28 | This library is free software; you can redistribute it and/or modify it under the 29 | terms of the GNU General Public License as published by the Free Software 30 | Foundation; either version 2.1 of the License, or any later version. 31 | This program is distributed in the hope that it will be useful, but WITHOUT ANY 32 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 33 | PARTICULAR PURPOSE. See the GNU General Public License for more details. 34 | */ 35 | 36 | #ifndef TinyWireS_h 37 | #define TinyWireS_h 38 | 39 | #include 40 | 41 | 42 | class USI_TWI_S 43 | { 44 | private: 45 | //static uint8_t USI_BytesAvail; 46 | 47 | public: 48 | USI_TWI_S(); 49 | void begin(uint8_t I2C_SLAVE_ADDR); 50 | void send(uint8_t data); 51 | uint8_t available(); 52 | uint8_t receive(); 53 | void onReceive( void (*)(uint8_t) ); 54 | void onRequest( void (*)(void) ); 55 | }; 56 | 57 | void TinyWireS_stop_check(); 58 | // Implement a delay loop that checks for the stop bit (basically direct copy of the stock arduino implementation from wiring.c) 59 | void tws_delay(unsigned long); 60 | 61 | extern USI_TWI_S TinyWireS; 62 | 63 | #endif 64 | 65 | -------------------------------------------------------------------------------- /TinyWireS/usiTwiSlave.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | 3 | Header file for the USI TWI Slave driver. 4 | 5 | Created by Donald R. Blake 6 | donblake at worldnet.att.net 7 | 8 | --------------------------------------------------------------------------------- 9 | 10 | Created from Atmel source files for Application Note AVR312: Using the USI Module 11 | as an I2C slave. 12 | 13 | This program is free software; you can redistribute it and/or modify it under the 14 | terms of the GNU General Public License as published by the Free Software 15 | Foundation; either version 2 of the License, or (at your option) any later 16 | version. 17 | 18 | This program is distributed in the hope that it will be useful, but WITHOUT ANY 19 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 20 | PARTICULAR PURPOSE. See the GNU General Public License for more details. 21 | 22 | --------------------------------------------------------------------------------- 23 | 24 | Change Activity: 25 | 26 | Date Description 27 | ------ ------------- 28 | 15 Mar 2007 Created. 29 | 30 | ********************************************************************************/ 31 | 32 | 33 | 34 | #ifndef _USI_TWI_SLAVE_H_ 35 | #define _USI_TWI_SLAVE_H_ 36 | 37 | 38 | 39 | /******************************************************************************** 40 | 41 | includes 42 | 43 | ********************************************************************************/ 44 | 45 | #include 46 | 47 | 48 | 49 | /******************************************************************************** 50 | 51 | prototypes 52 | 53 | ********************************************************************************/ 54 | 55 | void usiTwiSlaveInit( uint8_t ); 56 | void usiTwiTransmitByte( uint8_t ); 57 | uint8_t usiTwiReceiveByte( void ); 58 | bool usiTwiDataInReceiveBuffer( void ); 59 | void (*_onTwiDataRequest)(void); 60 | bool usiTwiDataInTransmitBuffer(void); 61 | uint8_t usiTwiAmountDataInReceiveBuffer(void); 62 | // on_XXX handler pointers 63 | void (*usi_onRequestPtr)(void); 64 | void (*usi_onReceiverPtr)(uint8_t); 65 | 66 | 67 | /******************************************************************************** 68 | 69 | driver buffer definitions 70 | 71 | ********************************************************************************/ 72 | 73 | // permitted RX buffer sizes: 1, 2, 4, 8, 16, 32, 64, 128 or 256 74 | 75 | #ifndef TWI_RX_BUFFER_SIZE 76 | #define TWI_RX_BUFFER_SIZE ( 16 ) 77 | #endif 78 | #define TWI_RX_BUFFER_MASK ( TWI_RX_BUFFER_SIZE - 1 ) 79 | 80 | #if ( TWI_RX_BUFFER_SIZE & TWI_RX_BUFFER_MASK ) 81 | # error TWI RX buffer size is not a power of 2 82 | #endif 83 | 84 | // permitted TX buffer sizes: 1, 2, 4, 8, 16, 32, 64, 128 or 256 85 | 86 | #ifndef TWI_TX_BUFFER_SIZE 87 | #define TWI_TX_BUFFER_SIZE ( 16 ) 88 | #endif 89 | #define TWI_TX_BUFFER_MASK ( TWI_TX_BUFFER_SIZE - 1 ) 90 | 91 | #if ( TWI_TX_BUFFER_SIZE & TWI_TX_BUFFER_MASK ) 92 | # error TWI TX buffer size is not a power of 2 93 | #endif 94 | 95 | 96 | 97 | #endif // ifndef _USI_TWI_SLAVE_H_ 98 | -------------------------------------------------------------------------------- /TinyWireS/TinyWireS.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | TinyWireS.cpp - a wrapper class for Don Blake's usiTwiSlave routines. 3 | Provides TWI/I2C Slave functionality on ATtiny processers in Arduino environment. 4 | 1/23/2011 BroHogan - brohoganx10 at gmail dot com 5 | 6 | **** See TinyWireS.h for Credits and Usage information **** 7 | 8 | This library is free software; you can redistribute it and/or modify it under the 9 | terms of the GNU General Public License as published by the Free Software 10 | Foundation; either version 2.1 of the License, or any later version. 11 | This program is distributed in the hope that it will be useful, but WITHOUT ANY 12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 13 | PARTICULAR PURPOSE. See the GNU General Public License for more details. 14 | */ 15 | 16 | extern "C" { 17 | #include 18 | #include "usiTwiSlave.h" 19 | #include 20 | } 21 | 22 | #include "TinyWireS.h" 23 | #include "Arduino.h" 24 | 25 | // Constructors //////////////////////////////////////////////////////////////// 26 | 27 | USI_TWI_S::USI_TWI_S(){ 28 | } 29 | 30 | 31 | // Public Methods ////////////////////////////////////////////////////////////// 32 | 33 | void USI_TWI_S::begin(uint8_t slaveAddr){ // initialize I2C lib 34 | usiTwiSlaveInit(slaveAddr); 35 | } 36 | 37 | void USI_TWI_S::send(uint8_t data){ // send it back to master 38 | usiTwiTransmitByte(data); 39 | } 40 | 41 | uint8_t USI_TWI_S::available(){ // the bytes available that haven't been read yet 42 | return usiTwiAmountDataInReceiveBuffer(); 43 | //return usiTwiDataInReceiveBuffer(); // This is wrong as far as the Wire API is concerned since it returns boolean and not amount 44 | } 45 | 46 | uint8_t USI_TWI_S::receive(){ // returns the bytes received one at a time 47 | return usiTwiReceiveByte(); 48 | } 49 | 50 | // sets function called on slave write 51 | void USI_TWI_S::onReceive( void (*function)(uint8_t) ) 52 | { 53 | usi_onReceiverPtr = function; 54 | } 55 | 56 | // sets function called on slave read 57 | void USI_TWI_S::onRequest( void (*function)(void) ) 58 | { 59 | usi_onRequestPtr = function; 60 | } 61 | 62 | void TinyWireS_stop_check() 63 | { 64 | if (!usi_onReceiverPtr) 65 | { 66 | // no onReceive callback, nothing to do... 67 | return; 68 | } 69 | if (!(USISR & ( 1 << USIPF ))) 70 | { 71 | // Stop not detected 72 | return; 73 | } 74 | uint8_t amount = usiTwiAmountDataInReceiveBuffer(); 75 | if (amount == 0) 76 | { 77 | // no data in buffer 78 | return; 79 | } 80 | usi_onReceiverPtr(amount); 81 | } 82 | 83 | // Implement a delay loop that checks for the stop bit (basically direct copy of the stock arduino implementation from wiring.c) 84 | void tws_delay(unsigned long ms) 85 | { 86 | uint16_t start = (uint16_t)micros(); 87 | while (ms > 0) 88 | { 89 | TinyWireS_stop_check(); 90 | if (((uint16_t)micros() - start) >= 1000) 91 | { 92 | ms--; 93 | start += 1000; 94 | } 95 | } 96 | } 97 | 98 | // Preinstantiate Objects ////////////////////////////////////////////////////// 99 | 100 | USI_TWI_S TinyWireS = USI_TWI_S(); 101 | 102 | -------------------------------------------------------------------------------- /TinyWireS/examples/TinyWireS_Stress_Slave/TinyWireS_Stress_Slave.ino: -------------------------------------------------------------------------------- 1 | // --------------------------------- 2 | // Stress test program/example for TinyWireS I2C library. 3 | // Run this slave program on the Attiny. 4 | // Run the other master program on the Arduino Uno R3. 5 | // --------------------------------- 6 | // // Written by Scott Hartog, 2/6/2016, to stress test the TinyWireS library. 7 | // https://github.com/rambo/TinyWire 8 | // 9 | // This project uses the Tiny85 as an I2C slave. 10 | // 11 | // The slave program using TinyWireS, running on a Attiny85, receives 12 | // N bytes of random data in a single receiveEvent() callback and 13 | // stores that data in a global buffer. It then responds the first requestEvent() 14 | // callback with that same data. The requestEvent() callback overwrites the data 15 | // buffer with zeros after responding so it will only respond correctly to the 16 | // first requestEvent() callback after each receiveEvent() callback. Subsequent 17 | // requestEvent() will respond with 0xff for all data bytes. 18 | // 19 | // 20 | // SETUP: 21 | // AtTiny Pin 5 (PB0/SDA) = I2C SDA 22 | // connect to SDA on master with external pull-up (~4.7K) 23 | // AtTiny Pin 7 (PB0/SCL) = I2C SCL 24 | // connect to SCL on master with external pull-up (~4.7K) 25 | // AtTiny Pin 1 (PB5/!RST) 26 | // connect to reset on master (or just pull-up) 27 | // 28 | // Please see credits and usage for usiTwiSlave and TinyWireS in the .h files of 29 | // those libraries. 30 | 31 | #include "TinyWireS.h" // wrapper class for I2C slave routines 32 | 33 | #define I2C_SLAVE_ADDR 0x26 // i2c slave address (38, 0x26) 34 | 35 | // global buffer to store data sent from the master. 36 | uint8_t master_data[16]; 37 | // global variable to number of bytes sent from the master. 38 | uint8_t master_bytes; 39 | 40 | // Gets called when the ATtiny receives an i2c write slave request 41 | void receiveEvent(uint8_t num_bytes) 42 | { 43 | uint8_t i; 44 | 45 | // save the number of bytes sent from the master 46 | master_bytes = num_bytes; 47 | 48 | // store the data from the master into the data buffer 49 | for (i = 0; i < master_bytes; i++) 50 | master_data[i] = TinyWireS.receive(); 51 | 52 | } 53 | 54 | // Gets called when the ATtiny receives an i2c read slave request 55 | void requestEvent() 56 | { 57 | uint8_t i; 58 | 59 | // send the data buffer back to the master 60 | for (i = 0; i < master_bytes; i++) 61 | TinyWireS.send(master_data[i]); 62 | 63 | // corrupt the byte values in the data buffer 64 | // so that subsequent call won't match 65 | for (i = 0; i < master_bytes; i++) 66 | master_data[i] += 0x5a; 67 | 68 | // corrupt length of the request, but dont' make it zero 69 | 70 | // if the usiTwiSlave.c is working fine, then this number is completely irrelevant 71 | // because the requestEvent() callback will not be called again until 72 | // after the next receiveEvent() callback, so the master_data and 73 | // master_bytes variables will be set by that call. 74 | 75 | // If the usiTwiSlave.c has the issue of calling the requestFrom() callback 76 | // for each byte sent, the buffer will accumulate by this amount *for each byte 77 | // in the original request*. 78 | // 79 | // Making it zero will obscure the 1-byte send issue in the usiTwiSlave.c 80 | // that is being tested. 81 | // Making it small will allow a few requests to succeed before the tx buffer 82 | // overflows and the usiTwiSlave.c hangs on the "while ( tmphead == txTail );" 83 | // line 84 | master_bytes = 2; 85 | } 86 | 87 | void setup() 88 | { 89 | // initialize the TinyWireS and usiTwiSlave libraries 90 | TinyWireS.begin(I2C_SLAVE_ADDR); // init I2C Slave mode 91 | 92 | // register the onReceive() callback function 93 | TinyWireS.onReceive(receiveEvent); 94 | 95 | // register the onRequest() callback function 96 | TinyWireS.onRequest(requestEvent); 97 | } 98 | 99 | void loop() 100 | { 101 | // This needs to be here 102 | TinyWireS_stop_check(); 103 | // otherwise empty loop 104 | } 105 | -------------------------------------------------------------------------------- /TinyWireS/examples/TinyWireS_Stress_Master/TinyWireS_Stress_Master.ino: -------------------------------------------------------------------------------- 1 | // --------------------------------- 2 | // Stress test program/example for TinyWireS I2C library. 3 | // Run this master program on the Arduino Uno R3. 4 | // Run the other slave program on the Attiny. 5 | // --------------------------------- 6 | // Written by Scott Hartog, 2/6/2016 7 | // This is the I2C master program which runs on on a regular Arduino 8 | // (not a AtTiny). This program uses the regular Wire library from the Arduino IDE. 9 | // 10 | // It performs these steps in a loop: 11 | // 1. picks a random number of bytes between 1 and 12 12 | // 2. sends that many bytes of random data to the AtTiny slave within 13 | // a single Wire.beginTransmission() / Wire.write() / Wire.endTransmission() set 14 | // 3. reads that same number of bytes back with a single Wire.requestFrom() call 15 | // 4. compares the received data to the originally transmitted data 16 | // 5. displays the number of requests, number of requests with mismatches, 17 | // and enough of the data so that the operator can tell it's working. 18 | // 19 | #include 20 | 21 | // BREADBOARD SETUP: 22 | // Arduino Uno R3 (D18/SDA) = I2C SDA 23 | // connect to SDA on slave with external pull-up (~4.7K) 24 | // Arduino Uno R3 (D19/SCL) = I2C SCL 25 | // connect to SCL on slave with external pull-up (~4.7K) 26 | // Arduino Uno R3 (D2) 27 | // connect to !RST on slave 28 | // Can alternatively connect !RST on slave to the Ardiuno "!RESET" pin 29 | 30 | #define I2C_SLAVE_ADDR 0x26 // i2c slave address (38, 0x26) 31 | 32 | #define SLAVE_RESET_PIN 2 33 | 34 | uint16_t count = 0; // total number of passes so far 35 | uint16_t error_count = 0; // total errors encountered so far 36 | 37 | char c_buf[64]; // for creating messages 38 | 39 | void setup() 40 | { 41 | // set pin modes 42 | pinMode(SLAVE_RESET_PIN,OUTPUT); 43 | 44 | // init the serial port 45 | Serial.begin(115200); 46 | 47 | // print some useful pinnout info for the Arduino 48 | //Serial.println(String("SCL:")+String(SCL)+String(", SDA:")+String(SDA)); 49 | //Serial.println(String("MOSI:")+String(MOSI)+String(", SCK:")+String(SCK)); 50 | 51 | // init the Wire object (for I2C) 52 | Wire.begin(); 53 | 54 | // reset the slave 55 | digitalWrite(SLAVE_RESET_PIN, LOW); 56 | delay(10); 57 | digitalWrite(SLAVE_RESET_PIN, HIGH); 58 | 59 | // wait for slave to finish any init sequence 60 | delay(2000); 61 | } 62 | 63 | void loop() 64 | { 65 | uint8_t i; 66 | uint8_t req_rtn; // num bytes returned by requestFrom() call 67 | uint8_t rand_byte_count; 68 | uint8_t out_rand[16]; // data written from master 69 | uint8_t in_rand[16]; // data read back from slave 70 | 71 | bool mismatch; 72 | 73 | // count total number of request 74 | count++; 75 | 76 | // compute random number of bytes for this pass 77 | rand_byte_count = random(12) + 1; 78 | 79 | // force the first three requests to be small so that the tx buffer doesn't overflow 80 | // instantly and the user can see at least one successful transaction and some 81 | // mismtaches before the usiTwiSlave.c library hangs on the line "while ( tmphead == txTail );". 82 | if (count <= 3) rand_byte_count = 2; 83 | 84 | // generate, save, and send N random byte values 85 | Wire.beginTransmission(I2C_SLAVE_ADDR); 86 | for (i = 0; i < rand_byte_count; i++) 87 | Wire.write(out_rand[i] = random(256)); 88 | Wire.endTransmission(); 89 | 90 | //delay (10); // optional delay if required by slave (like sample ADC) 91 | 92 | // read N bytes from slave 93 | req_rtn = Wire.requestFrom(I2C_SLAVE_ADDR, (int)rand_byte_count); // Request N bytes from slave 94 | for (i = 0; i < req_rtn; i++) 95 | in_rand[i] = Wire.read(); 96 | 97 | // compare in/out data values 98 | mismatch = false; 99 | for (i = 0; i < rand_byte_count; i++) 100 | mismatch = mismatch || (out_rand[i] != in_rand[i]); 101 | 102 | // increment the error counter if the number of byte variables don't match or 103 | // if the data itself doesn't match 104 | if (mismatch || (rand_byte_count != req_rtn)) error_count++; 105 | 106 | // The rest of the program just displays the results 107 | 108 | // display total requests so far and error count so far 109 | snprintf(c_buf, sizeof(c_buf), "req: %3d,err: %3d", count, error_count); 110 | Serial.println(c_buf); 111 | 112 | // display the random byte count, the number of bytes read back, and "MATCH"/"MISMATCH" 113 | snprintf(c_buf, sizeof(c_buf), "size: %2d/%2d,%s", rand_byte_count, req_rtn, rand_byte_count != req_rtn?"MISMATCH <<--- !!!":"MATCH"); 114 | Serial.println(c_buf); 115 | 116 | // display whether the data compare matched or mismatched 117 | snprintf(c_buf, sizeof(c_buf), "data: %s", mismatch?"MISMATCH <<--- !!!":"MATCH"); 118 | Serial.println(c_buf); 119 | 120 | // send up to three tx/rx bytes so that random data can be 121 | // visually verified 122 | if (rand_byte_count >= 1) 123 | { 124 | snprintf(c_buf, sizeof(c_buf), "rand[0]: %02x/%02x", out_rand[0], in_rand[0]); 125 | Serial.println(c_buf); 126 | } 127 | 128 | if (rand_byte_count >= 2) 129 | { 130 | snprintf(c_buf, sizeof(c_buf), "rand[1]: %02x/%02x", out_rand[1], in_rand[1]); 131 | Serial.println(c_buf); 132 | } 133 | 134 | if (rand_byte_count >= 3) 135 | { 136 | snprintf(c_buf, sizeof(c_buf), "rand[2]: %02x/%02x", out_rand[2], in_rand[2]); 137 | Serial.println(c_buf); 138 | } 139 | 140 | // delay 1 second so user can watch results 141 | delay(1000); 142 | } 143 | -------------------------------------------------------------------------------- /TinyWireS/examples/attiny85_i2c_slave/attiny85_i2c_slave.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Example sketch for writing to and reading from a slave in transactional manner 3 | * 4 | * NOTE: You must not use delay() or I2C communications will fail, use tws_delay() instead (or preferably some smarter timing system) 5 | * 6 | * On write the first byte received is considered the register addres to modify/read 7 | * On each byte sent or read the register address is incremented (and it will loop back to 0) 8 | * 9 | * You can try this with the Arduino I2C REPL sketch at https://github.com/rambo/I2C/blob/master/examples/i2crepl/i2crepl.ino 10 | * If you have bus-pirate remember that the older revisions do not like the slave streching the clock, this leads to all sorts of weird behaviour 11 | * 12 | * To read third value (register number 2 since counting starts at 0) send "[ 8 2 [ 9 r ]", value read should be 0xBE 13 | * If you then send "[ 9 r r r ]" you should get 0xEF 0xDE 0xAD as response (demonstrating the register counter looping back to zero) 14 | * 15 | * You need to have at least 8MHz clock on the ATTiny for this to work (and in fact I have so far tested it only on ATTiny85 @8MHz using internal oscillator) 16 | * Remember to "Burn bootloader" to make sure your chip is in correct mode 17 | */ 18 | 19 | 20 | /** 21 | * Pin notes by Suovula, see also http://hlt.media.mit.edu/?p=1229 22 | * 23 | * DIP and SOIC have same pinout, however the SOIC chips are much cheaper, especially if you buy more than 5 at a time 24 | * For nice breakout boards see https://github.com/rambo/attiny_boards 25 | * 26 | * Basically the arduino pin numbers map directly to the PORTB bit numbers. 27 | * 28 | // I2C 29 | arduino pin 0 = not(OC1A) = PORTB <- _BV(0) = SOIC pin 5 (I2C SDA, PWM) 30 | arduino pin 2 = = PORTB <- _BV(2) = SOIC pin 7 (I2C SCL, Analog 1) 31 | // Timer1 -> PWM 32 | arduino pin 1 = OC1A = PORTB <- _BV(1) = SOIC pin 6 (PWM) 33 | arduino pin 3 = not(OC1B) = PORTB <- _BV(3) = SOIC pin 2 (Analog 3) 34 | arduino pin 4 = OC1B = PORTB <- _BV(4) = SOIC pin 3 (Analog 2) 35 | */ 36 | #define I2C_SLAVE_ADDRESS 0x4 // the 7-bit address (remember to change this when adapting this example) 37 | // Get this from https://github.com/rambo/TinyWire 38 | #include 39 | // The default buffer size, Can't recall the scope of defines right now 40 | #ifndef TWI_RX_BUFFER_SIZE 41 | #define TWI_RX_BUFFER_SIZE ( 16 ) 42 | #endif 43 | 44 | 45 | volatile uint8_t i2c_regs[] = 46 | { 47 | 0xDE, 48 | 0xAD, 49 | 0xBE, 50 | 0xEF, 51 | }; 52 | // Tracks the current register pointer position 53 | volatile byte reg_position; 54 | const byte reg_size = sizeof(i2c_regs); 55 | 56 | /** 57 | * This is called for each read request we receive, never put more than one byte of data (with TinyWireS.send) to the 58 | * send-buffer when using this callback 59 | */ 60 | void requestEvent() 61 | { 62 | TinyWireS.send(i2c_regs[reg_position]); 63 | // Increment the reg position on each read, and loop back to zero 64 | reg_position++; 65 | if (reg_position >= reg_size) 66 | { 67 | reg_position = 0; 68 | } 69 | } 70 | 71 | // TODO: Either update this to use something smarter for timing or remove it alltogether 72 | void blinkn(uint8_t blinks) 73 | { 74 | digitalWrite(3, HIGH); 75 | while(blinks--) 76 | { 77 | digitalWrite(3, LOW); 78 | tws_delay(50); 79 | digitalWrite(3, HIGH); 80 | tws_delay(100); 81 | } 82 | } 83 | 84 | /** 85 | * The I2C data received -handler 86 | * 87 | * This needs to complete before the next incoming transaction (start, data, restart/stop) on the bus does 88 | * so be quick, set flags for long running tasks to be called from the mainloop instead of running them directly, 89 | */ 90 | void receiveEvent(uint8_t howMany) 91 | { 92 | if (howMany < 1) 93 | { 94 | // Sanity-check 95 | return; 96 | } 97 | if (howMany > TWI_RX_BUFFER_SIZE) 98 | { 99 | // Also insane number 100 | return; 101 | } 102 | 103 | reg_position = TinyWireS.receive(); 104 | howMany--; 105 | if (!howMany) 106 | { 107 | // This write was only to set the buffer for next read 108 | return; 109 | } 110 | while(howMany--) 111 | { 112 | i2c_regs[reg_position] = TinyWireS.receive(); 113 | reg_position++; 114 | if (reg_position >= reg_size) 115 | { 116 | reg_position = 0; 117 | } 118 | } 119 | } 120 | 121 | 122 | void setup() 123 | { 124 | // TODO: Tri-state this and wait for input voltage to stabilize 125 | pinMode(3, OUTPUT); // OC1B-, Arduino pin 3, ADC 126 | digitalWrite(3, LOW); // Note that this makes the led turn on, it's wire this way to allow for the voltage sensing above. 127 | 128 | pinMode(1, OUTPUT); // OC1A, also The only HW-PWM -pin supported by the tiny core analogWrite 129 | 130 | /** 131 | * Reminder: taking care of pull-ups is the masters job 132 | */ 133 | 134 | TinyWireS.begin(I2C_SLAVE_ADDRESS); 135 | TinyWireS.onReceive(receiveEvent); 136 | TinyWireS.onRequest(requestEvent); 137 | 138 | 139 | // Whatever other setup routines ? 140 | 141 | digitalWrite(3, HIGH); 142 | } 143 | 144 | void loop() 145 | { 146 | /** 147 | * This is the only way we can detect stop condition (http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=984716&sid=82e9dc7299a8243b86cf7969dd41b5b5#984716) 148 | * it needs to be called in a very tight loop in order not to miss any (REMINDER: Do *not* use delay() anywhere, use tws_delay() instead). 149 | * It will call the function registered via TinyWireS.onReceive(); if there is data in the buffer on stop. 150 | */ 151 | TinyWireS_stop_check(); 152 | } 153 | -------------------------------------------------------------------------------- /TinyWireS/examples/attiny85_i2c_analog/attiny85_i2c_analog.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Example sketch for writing to and reading from a slave in transactional manner 3 | * 4 | * NOTE: You must not use delay() or I2C communications will fail, use tws_delay() instead (or preferably some smarter timing system) 5 | * 6 | * On write the first byte received is considered the register addres to modify/read 7 | * On each byte sent or read the register address is incremented (and it will loop back to 0) 8 | * 9 | * You can try this with the Arduino I2C REPL sketch at https://github.com/rambo/I2C/blob/master/examples/i2crepl/i2crepl.ino 10 | * If you have bus-pirate remember that the older revisions do not like the slave streching the clock, this leads to all sorts of weird behaviour 11 | * Examples use bus-pirate semantics (like the REPL) 12 | * 13 | * The basic idea is: 14 | * 1. Choose your ADC channel (0-X), use "byte ch = 1;" for example. 15 | * 2. Combine the channel and conversion start flag to single calue: byte start_on_ch = (ch | _BV(7)); // This is 0x81 16 | * 3. Write start_on_ch to the first register on the attiny [ 8 0 81 ] 17 | * 4. Come back later and check the first register [ 8 0 [ r ], if the value is same as ch then the conversion is complete, you can now read the value 18 | * 5. read the value [ 8 2 [ r r ] (first one is low, second high byte) 19 | * 20 | * You need to have at least 8MHz clock on the ATTiny for this to work (and in fact I have so far tested it only on ATTiny85 @8MHz using internal oscillator) 21 | * Remember to "Burn bootloader" to make sure your chip is in correct mode 22 | */ 23 | 24 | 25 | /** 26 | * Pin notes by Suovula, see also http://hlt.media.mit.edu/?p=1229 27 | * 28 | * DIP and SOIC have same pinout, however the SOIC chips are much cheaper, especially if you buy more than 5 at a time 29 | * For nice breakout boards see https://github.com/rambo/attiny_boards 30 | * 31 | * Basically the arduino pin numbers map directly to the PORTB bit numbers. 32 | * 33 | // I2C 34 | arduino pin 0 = not(OC1A) = PORTB <- _BV(0) = SOIC pin 5 (I2C SDA, PWM) 35 | arduino pin 2 = = PORTB <- _BV(2) = SOIC pin 7 (I2C SCL, Analog 1) 36 | // Timer1 -> PWM 37 | arduino pin 1 = OC1A = PORTB <- _BV(1) = SOIC pin 6 (PWM) 38 | arduino pin 3 = not(OC1B) = PORTB <- _BV(3) = SOIC pin 2 (Analog 3) 39 | arduino pin 4 = OC1B = PORTB <- _BV(4) = SOIC pin 3 (Analog 2) 40 | */ 41 | #define I2C_SLAVE_ADDRESS 0x4 // the 7-bit address (remember to change this when adapting this example) 42 | // Get this from https://github.com/rambo/TinyWire 43 | #include 44 | // The default buffer size, though we cannot actually affect it by defining it in the sketch 45 | #ifndef TWI_RX_BUFFER_SIZE 46 | #define TWI_RX_BUFFER_SIZE ( 16 ) 47 | #endif 48 | // For the ADC_xxx helpers 49 | #include 50 | 51 | // The "registers" we expose to I2C 52 | volatile uint8_t i2c_regs[] = 53 | { 54 | 0x0, // Status register, writing (1<<7 & channel) will start a conversion on that channel, the flag will be set low when conversion is done. 55 | 0x1, // Averaging count, make this many conversions in row and average the result (well, actually it's a rolling average since we do not want to have the possibility of integer overflows) 56 | 0x0, // low byte 57 | 0x0, // high byte 58 | }; 59 | const byte reg_size = sizeof(i2c_regs); 60 | // Tracks the current register pointer position 61 | volatile byte reg_position; 62 | // Tracks wheter to start a conversion cycle 63 | volatile boolean start_conversion; 64 | // Counter to track where we are averaging 65 | byte avg_count; 66 | // Some temp value holders 67 | int avg_temp1; 68 | int avg_temp2; 69 | 70 | /** 71 | * This is called for each read request we receive, never put more than one byte of data (with TinyWireS.send) to the 72 | * send-buffer when using this callback 73 | */ 74 | void requestEvent() 75 | { 76 | TinyWireS.send(i2c_regs[reg_position]); 77 | // Increment the reg position on each read, and loop back to zero 78 | reg_position++; 79 | if (reg_position >= reg_size) 80 | { 81 | reg_position = 0; 82 | } 83 | } 84 | 85 | /** 86 | * The I2C data received -handler 87 | * 88 | * This needs to complete before the next incoming transaction (start, data, restart/stop) on the bus does 89 | * so be quick, set flags for long running tasks to be called from the mainloop instead of running them directly, 90 | */ 91 | void receiveEvent(uint8_t howMany) 92 | { 93 | if (howMany < 1) 94 | { 95 | // Sanity-check 96 | return; 97 | } 98 | if (howMany > TWI_RX_BUFFER_SIZE) 99 | { 100 | // Also insane number 101 | return; 102 | } 103 | 104 | reg_position = TinyWireS.receive(); 105 | howMany--; 106 | if (!howMany) 107 | { 108 | // This write was only to set the buffer for next read 109 | return; 110 | } 111 | while(howMany--) 112 | { 113 | i2c_regs[reg_position] = TinyWireS.receive(); 114 | if ( reg_position == 0 // If it was the first register 115 | && bitRead(i2c_regs[0], 7) // And the highest bit is set 116 | && !ADC_ConversionInProgress() // and we do not actually have a conversion running already 117 | ) 118 | { 119 | start_conversion = true; 120 | } 121 | reg_position++; 122 | if (reg_position >= reg_size) 123 | { 124 | reg_position = 0; 125 | } 126 | } 127 | } 128 | 129 | 130 | void setup() 131 | { 132 | // TODO: Tri-state this and wait for input voltage to stabilize 133 | pinMode(3, OUTPUT); // OC1B-, Arduino pin 3, ADC 134 | digitalWrite(3, LOW); // Note that this makes the led turn on, it's wire this way to allow for the voltage sensing above. 135 | 136 | pinMode(1, OUTPUT); // OC1A, also The only HW-PWM -pin supported by the tiny core analogWrite 137 | 138 | /** 139 | * Reminder: taking care of pull-ups is the masters job 140 | */ 141 | 142 | TinyWireS.begin(I2C_SLAVE_ADDRESS); 143 | TinyWireS.onReceive(receiveEvent); 144 | TinyWireS.onRequest(requestEvent); 145 | 146 | 147 | // Whatever other setup routines ? 148 | 149 | digitalWrite(3, HIGH); 150 | } 151 | 152 | void loop() 153 | { 154 | /** 155 | * This is the only way we can detect stop condition (http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=984716&sid=82e9dc7299a8243b86cf7969dd41b5b5#984716) 156 | * it needs to be called in a very tight loop in order not to miss any (REMINDER: Do *not* use delay() anywhere, use tws_delay() instead). 157 | * It will call the function registered via TinyWireS.onReceive(); if there is data in the buffer on stop. 158 | */ 159 | TinyWireS_stop_check(); 160 | 161 | // Thus stuff is basically copied from wiring_analog.c 162 | if (start_conversion) 163 | { 164 | //Avoid doubled starts 165 | start_conversion = false; 166 | byte adcpin = (i2c_regs[0] & 0x7f); // Set the channel from the control reg, dropping the highest bit. 167 | #if defined( CORE_ANALOG_FIRST ) 168 | if ( adcpin >= CORE_ANALOG_FIRST ) adcpin -= CORE_ANALOG_FIRST; // allow for channel or pin numbers 169 | #endif 170 | // NOTE: These handy helpers (ADC_xxx) are only present in the tiny-core, for other cores you need to check their wiring_analog.c source. 171 | ADC_SetInputChannel( (adc_ic_t)adcpin ); // we need to typecast 172 | ADC_StartConversion(); 173 | // Reset these variables 174 | avg_count = 0; 175 | avg_temp2 = 0; 176 | } 177 | 178 | if ( bitRead(i2c_regs[0], 7) // We have conversion flag up 179 | && !ADC_ConversionInProgress()) // But the conversion is complete 180 | { 181 | // So handle it 182 | avg_temp1 = ADC_GetDataRegister(); 183 | // Rolling average 184 | if (avg_count) 185 | { 186 | avg_temp2 = (avg_temp2+avg_temp1)/2; 187 | } 188 | else 189 | { 190 | avg_temp2 = avg_temp1; 191 | } 192 | avg_count++; 193 | if (avg_count >= i2c_regs[1]) 194 | { 195 | // All done, set the bytes to registers 196 | cli(); 197 | i2c_regs[2] = lowByte(avg_temp2); 198 | i2c_regs[3] = highByte(avg_temp2); 199 | sei(); 200 | // And clear the conversion flag so the master knows we're ready 201 | bitClear(i2c_regs[0], 7); 202 | } 203 | else 204 | { 205 | // Re-trigger conversion 206 | ADC_StartConversion(); 207 | } 208 | } 209 | 210 | } 211 | -------------------------------------------------------------------------------- /TinyWireS/examples/attiny85_i2c_slave_task/attiny85_i2c_slave_task.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Example sketch for writing to and reading from a slave in transactional manner, it will also blink a led attached to pin 3 (which is the SOIC pin 2) 3 | * (provided you're using one of my ATTiny85 boards from https://github.com/rambo/attiny_boards with the led soldered) 4 | * 5 | * NOTE: You must not use delay() or I2C communications will fail, use tws_delay() instead (or preferably some smarter timing system, like the Task library used in this example) 6 | * 7 | * On write the first byte received is considered the register addres to modify/read 8 | * On each byte sent or read the register address is incremented (and it will loop back to 0) 9 | * 10 | * You can try this with the Arduino I2C REPL sketch at https://github.com/rambo/I2C/blob/master/examples/i2crepl/i2crepl.ino 11 | * If you have bus-pirate remember that the older revisions do not like the slave streching the clock, this leads to all sorts of weird behaviour 12 | * 13 | * By default this blinks the SOS morse pattern and then has long on/off time to indicate end of pattern, send [ 8 0 32 ] (using the REPL/bus-pirate 14 | * semantics) to make the delay per bit smaller (and thus blinking faster). The pattern lenght is calculated from the register size, it would be fairly 15 | * trivial to make it yet another variable changeable via I2C. 16 | * 17 | * You need to have at least 8MHz clock on the ATTiny for this to work (and in fact I have so far tested it only on ATTiny85 @8MHz using internal oscillator) 18 | * Remember to "Burn bootloader" to make sure your chip is in correct mode 19 | */ 20 | 21 | 22 | /** 23 | * Pin notes by Suovula, see also http://hlt.media.mit.edu/?p=1229 24 | * 25 | * DIP and SOIC have same pinout, however the SOIC chips are much cheaper, especially if you buy more than 5 at a time 26 | * For nice breakout boards see https://github.com/rambo/attiny_boards 27 | * 28 | * Basically the arduino pin numbers map directly to the PORTB bit numbers. 29 | * 30 | // I2C 31 | arduino pin 0 = not(OC1A) = PORTB <- _BV(0) = SOIC pin 5 (I2C SDA, PWM) 32 | arduino pin 2 = = PORTB <- _BV(2) = SOIC pin 7 (I2C SCL, Analog 1) 33 | // Timer1 -> PWM 34 | arduino pin 1 = OC1A = PORTB <- _BV(1) = SOIC pin 6 (PWM) 35 | arduino pin 3 = not(OC1B) = PORTB <- _BV(3) = SOIC pin 2 (Analog 3) 36 | arduino pin 4 = OC1B = PORTB <- _BV(4) = SOIC pin 3 (Analog 2) 37 | */ 38 | #define I2C_SLAVE_ADDRESS 0x4 // the 7-bit address (remember to change this when adapting this example) 39 | // Get this from https://github.com/rambo/TinyWire 40 | #include 41 | // The default buffer size, Can't recall the scope of defines right now 42 | #ifndef TWI_RX_BUFFER_SIZE 43 | #define TWI_RX_BUFFER_SIZE ( 16 ) 44 | #endif 45 | // Get this library from http://bleaklow.com/files/2010/Task.tar.gz 46 | // and read http://bleaklow.com/2010/07/20/a_very_simple_arduino_task_manager.html for background and instructions 47 | #include 48 | #include 49 | 50 | // The led is connected so that the tiny sinks current 51 | #define LED_ON LOW 52 | #define LED_OFF HIGH 53 | 54 | // The I2C registers 55 | volatile uint8_t i2c_regs[] = 56 | { 57 | 150, // Delay between each position (ms, remeber that this isa byte so 255 is max) 58 | B10101000, // SOS pattern 59 | B01110111, 60 | B01110001, 61 | B01010000, 62 | B00000000, 63 | B11111111, // Long on and off to mark end of pattern 64 | B00000000, 65 | }; 66 | // Tracks the current register pointer position 67 | volatile byte reg_position; 68 | const byte reg_size = sizeof(i2c_regs); 69 | 70 | 71 | /** 72 | * BEGIN: PatternBlinker task based on the Task library Blinker example 73 | */ 74 | // Timed task to blink a LED. 75 | const byte pattern_lenght = (sizeof(i2c_regs)-1) * 8; // bits (first is the speed, rest is the pattern) 76 | class PatternBlinker : public TimedTask 77 | { 78 | public: 79 | // Create a new blinker for the specified pin and rate. 80 | PatternBlinker(uint8_t _pin); 81 | virtual void run(uint32_t now); 82 | private: 83 | uint8_t pin; // LED pin. 84 | uint8_t pattern_position; // Used to calcuate the register and bit offset 85 | }; 86 | 87 | PatternBlinker::PatternBlinker(uint8_t _pin) 88 | : TimedTask(millis()), 89 | pin(_pin) 90 | { 91 | pinMode(pin, OUTPUT); // Set pin for output. 92 | } 93 | 94 | void PatternBlinker::run(uint32_t now) 95 | { 96 | // Start by setting the next runtime 97 | incRunTime(i2c_regs[0]); 98 | 99 | // Written out for clear code, the complier might optimize it to something more efficient even without it being unrolled into one line 100 | byte reg = i2c_regs[1+(pattern_position/8)]; // Get the register where the bit pattern position is stored 101 | byte shift_amount = 7 - (pattern_position % 7); // To have "natural" left-to-right pattern flow. 102 | bool state = (reg >> shift_amount) & 0x1; 103 | if (state) { 104 | digitalWrite(pin, LED_ON); 105 | } else { 106 | digitalWrite(pin, LED_OFF); 107 | } 108 | // Calculate the next pattern position 109 | pattern_position = (pattern_position+1) % pattern_lenght; 110 | } 111 | /** 112 | * END: PatternBlinker task copied from the Task library example 113 | */ 114 | /** 115 | * BEGIN: I2C Stop flag checker 116 | * 117 | * This task needs to run almost all the time due to the USI I2C implementation limitations 118 | * 119 | * So I2CStopCheck_YIELD_TICKS below is used to specify how often the task is run, not it's every 4 ticks 120 | */ 121 | #define I2CStopCheck_YIELD_TICKS 4 122 | class I2CStopCheck : public Task 123 | { 124 | public: 125 | I2CStopCheck(); 126 | virtual void run(uint32_t now); 127 | virtual bool canRun(uint32_t now); 128 | private: 129 | uint8_t yield_counter; // Incremented on each canRun call, used to yield to other tasks. 130 | }; 131 | 132 | I2CStopCheck::I2CStopCheck() 133 | : Task() 134 | { 135 | } 136 | 137 | // We can't just return true since then no other task could ever run (since we have the priority) 138 | bool I2CStopCheck::canRun(uint32_t now) 139 | { 140 | yield_counter++; 141 | bool ret = false; 142 | if (yield_counter == I2CStopCheck_YIELD_TICKS) 143 | { 144 | ret = true; 145 | yield_counter = 0; 146 | } 147 | return ret; 148 | } 149 | 150 | void I2CStopCheck::run(uint32_t now) 151 | { 152 | TinyWireS_stop_check(); 153 | } 154 | /** 155 | * END: I2C Stop flag checker 156 | */ 157 | 158 | // Create the tasks. 159 | PatternBlinker blinker(3); 160 | I2CStopCheck checker; 161 | 162 | // Tasks are in priority order, only one task is run per tick 163 | Task *tasks[] = { &checker, &blinker, }; 164 | TaskScheduler sched(tasks, NUM_TASKS(tasks)); 165 | 166 | 167 | /** 168 | * This is called for each read request we receive, never put more than one byte of data (with TinyWireS.send) to the 169 | * send-buffer when using this callback 170 | */ 171 | void requestEvent() 172 | { 173 | TinyWireS.send(i2c_regs[reg_position]); 174 | // Increment the reg position on each read, and loop back to zero 175 | reg_position++; 176 | if (reg_position >= reg_size) 177 | { 178 | reg_position = 0; 179 | } 180 | } 181 | 182 | /** 183 | * The I2C data received -handler 184 | * 185 | * This needs to complete before the next incoming transaction (start, data, restart/stop) on the bus does 186 | * so be quick, set flags for long running tasks to be called from the mainloop instead of running them directly, 187 | */ 188 | void receiveEvent(uint8_t howMany) 189 | { 190 | if (howMany < 1) 191 | { 192 | // Sanity-check 193 | return; 194 | } 195 | if (howMany > TWI_RX_BUFFER_SIZE) 196 | { 197 | // Also insane number 198 | return; 199 | } 200 | 201 | reg_position = TinyWireS.receive(); 202 | howMany--; 203 | if (!howMany) 204 | { 205 | // This write was only to set the buffer for next read 206 | return; 207 | } 208 | while(howMany--) 209 | { 210 | i2c_regs[reg_position] = TinyWireS.receive(); 211 | reg_position++; 212 | if (reg_position >= reg_size) 213 | { 214 | reg_position = 0; 215 | } 216 | } 217 | } 218 | 219 | 220 | void setup() 221 | { 222 | // TODO: Tri-state this and wait for input voltage to stabilize 223 | pinMode(3, OUTPUT); // OC1B-, Arduino pin 3, ADC 224 | digitalWrite(3, LED_ON); // Note that this makes the led turn on, it's wire this way to allow for the voltage sensing above. 225 | 226 | pinMode(1, OUTPUT); // OC1A, also The only HW-PWM -pin supported by the tiny core analogWrite 227 | 228 | /** 229 | * Reminder: taking care of pull-ups is the masters job 230 | */ 231 | 232 | TinyWireS.begin(I2C_SLAVE_ADDRESS); 233 | TinyWireS.onReceive(receiveEvent); 234 | TinyWireS.onRequest(requestEvent); 235 | 236 | 237 | // Whatever other setup routines ? 238 | 239 | digitalWrite(3, LED_OFF); 240 | } 241 | 242 | void loop() 243 | { 244 | // Run the scheduler - never returns. 245 | sched.run(); 246 | } 247 | -------------------------------------------------------------------------------- /TinyWireS/usiTwiSlave.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | 3 | USI TWI Slave driver. 4 | 5 | Created by Donald R. Blake. donblake at worldnet.att.net 6 | Adapted by Jochen Toppe, jochen.toppe at jtoee.com 7 | 8 | --------------------------------------------------------------------------------- 9 | 10 | Created from Atmel source files for Application Note AVR312: Using the USI Module 11 | as an I2C slave. 12 | 13 | This program is free software; you can redistribute it and/or modify it under the 14 | terms of the GNU General Public License as published by the Free Software 15 | Foundation; either version 2 of the License, or (at your option) any later 16 | version. 17 | 18 | This program is distributed in the hope that it will be useful, but WITHOUT ANY 19 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 20 | PARTICULAR PURPOSE. See the GNU General Public License for more details. 21 | 22 | --------------------------------------------------------------------------------- 23 | 24 | Change Activity: 25 | 26 | Date Description 27 | ------ ------------- 28 | 16 Mar 2007 Created. 29 | 27 Mar 2007 Added support for ATtiny261, 461 and 861. 30 | 26 Apr 2007 Fixed ACK of slave address on a read. 31 | 04 Jul 2007 Fixed USISIF in ATtiny45 def 32 | 12 Dev 2009 Added callback functions for data requests 33 | 06 Feb 2015 Minor change to allow mutli-byte requestFrom() from master. 34 | 10 Feb 2015 Simplied RX/TX buffer code and allowed use of full buffer. 35 | 36 | ********************************************************************************/ 37 | 38 | 39 | /******************************************************************************** 40 | includes 41 | ********************************************************************************/ 42 | 43 | #include 44 | #include 45 | 46 | #include "usiTwiSlave.h" 47 | //#include "../common/util.h" 48 | 49 | 50 | /******************************************************************************** 51 | device dependent defines 52 | ********************************************************************************/ 53 | 54 | #if defined( __AVR_ATtiny2313__ ) 55 | # define DDR_USI DDRB 56 | # define PORT_USI PORTB 57 | # define PIN_USI PINB 58 | # define PORT_USI_SDA PB5 59 | # define PORT_USI_SCL PB7 60 | # define PIN_USI_SDA PINB5 61 | # define PIN_USI_SCL PINB7 62 | # define USI_START_COND_INT USISIF 63 | # define USI_START_VECTOR USI_START_vect 64 | # define USI_OVERFLOW_VECTOR USI_OVERFLOW_vect 65 | #endif 66 | 67 | #if defined(__AVR_ATtiny84__) | \ 68 | defined(__AVR_ATtiny44__) 69 | # define DDR_USI DDRA 70 | # define PORT_USI PORTA 71 | # define PIN_USI PINA 72 | # define PORT_USI_SDA PORTA6 73 | # define PORT_USI_SCL PORTA4 74 | # define PIN_USI_SDA PINA6 75 | # define PIN_USI_SCL PINA4 76 | # define USI_START_COND_INT USISIF 77 | # define USI_START_VECTOR USI_START_vect 78 | # define USI_OVERFLOW_VECTOR USI_OVF_vect 79 | #endif 80 | 81 | #if defined( __AVR_ATtiny25__ ) | \ 82 | defined( __AVR_ATtiny45__ ) | \ 83 | defined( __AVR_ATtiny85__ ) 84 | # define DDR_USI DDRB 85 | # define PORT_USI PORTB 86 | # define PIN_USI PINB 87 | # define PORT_USI_SDA PB0 88 | # define PORT_USI_SCL PB2 89 | # define PIN_USI_SDA PINB0 90 | # define PIN_USI_SCL PINB2 91 | # define USI_START_COND_INT USISIF 92 | # define USI_START_VECTOR USI_START_vect 93 | # define USI_OVERFLOW_VECTOR USI_OVF_vect 94 | #endif 95 | 96 | #if defined( __AVR_ATtiny26__ ) 97 | # define DDR_USI DDRB 98 | # define PORT_USI PORTB 99 | # define PIN_USI PINB 100 | # define PORT_USI_SDA PB0 101 | # define PORT_USI_SCL PB2 102 | # define PIN_USI_SDA PINB0 103 | # define PIN_USI_SCL PINB2 104 | # define USI_START_COND_INT USISIF 105 | # define USI_START_VECTOR USI_STRT_vect 106 | # define USI_OVERFLOW_VECTOR USI_OVF_vect 107 | #endif 108 | 109 | #if defined( __AVR_ATtiny261__ ) | \ 110 | defined( __AVR_ATtiny461__ ) | \ 111 | defined( __AVR_ATtiny861__ ) 112 | # define DDR_USI DDRB 113 | # define PORT_USI PORTB 114 | # define PIN_USI PINB 115 | # define PORT_USI_SDA PB0 116 | # define PORT_USI_SCL PB2 117 | # define PIN_USI_SDA PINB0 118 | # define PIN_USI_SCL PINB2 119 | # define USI_START_COND_INT USISIF 120 | # define USI_START_VECTOR USI_START_vect 121 | # define USI_OVERFLOW_VECTOR USI_OVF_vect 122 | #endif 123 | 124 | #if defined( __AVR_ATmega165__ ) | \ 125 | defined( __AVR_ATmega325__ ) | \ 126 | defined( __AVR_ATmega3250__ ) | \ 127 | defined( __AVR_ATmega645__ ) | \ 128 | defined( __AVR_ATmega6450__ ) | \ 129 | defined( __AVR_ATmega329__ ) | \ 130 | defined( __AVR_ATmega3290__ ) 131 | # define DDR_USI DDRE 132 | # define PORT_USI PORTE 133 | # define PIN_USI PINE 134 | # define PORT_USI_SDA PE5 135 | # define PORT_USI_SCL PE4 136 | # define PIN_USI_SDA PINE5 137 | # define PIN_USI_SCL PINE4 138 | # define USI_START_COND_INT USISIF 139 | # define USI_START_VECTOR USI_START_vect 140 | # define USI_OVERFLOW_VECTOR USI_OVERFLOW_vect 141 | #endif 142 | 143 | #if defined( __AVR_ATmega169__ ) 144 | # define DDR_USI DDRE 145 | # define PORT_USI PORTE 146 | # define PIN_USI PINE 147 | # define PORT_USI_SDA PE5 148 | # define PORT_USI_SCL PE4 149 | # define PIN_USI_SDA PINE5 150 | # define PIN_USI_SCL PINE4 151 | # define USI_START_COND_INT USISIF 152 | # define USI_START_VECTOR USI_START_vect 153 | # define USI_OVERFLOW_VECTOR USI_OVERFLOW_vect 154 | #endif 155 | 156 | 157 | 158 | /******************************************************************************** 159 | 160 | functions implemented as macros 161 | 162 | ********************************************************************************/ 163 | 164 | #define SET_USI_TO_SEND_ACK( ) \ 165 | { \ 166 | /* prepare ACK */ \ 167 | USIDR = 0; \ 168 | /* set SDA as output */ \ 169 | DDR_USI |= ( 1 << PORT_USI_SDA ); \ 170 | /* clear all interrupt flags, except Start Cond */ \ 171 | USISR = \ 172 | ( 0 << USI_START_COND_INT ) | \ 173 | ( 1 << USIOIF ) | ( 1 << USIPF ) | \ 174 | ( 1 << USIDC )| \ 175 | /* set USI counter to shift 1 bit */ \ 176 | ( 0x0E << USICNT0 ); \ 177 | } 178 | 179 | #define SET_USI_TO_READ_ACK( ) \ 180 | { \ 181 | /* set SDA as input */ \ 182 | DDR_USI &= ~( 1 << PORT_USI_SDA ); \ 183 | /* prepare ACK */ \ 184 | USIDR = 0; \ 185 | /* clear all interrupt flags, except Start Cond */ \ 186 | USISR = \ 187 | ( 0 << USI_START_COND_INT ) | \ 188 | ( 1 << USIOIF ) | \ 189 | ( 1 << USIPF ) | \ 190 | ( 1 << USIDC ) | \ 191 | /* set USI counter to shift 1 bit */ \ 192 | ( 0x0E << USICNT0 ); \ 193 | } 194 | 195 | #define SET_USI_TO_TWI_START_CONDITION_MODE( ) \ 196 | { \ 197 | USICR = \ 198 | /* enable Start Condition Interrupt, disable Overflow Interrupt */ \ 199 | ( 1 << USISIE ) | ( 0 << USIOIE ) | \ 200 | /* set USI in Two-wire mode, no USI Counter overflow hold */ \ 201 | ( 1 << USIWM1 ) | ( 0 << USIWM0 ) | \ 202 | /* Shift Register Clock Source = External, positive edge */ \ 203 | /* 4-Bit Counter Source = external, both edges */ \ 204 | ( 1 << USICS1 ) | ( 0 << USICS0 ) | ( 0 << USICLK ) | \ 205 | /* no toggle clock-port pin */ \ 206 | ( 0 << USITC ); \ 207 | USISR = \ 208 | /* clear all interrupt flags, except Start Cond */ \ 209 | ( 0 << USI_START_COND_INT ) | ( 1 << USIOIF ) | ( 1 << USIPF ) | \ 210 | ( 1 << USIDC ) | ( 0x0 << USICNT0 ); \ 211 | } 212 | 213 | #define SET_USI_TO_SEND_DATA( ) \ 214 | { \ 215 | /* set SDA as output */ \ 216 | DDR_USI |= ( 1 << PORT_USI_SDA ); \ 217 | /* clear all interrupt flags, except Start Cond */ \ 218 | USISR = \ 219 | ( 0 << USI_START_COND_INT ) | ( 1 << USIOIF ) | ( 1 << USIPF ) | \ 220 | ( 1 << USIDC) | \ 221 | /* set USI to shift out 8 bits */ \ 222 | ( 0x0 << USICNT0 ); \ 223 | } 224 | 225 | #define SET_USI_TO_READ_DATA( ) \ 226 | { \ 227 | /* set SDA as input */ \ 228 | DDR_USI &= ~( 1 << PORT_USI_SDA ); \ 229 | /* clear all interrupt flags, except Start Cond */ \ 230 | USISR = \ 231 | ( 0 << USI_START_COND_INT ) | ( 1 << USIOIF ) | \ 232 | ( 1 << USIPF ) | ( 1 << USIDC ) | \ 233 | /* set USI to shift out 8 bits */ \ 234 | ( 0x0 << USICNT0 ); \ 235 | } 236 | 237 | #define USI_RECEIVE_CALLBACK() \ 238 | { \ 239 | if (usi_onReceiverPtr) \ 240 | { \ 241 | if (usiTwiAmountDataInReceiveBuffer()) \ 242 | { \ 243 | usi_onReceiverPtr(usiTwiAmountDataInReceiveBuffer()); \ 244 | } \ 245 | } \ 246 | } 247 | 248 | #define ONSTOP_USI_RECEIVE_CALLBACK() \ 249 | { \ 250 | if (USISR & ( 1 << USIPF )) \ 251 | { \ 252 | USI_RECEIVE_CALLBACK(); \ 253 | } \ 254 | } 255 | 256 | 257 | #define USI_REQUEST_CALLBACK() \ 258 | { \ 259 | USI_RECEIVE_CALLBACK(); \ 260 | if(usi_onRequestPtr) usi_onRequestPtr(); \ 261 | } 262 | 263 | /******************************************************************************** 264 | 265 | typedef's 266 | 267 | ********************************************************************************/ 268 | 269 | typedef enum 270 | { 271 | USI_SLAVE_CHECK_ADDRESS = 0x00, 272 | USI_SLAVE_SEND_DATA = 0x01, 273 | USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA = 0x02, 274 | USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA = 0x03, 275 | USI_SLAVE_REQUEST_DATA = 0x04, 276 | USI_SLAVE_GET_DATA_AND_SEND_ACK = 0x05 277 | } overflowState_t; 278 | 279 | 280 | 281 | /******************************************************************************** 282 | 283 | local variables 284 | 285 | ********************************************************************************/ 286 | 287 | static uint8_t slaveAddress; 288 | static volatile overflowState_t overflowState; 289 | 290 | 291 | static uint8_t rxBuf[ TWI_RX_BUFFER_SIZE ]; 292 | static volatile uint8_t rxHead; 293 | static volatile uint8_t rxTail; 294 | static volatile uint8_t rxCount; 295 | 296 | static uint8_t txBuf[ TWI_TX_BUFFER_SIZE ]; 297 | static volatile uint8_t txHead; 298 | static volatile uint8_t txTail; 299 | static volatile uint8_t txCount; 300 | 301 | 302 | 303 | /******************************************************************************** 304 | 305 | local functions 306 | 307 | ********************************************************************************/ 308 | 309 | 310 | 311 | // flushes the TWI buffers 312 | 313 | static 314 | void 315 | flushTwiBuffers( 316 | void 317 | ) 318 | { 319 | rxTail = 0; 320 | rxHead = 0; 321 | rxCount = 0; 322 | txTail = 0; 323 | txHead = 0; 324 | txCount = 0; 325 | } // end flushTwiBuffers 326 | 327 | 328 | 329 | /******************************************************************************** 330 | 331 | public functions 332 | 333 | ********************************************************************************/ 334 | 335 | 336 | 337 | // initialise USI for TWI slave mode 338 | 339 | void 340 | usiTwiSlaveInit( 341 | uint8_t ownAddress 342 | ) 343 | { 344 | 345 | flushTwiBuffers( ); 346 | 347 | slaveAddress = ownAddress; 348 | 349 | // In Two Wire mode (USIWM1, USIWM0 = 1X), the slave USI will pull SCL 350 | // low when a start condition is detected or a counter overflow (only 351 | // for USIWM1, USIWM0 = 11). This inserts a wait state. SCL is released 352 | // by the ISRs (USI_START_vect and USI_OVERFLOW_vect). 353 | 354 | // Set SCL and SDA as output 355 | DDR_USI |= ( 1 << PORT_USI_SCL ) | ( 1 << PORT_USI_SDA ); 356 | 357 | // set SCL high 358 | PORT_USI |= ( 1 << PORT_USI_SCL ); 359 | 360 | // set SDA high 361 | PORT_USI |= ( 1 << PORT_USI_SDA ); 362 | 363 | // Set SDA as input 364 | DDR_USI &= ~( 1 << PORT_USI_SDA ); 365 | 366 | USICR = 367 | // enable Start Condition Interrupt 368 | ( 1 << USISIE ) | 369 | // disable Overflow Interrupt 370 | ( 0 << USIOIE ) | 371 | // set USI in Two-wire mode, no USI Counter overflow hold 372 | ( 1 << USIWM1 ) | ( 0 << USIWM0 ) | 373 | // Shift Register Clock Source = external, positive edge 374 | // 4-Bit Counter Source = external, both edges 375 | ( 1 << USICS1 ) | ( 0 << USICS0 ) | ( 0 << USICLK ) | 376 | // no toggle clock-port pin 377 | ( 0 << USITC ); 378 | 379 | // clear all interrupt flags and reset overflow counter 380 | 381 | USISR = ( 1 << USI_START_COND_INT ) | ( 1 << USIOIF ) | ( 1 << USIPF ) | ( 1 << USIDC ); 382 | 383 | } // end usiTwiSlaveInit 384 | 385 | 386 | bool usiTwiDataInTransmitBuffer(void) 387 | { 388 | 389 | // return 0 (false) if the receive buffer is empty 390 | return txCount; 391 | 392 | } // end usiTwiDataInTransmitBuffer 393 | 394 | 395 | // put data in the transmission buffer, wait if buffer is full 396 | 397 | void 398 | usiTwiTransmitByte( 399 | uint8_t data 400 | ) 401 | { 402 | 403 | uint8_t tmphead; 404 | 405 | // wait for free space in buffer 406 | while ( txCount == TWI_TX_BUFFER_SIZE) ; 407 | 408 | // store data in buffer 409 | txBuf[ txHead ] = data; 410 | txHead = ( txHead + 1 ) & TWI_TX_BUFFER_MASK; 411 | txCount++; 412 | 413 | } // end usiTwiTransmitByte 414 | 415 | 416 | 417 | 418 | 419 | // return a byte from the receive buffer, wait if buffer is empty 420 | 421 | uint8_t 422 | usiTwiReceiveByte( 423 | void 424 | ) 425 | { 426 | uint8_t rtn_byte; 427 | 428 | // wait for Rx data 429 | while ( !rxCount ); 430 | 431 | rtn_byte = rxBuf [ rxTail ]; 432 | // calculate buffer index 433 | rxTail = ( rxTail + 1 ) & TWI_RX_BUFFER_MASK; 434 | rxCount--; 435 | 436 | // return data from the buffer. 437 | return rtn_byte; 438 | 439 | } // end usiTwiReceiveByte 440 | 441 | 442 | 443 | uint8_t usiTwiAmountDataInReceiveBuffer(void) 444 | { 445 | return rxCount; 446 | } 447 | 448 | 449 | 450 | 451 | /******************************************************************************** 452 | 453 | USI Start Condition ISR 454 | 455 | ********************************************************************************/ 456 | 457 | ISR( USI_START_VECTOR ) 458 | { 459 | 460 | /* 461 | // This triggers on second write, but claims to the callback there is only *one* byte in buffer 462 | ONSTOP_USI_RECEIVE_CALLBACK(); 463 | */ 464 | /* 465 | // This triggers on second write, but claims to the callback there is only *one* byte in buffer 466 | USI_RECEIVE_CALLBACK(); 467 | */ 468 | 469 | // set default starting conditions for new TWI package 470 | overflowState = USI_SLAVE_CHECK_ADDRESS; 471 | 472 | // set SDA as input 473 | DDR_USI &= ~( 1 << PORT_USI_SDA ); 474 | 475 | // wait for SCL to go low to ensure the Start Condition has completed (the 476 | // start detector will hold SCL low ) - if a Stop Condition arises then leave 477 | // the interrupt to prevent waiting forever - don't use USISR to test for Stop 478 | // Condition as in Application Note AVR312 because the Stop Condition Flag is 479 | // going to be set from the last TWI sequence 480 | while ( 481 | // SCL his high 482 | ( PIN_USI & ( 1 << PIN_USI_SCL ) ) && 483 | // and SDA is low 484 | !( ( PIN_USI & ( 1 << PIN_USI_SDA ) ) ) 485 | ); 486 | 487 | 488 | if ( !( PIN_USI & ( 1 << PIN_USI_SDA ) ) ) 489 | { 490 | 491 | // a Stop Condition did not occur 492 | 493 | USICR = 494 | // keep Start Condition Interrupt enabled to detect RESTART 495 | ( 1 << USISIE ) | 496 | // enable Overflow Interrupt 497 | ( 1 << USIOIE ) | 498 | // set USI in Two-wire mode, hold SCL low on USI Counter overflow 499 | ( 1 << USIWM1 ) | ( 1 << USIWM0 ) | 500 | // Shift Register Clock Source = External, positive edge 501 | // 4-Bit Counter Source = external, both edges 502 | ( 1 << USICS1 ) | ( 0 << USICS0 ) | ( 0 << USICLK ) | 503 | // no toggle clock-port pin 504 | ( 0 << USITC ); 505 | 506 | } 507 | else 508 | { 509 | // a Stop Condition did occur 510 | 511 | USICR = 512 | // enable Start Condition Interrupt 513 | ( 1 << USISIE ) | 514 | // disable Overflow Interrupt 515 | ( 0 << USIOIE ) | 516 | // set USI in Two-wire mode, no USI Counter overflow hold 517 | ( 1 << USIWM1 ) | ( 0 << USIWM0 ) | 518 | // Shift Register Clock Source = external, positive edge 519 | // 4-Bit Counter Source = external, both edges 520 | ( 1 << USICS1 ) | ( 0 << USICS0 ) | ( 0 << USICLK ) | 521 | // no toggle clock-port pin 522 | ( 0 << USITC ); 523 | 524 | } // end if 525 | 526 | USISR = 527 | // clear interrupt flags - resetting the Start Condition Flag will 528 | // release SCL 529 | ( 1 << USI_START_COND_INT ) | ( 1 << USIOIF ) | 530 | ( 1 << USIPF ) |( 1 << USIDC ) | 531 | // set USI to sample 8 bits (count 16 external SCL pin toggles) 532 | ( 0x0 << USICNT0); 533 | 534 | 535 | } // end ISR( USI_START_VECTOR ) 536 | 537 | 538 | 539 | /******************************************************************************** 540 | 541 | USI Overflow ISR 542 | 543 | Handles all the communication. 544 | 545 | Only disabled when waiting for a new Start Condition. 546 | 547 | ********************************************************************************/ 548 | 549 | ISR( USI_OVERFLOW_VECTOR ) 550 | { 551 | 552 | switch ( overflowState ) 553 | { 554 | 555 | // Address mode: check address and send ACK (and next USI_SLAVE_SEND_DATA) if OK, 556 | // else reset USI 557 | case USI_SLAVE_CHECK_ADDRESS: 558 | if ( ( USIDR == 0 ) || ( ( USIDR >> 1 ) == slaveAddress) ) 559 | { 560 | if ( USIDR & 0x01 ) 561 | { 562 | USI_REQUEST_CALLBACK(); 563 | overflowState = USI_SLAVE_SEND_DATA; 564 | } 565 | else 566 | { 567 | overflowState = USI_SLAVE_REQUEST_DATA; 568 | } // end if 569 | SET_USI_TO_SEND_ACK( ); 570 | } 571 | else 572 | { 573 | SET_USI_TO_TWI_START_CONDITION_MODE( ); 574 | } 575 | break; 576 | 577 | // Master write data mode: check reply and goto USI_SLAVE_SEND_DATA if OK, 578 | // else reset USI 579 | case USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA: 580 | if ( USIDR ) 581 | { 582 | // if NACK, the master does not want more data 583 | SET_USI_TO_TWI_START_CONDITION_MODE( ); 584 | return; 585 | } 586 | // from here we just drop straight into USI_SLAVE_SEND_DATA if the 587 | // master sent an ACK 588 | 589 | // copy data from buffer to USIDR and set USI to shift byte 590 | // next USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA 591 | case USI_SLAVE_SEND_DATA: 592 | // Get data from Buffer 593 | if ( txCount ) 594 | { 595 | USIDR = txBuf[ txTail ]; 596 | txTail = ( txTail + 1 ) & TWI_TX_BUFFER_MASK; 597 | txCount--; 598 | } 599 | else 600 | { 601 | // the buffer is empty 602 | SET_USI_TO_READ_ACK( ); // This might be neccessary sometimes see http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=805227#805227 603 | SET_USI_TO_TWI_START_CONDITION_MODE( ); 604 | return; 605 | } // end if 606 | overflowState = USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA; 607 | SET_USI_TO_SEND_DATA( ); 608 | break; 609 | 610 | // set USI to sample reply from master 611 | // next USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA 612 | case USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA: 613 | overflowState = USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA; 614 | SET_USI_TO_READ_ACK( ); 615 | break; 616 | 617 | // Master read data mode: set USI to sample data from master, next 618 | // USI_SLAVE_GET_DATA_AND_SEND_ACK 619 | case USI_SLAVE_REQUEST_DATA: 620 | overflowState = USI_SLAVE_GET_DATA_AND_SEND_ACK; 621 | SET_USI_TO_READ_DATA( ); 622 | break; 623 | 624 | // copy data from USIDR and send ACK 625 | // next USI_SLAVE_REQUEST_DATA 626 | case USI_SLAVE_GET_DATA_AND_SEND_ACK: 627 | // put data into buffer 628 | // check buffer size 629 | if ( rxCount < TWI_RX_BUFFER_SIZE ) 630 | { 631 | rxBuf[ rxHead ] = USIDR; 632 | rxHead = ( rxHead + 1 ) & TWI_RX_BUFFER_MASK; 633 | rxCount++; 634 | } else { 635 | // overrun 636 | // drop data 637 | } 638 | // next USI_SLAVE_REQUEST_DATA 639 | overflowState = USI_SLAVE_REQUEST_DATA; 640 | SET_USI_TO_SEND_ACK( ); 641 | break; 642 | 643 | } // end switch 644 | 645 | } // end ISR( USI_OVERFLOW_VECTOR ) 646 | --------------------------------------------------------------------------------