1 /* Library made by: g4lvanix
2 * Github repository: https://github.com/g4lvanix/I2C-master-lib
8 #include "i2c_master.h"
13 # define F_SCL 400000UL // SCL frequency
16 #define TWBR_val ((((F_CPU / F_SCL) / Prescaler) - 16) / 2)
19 TWSR = 0; /* no prescaler */
20 TWBR = (uint8_t)TWBR_val;
23 i2c_status_t i2c_start(uint8_t address, uint16_t timeout) {
24 // reset TWI control register
26 // transmit START condition
27 TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
29 uint16_t timeout_timer = timer_read();
30 while (!(TWCR & (1 << TWINT))) {
31 if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
32 return I2C_STATUS_TIMEOUT;
36 // check if the start condition was successfully transmitted
37 if (((TW_STATUS & 0xF8) != TW_START) && ((TW_STATUS & 0xF8) != TW_REP_START)) {
38 return I2C_STATUS_ERROR;
41 // load slave address into data register
43 // start transmission of address
44 TWCR = (1 << TWINT) | (1 << TWEN);
46 timeout_timer = timer_read();
47 while (!(TWCR & (1 << TWINT))) {
48 if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
49 return I2C_STATUS_TIMEOUT;
53 // check if the device has acknowledged the READ / WRITE mode
54 uint8_t twst = TW_STATUS & 0xF8;
55 if ((twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK)) {
56 return I2C_STATUS_ERROR;
59 return I2C_STATUS_SUCCESS;
62 i2c_status_t i2c_write(uint8_t data, uint16_t timeout) {
63 // load data into data register
65 // start transmission of data
66 TWCR = (1 << TWINT) | (1 << TWEN);
68 uint16_t timeout_timer = timer_read();
69 while (!(TWCR & (1 << TWINT))) {
70 if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
71 return I2C_STATUS_TIMEOUT;
75 if ((TW_STATUS & 0xF8) != TW_MT_DATA_ACK) {
76 return I2C_STATUS_ERROR;
79 return I2C_STATUS_SUCCESS;
82 int16_t i2c_read_ack(uint16_t timeout) {
83 // start TWI module and acknowledge data after reception
84 TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA);
86 uint16_t timeout_timer = timer_read();
87 while (!(TWCR & (1 << TWINT))) {
88 if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
89 return I2C_STATUS_TIMEOUT;
93 // return received data from TWDR
97 int16_t i2c_read_nack(uint16_t timeout) {
98 // start receiving without acknowledging reception
99 TWCR = (1 << TWINT) | (1 << TWEN);
101 uint16_t timeout_timer = timer_read();
102 while (!(TWCR & (1 << TWINT))) {
103 if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
104 return I2C_STATUS_TIMEOUT;
108 // return received data from TWDR
112 i2c_status_t i2c_transmit(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout) {
113 i2c_status_t status = i2c_start(address | I2C_WRITE, timeout);
115 for (uint16_t i = 0; i < length && status >= 0; i++) {
116 status = i2c_write(data[i], timeout);
124 i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout) {
125 i2c_status_t status = i2c_start(address | I2C_READ, timeout);
127 for (uint16_t i = 0; i < (length - 1) && status >= 0; i++) {
128 status = i2c_read_ack(timeout);
135 status = i2c_read_nack(timeout);
137 data[(length - 1)] = status;
143 return (status < 0) ? status : I2C_STATUS_SUCCESS;
146 i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) {
147 i2c_status_t status = i2c_start(devaddr | 0x00, timeout);
149 status = i2c_write(regaddr, timeout);
151 for (uint16_t i = 0; i < length && status >= 0; i++) {
152 status = i2c_write(data[i], timeout);
161 i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) {
162 i2c_status_t status = i2c_start(devaddr, timeout);
167 status = i2c_write(regaddr, timeout);
172 status = i2c_start(devaddr | 0x01, timeout);
174 for (uint16_t i = 0; i < (length - 1) && status >= 0; i++) {
175 status = i2c_read_ack(timeout);
182 status = i2c_read_nack(timeout);
184 data[(length - 1)] = status;
191 return (status < 0) ? status : I2C_STATUS_SUCCESS;
194 void i2c_stop(void) {
195 // transmit STOP condition
196 TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);