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;
22 #ifdef __AVR_ATmega32A__
23 // set pull-up resistors on I2C bus pins
26 // enable TWI (two-wire interface)
29 // enable TWI interrupt and slave address ACK
35 i2c_status_t i2c_start(uint8_t address, uint16_t timeout) {
36 // reset TWI control register
38 // transmit START condition
39 TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
41 uint16_t timeout_timer = timer_read();
42 while (!(TWCR & (1 << TWINT))) {
43 if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
44 return I2C_STATUS_TIMEOUT;
48 // check if the start condition was successfully transmitted
49 if (((TW_STATUS & 0xF8) != TW_START) && ((TW_STATUS & 0xF8) != TW_REP_START)) {
50 return I2C_STATUS_ERROR;
53 // load slave address into data register
55 // start transmission of address
56 TWCR = (1 << TWINT) | (1 << TWEN);
58 timeout_timer = timer_read();
59 while (!(TWCR & (1 << TWINT))) {
60 if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
61 return I2C_STATUS_TIMEOUT;
65 // check if the device has acknowledged the READ / WRITE mode
66 uint8_t twst = TW_STATUS & 0xF8;
67 if ((twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK)) {
68 return I2C_STATUS_ERROR;
71 return I2C_STATUS_SUCCESS;
74 i2c_status_t i2c_write(uint8_t data, uint16_t timeout) {
75 // load data into data register
77 // start transmission of data
78 TWCR = (1 << TWINT) | (1 << TWEN);
80 uint16_t timeout_timer = timer_read();
81 while (!(TWCR & (1 << TWINT))) {
82 if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
83 return I2C_STATUS_TIMEOUT;
87 if ((TW_STATUS & 0xF8) != TW_MT_DATA_ACK) {
88 return I2C_STATUS_ERROR;
91 return I2C_STATUS_SUCCESS;
94 int16_t i2c_read_ack(uint16_t timeout) {
95 // start TWI module and acknowledge data after reception
96 TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA);
98 uint16_t timeout_timer = timer_read();
99 while (!(TWCR & (1 << TWINT))) {
100 if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
101 return I2C_STATUS_TIMEOUT;
105 // return received data from TWDR
109 int16_t i2c_read_nack(uint16_t timeout) {
110 // start receiving without acknowledging reception
111 TWCR = (1 << TWINT) | (1 << TWEN);
113 uint16_t timeout_timer = timer_read();
114 while (!(TWCR & (1 << TWINT))) {
115 if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
116 return I2C_STATUS_TIMEOUT;
120 // return received data from TWDR
124 i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout) {
125 i2c_status_t status = i2c_start(address | I2C_WRITE, timeout);
127 for (uint16_t i = 0; i < length && status >= 0; i++) {
128 status = i2c_write(data[i], timeout);
136 i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout) {
137 i2c_status_t status = i2c_start(address | I2C_READ, timeout);
139 for (uint16_t i = 0; i < (length - 1) && status >= 0; i++) {
140 status = i2c_read_ack(timeout);
147 status = i2c_read_nack(timeout);
149 data[(length - 1)] = status;
155 return (status < 0) ? status : I2C_STATUS_SUCCESS;
158 i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) {
159 i2c_status_t status = i2c_start(devaddr | 0x00, timeout);
161 status = i2c_write(regaddr, timeout);
163 for (uint16_t i = 0; i < length && status >= 0; i++) {
164 status = i2c_write(data[i], timeout);
173 i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) {
174 i2c_status_t status = i2c_start(devaddr, timeout);
179 status = i2c_write(regaddr, timeout);
184 status = i2c_start(devaddr | 0x01, timeout);
186 for (uint16_t i = 0; i < (length - 1) && status >= 0; i++) {
187 status = i2c_read_ack(timeout);
194 status = i2c_read_nack(timeout);
196 data[(length - 1)] = status;
203 return (status < 0) ? status : I2C_STATUS_SUCCESS;
206 void i2c_stop(void) {
207 // transmit STOP condition
208 TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);