i2c.h
  1  // SPDX-FileCopyrightText: 2019 Anne Barela for Adafruit Industries
  2  //
  3  // SPDX-License-Identifier: MIT
  4  
  5  // This library provides the high-level functions needed to use the I2C
  6  // serial interface supported by the hardware of several AVR processors.
  7  #ifndef i2c_h
  8  #define i2c_h
  9  
 10  #include <avr/io.h>
 11  
 12  // TWSR values (status codes)
 13  // Master
 14  #define TW_START				0x08
 15  #define TW_REP_START				0x10
 16  // Master Transmitter
 17  #define TW_MT_SLA_ACK				0x18
 18  #define TW_MT_SLA_NACK				0x20
 19  #define TW_MT_DATA_ACK				0x28
 20  #define TW_MT_DATA_NACK				0x30
 21  #define TW_MT_ARB_LOST				0x38
 22  // Master Receiver
 23  #define TW_MR_ARB_LOST				0x38
 24  #define TW_MR_SLA_ACK				0x40
 25  #define TW_MR_SLA_NACK				0x48
 26  #define TW_MR_DATA_ACK				0x50
 27  #define TW_MR_DATA_NACK				0x58
 28  // Slave Transmitter
 29  #define TW_ST_SLA_ACK				0xA8
 30  #define TW_ST_ARB_LOST_SLA_ACK		        0xB0
 31  #define TW_ST_DATA_ACK				0xB8
 32  #define TW_ST_DATA_NACK				0xC0
 33  #define TW_ST_LAST_DATA				0xC8
 34  // Slave Receiver
 35  #define TW_SR_SLA_ACK				0x60
 36  #define TW_SR_ARB_LOST_SLA_ACK		        0x68
 37  #define TW_SR_GCALL_ACK				0x70
 38  #define TW_SR_ARB_LOST_GCALL_ACK	        0x78
 39  #define TW_SR_DATA_ACK				0x80
 40  #define TW_SR_DATA_NACK				0x88
 41  #define TW_SR_GCALL_DATA_ACK		        0x90
 42  #define TW_SR_GCALL_DATA_NACK		        0x98
 43  #define TW_SR_STOP			        0xA0
 44  // Misc
 45  #define TW_NO_INFO				0xF8
 46  #define TW_BUS_ERROR				0x00
 47  
 48  // defines and constants
 49  #define TWCR_CMD_MASK		0x0F
 50  #define TWSR_STATUS_MASK	0xF8
 51  
 52  // return values
 53  #define I2C_OK			0x00
 54  #define I2C_ERROR_NODEV		0x01
 55  
 56  //! Initialize I2C (TWI) interface
 57  void i2cInit(void);
 58  // Low-level I2C transaction commands 
 59  //! Send an I2C start condition in Master mode
 60  void i2cSendStart(void);
 61  //! Send an I2C stop condition in Master mode
 62  void i2cSendStop(void);
 63  //! Wait for current I2C operation to complete
 64  void i2cWaitForComplete(void);
 65  //! Send an (address|R/W) combination or a data byte over I2C
 66  void i2cSendByte(unsigned char data);
 67  //! Receive a data byte over I2C  
 68  // ackFlag = -1 if recevied data should be ACK'ed
 69  // ackFlag = 0 if recevied data should be NACK'ed
 70  void i2cReceiveByte(unsigned char ackFlag);
 71  //! Pick up the data that was received with i2cReceiveByte()
 72  unsigned char i2cGetReceivedByte(void);
 73  //! Get current I2c bus status from TWSR
 74  unsigned char i2cGetStatus(void);
 75  void delay_10us(uint16_t x);
 76  
 77  /*********************
 78   ****I2C Functions****
 79   *********************/
 80  
 81  void i2cInit(void){
 82    // set SCL freq = F_CPU/(16+2*TWBR*4^TWPS))=16*10^6/(16+2*12)=400kHz
 83    TWSR &= ~(_BV(TWPS0)|_BV(TWPS1));  // clear TWPS in TWSR register, setting prescaler(TWPS) = 0
 84    TWBR = 12;  // set bit rate register (12 -> 400kHz; 32 -> 200kHz)
 85    TWCR |= _BV(TWEN);  // Enable TWI	
 86  }
 87  
 88  void i2cSendStart(void){
 89    // send start condition
 90    TWCR = _BV(TWINT)|_BV(TWSTA)|_BV(TWEN);
 91  }
 92  
 93  void i2cSendStop(void){
 94    // transmit stop condition
 95    TWCR = _BV(TWINT)|_BV(TWEN)|_BV(TWSTO);
 96  }
 97  
 98  void i2cWaitForComplete(void){
 99    // wait for i2c interface to complete operation, use i for timeout
100    uint8_t i = 0;
101    while ((!(TWCR & (1<<TWINT))) && (i < 90))
102      i++;
103  }
104  
105  void i2cSendByte(uint8_t data){
106    delay_10us(1);
107    TWDR = data;  // save data to the TWDR
108    TWCR = (1<<TWINT) | (1<<TWEN);  // begin send
109  }
110  
111  void i2cReceiveByte(uint8_t ackFlag){
112    if( ackFlag ){
113      // ackFlag = 1: ACK the recevied data (would like to receive more data)
114      TWCR = (TWCR&TWCR_CMD_MASK)|_BV(TWINT)|_BV(TWEA);
115    }
116    else{
117      // ackFlag = 0: NACK the recevied data (want to stop receiving data)
118      TWCR = (TWCR&TWCR_CMD_MASK)|_BV(TWINT);
119    }
120  }
121  
122  unsigned char i2cGetReceivedByte(void) {
123    // retieve received data byte from i2c TWDR
124    return(TWDR);
125  }
126  
127  unsigned char i2cGetStatus(void){
128    // retieve current i2c status from i2c TWSR
129    return(TWSR);
130  }
131  
132  void delay_10us(uint16_t x){
133    for (; x > 0 ; x--){
134      for (uint8_t y = 0 ; y < 25; y++){
135          asm volatile ("nop");
136      }
137    }
138  }
139  
140  /*********************
141   ****I2C High Level Functions****
142   *********************/
143   
144  void writeRegister(uint8_t address, uint8_t data){
145    i2cSendStart();
146    i2cWaitForComplete();
147    i2cSendByte((address<<1));
148    i2cWaitForComplete();
149    i2cSendByte(data);
150    i2cWaitForComplete();
151    i2cSendStop();
152  }
153  
154  void writeRegisters(uint8_t address, uint8_t regsiter, uint8_t i, uint16_t *data){
155    i2cSendStart();
156    i2cWaitForComplete();
157    i2cSendByte((address<<1));
158    i2cWaitForComplete();
159    i2cSendByte(regsiter);
160    i2cWaitForComplete();
161    
162    for (uint8_t j=0;j<i;j++) {
163      i2cSendByte(data[j]&255);
164      i2cWaitForComplete();
165      i2cSendByte((data[j]>>8)&255);
166      i2cWaitForComplete();
167    }  
168    i2cSendStop();
169  }
170  
171  uint8_t readRegister(uint8_t address, uint8_t regsiter){
172    i2cSendStart();
173    i2cWaitForComplete();
174    i2cSendByte((address<<1));
175    i2cWaitForComplete();
176    i2cSendByte(regsiter);
177    i2cWaitForComplete();
178  
179    i2cSendStart();
180    i2cWaitForComplete();
181    i2cSendByte((address<<1)|0x01);
182    i2cWaitForComplete();
183    i2cReceiveByte(0);
184    i2cWaitForComplete();
185    uint8_t data = i2cGetReceivedByte();
186    i2cSendStop();
187  
188    return data;
189  }
190  
191  #endif