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