i2c_master.c (9852B)
1 /* Copyright (C) 2019 Elia Ritterbusch 2 + 3 * This program is free software: you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published by 5 * the Free Software Foundation, either version 3 of the License, or 6 * (at your option) any later version. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <https://www.gnu.org/licenses/>. 15 */ 16 /* Library made by: g4lvanix 17 * GitHub repository: https://github.com/g4lvanix/I2C-master-lib 18 */ 19 20 #include <avr/io.h> 21 #include <util/twi.h> 22 23 #include "i2c_master.h" 24 #include "timer.h" 25 #include "wait.h" 26 #include "util.h" 27 #include "progmem.h" 28 29 #ifndef F_SCL 30 # define F_SCL 400000UL // SCL frequency 31 #endif 32 33 #ifndef I2C_START_RETRY_COUNT 34 # define I2C_START_RETRY_COUNT 20 35 #endif // I2C_START_RETRY_COUNT 36 37 #define I2C_ACTION_READ 0x01 38 #define I2C_ACTION_WRITE 0x00 39 40 #define TWBR_val (((F_CPU / F_SCL) - 16) / 2) 41 42 __attribute__((weak)) void i2c_init(void) { 43 TWSR = 0; /* no prescaler */ 44 TWBR = (uint8_t)TWBR_val; 45 46 #ifdef __AVR_ATmega32A__ 47 // set pull-up resistors on I2C bus pins 48 PORTC |= 0b11; 49 50 // enable TWI (two-wire interface) 51 TWCR |= (1 << TWEN); 52 53 // enable TWI interrupt and slave address ACK 54 TWCR |= (1 << TWIE); 55 TWCR |= (1 << TWEA); 56 #endif 57 } 58 59 static i2c_status_t i2c_start_impl(uint8_t address, uint16_t timeout) { 60 // reset TWI control register 61 TWCR = 0; 62 // transmit START condition 63 TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); 64 65 uint16_t timeout_timer = timer_read(); 66 while (!(TWCR & (1 << TWINT))) { 67 if ((timeout != I2C_TIMEOUT_INFINITE) && (timer_elapsed(timeout_timer) > timeout)) { 68 return I2C_STATUS_TIMEOUT; 69 } 70 } 71 72 // check if the start condition was successfully transmitted 73 if (((TW_STATUS & 0xF8) != TW_START) && ((TW_STATUS & 0xF8) != TW_REP_START)) { 74 return I2C_STATUS_ERROR; 75 } 76 77 // load slave address into data register 78 TWDR = address; 79 // start transmission of address 80 TWCR = (1 << TWINT) | (1 << TWEN); 81 82 timeout_timer = timer_read(); 83 while (!(TWCR & (1 << TWINT))) { 84 if ((timeout != I2C_TIMEOUT_INFINITE) && (timer_elapsed(timeout_timer) > timeout)) { 85 return I2C_STATUS_TIMEOUT; 86 } 87 } 88 89 // check if the device has acknowledged the READ / WRITE mode 90 uint8_t twst = TW_STATUS & 0xF8; 91 if ((twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK)) { 92 return I2C_STATUS_ERROR; 93 } 94 95 return I2C_STATUS_SUCCESS; 96 } 97 98 __attribute__((always_inline)) static inline i2c_status_t i2c_start(uint8_t address, uint16_t timeout) { 99 // Retry i2c_start_impl a bunch times in case the remote side has interrupts disabled. 100 uint16_t timeout_timer = timer_read(); 101 uint16_t time_slice = MAX(1, (timeout == (I2C_TIMEOUT_INFINITE)) ? 5 : (timeout / (I2C_START_RETRY_COUNT))); // if it's infinite, wait 1ms between attempts, otherwise split up the entire timeout into the number of retries 102 i2c_status_t status; 103 do { 104 status = i2c_start_impl(address, time_slice); 105 } while ((status < 0) && ((timeout == I2C_TIMEOUT_INFINITE) || (timer_elapsed(timeout_timer) <= timeout))); 106 return status; 107 } 108 109 __attribute__((always_inline)) static inline void i2c_stop(void) { 110 // transmit STOP condition 111 TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); 112 } 113 114 i2c_status_t i2c_write(uint8_t data, uint16_t timeout) { 115 // load data into data register 116 TWDR = data; 117 // start transmission of data 118 TWCR = (1 << TWINT) | (1 << TWEN); 119 120 uint16_t timeout_timer = timer_read(); 121 while (!(TWCR & (1 << TWINT))) { 122 if ((timeout != I2C_TIMEOUT_INFINITE) && (timer_elapsed(timeout_timer) > timeout)) { 123 return I2C_STATUS_TIMEOUT; 124 } 125 } 126 127 if ((TW_STATUS & 0xF8) != TW_MT_DATA_ACK) { 128 return I2C_STATUS_ERROR; 129 } 130 131 return I2C_STATUS_SUCCESS; 132 } 133 134 int16_t i2c_read_ack(uint16_t timeout) { 135 // start TWI module and acknowledge data after reception 136 TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA); 137 138 uint16_t timeout_timer = timer_read(); 139 while (!(TWCR & (1 << TWINT))) { 140 if ((timeout != I2C_TIMEOUT_INFINITE) && (timer_elapsed(timeout_timer) > timeout)) { 141 return I2C_STATUS_TIMEOUT; 142 } 143 } 144 145 // return received data from TWDR 146 return TWDR; 147 } 148 149 int16_t i2c_read_nack(uint16_t timeout) { 150 // start receiving without acknowledging reception 151 TWCR = (1 << TWINT) | (1 << TWEN); 152 153 uint16_t timeout_timer = timer_read(); 154 while (!(TWCR & (1 << TWINT))) { 155 if ((timeout != I2C_TIMEOUT_INFINITE) && (timer_elapsed(timeout_timer) > timeout)) { 156 return I2C_STATUS_TIMEOUT; 157 } 158 } 159 160 // return received data from TWDR 161 return TWDR; 162 } 163 164 i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout) { 165 i2c_status_t status = i2c_start(address | I2C_ACTION_WRITE, timeout); 166 167 for (uint16_t i = 0; i < length && status >= 0; i++) { 168 status = i2c_write(data[i], timeout); 169 } 170 171 i2c_stop(); 172 173 return status; 174 } 175 176 i2c_status_t i2c_transmit_P(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout) { 177 i2c_status_t status = i2c_start(address | I2C_ACTION_WRITE, timeout); 178 179 for (uint16_t i = 0; i < length && status >= 0; i++) { 180 status = i2c_write(pgm_read_byte((const char*)data++), timeout); 181 } 182 183 i2c_stop(); 184 185 return status; 186 } 187 188 i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout) { 189 i2c_status_t status = i2c_start(address | I2C_ACTION_READ, timeout); 190 191 for (uint16_t i = 0; i < (length - 1) && status >= 0; i++) { 192 status = i2c_read_ack(timeout); 193 if (status >= 0) { 194 data[i] = status; 195 } 196 } 197 198 if (status >= 0) { 199 status = i2c_read_nack(timeout); 200 if (status >= 0) { 201 data[(length - 1)] = status; 202 } 203 } 204 205 i2c_stop(); 206 207 return (status < 0) ? status : I2C_STATUS_SUCCESS; 208 } 209 210 i2c_status_t i2c_transmit_and_receive(uint8_t address, const uint8_t* tx_data, uint16_t tx_length, uint8_t* rx_data, uint16_t rx_length, uint16_t timeout) { 211 i2c_status_t status = i2c_start(address | I2C_ACTION_WRITE, timeout); 212 213 for (uint16_t i = 0; i < tx_length && status >= 0; i++) { 214 status = i2c_write(tx_data[i], timeout); 215 } 216 217 for (uint16_t i = 0; i < (rx_length - 1) && status >= 0; i++) { 218 status = i2c_read_ack(timeout); 219 if (status >= 0) { 220 rx_data[i] = status; 221 } 222 } 223 224 if (status >= 0) { 225 status = i2c_read_nack(timeout); 226 if (status >= 0) { 227 rx_data[(rx_length - 1)] = status; 228 } 229 } 230 231 i2c_stop(); 232 233 return status; 234 } 235 236 i2c_status_t i2c_write_register(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) { 237 i2c_status_t status = i2c_start(devaddr | 0x00, timeout); 238 if (status >= 0) { 239 status = i2c_write(regaddr, timeout); 240 241 for (uint16_t i = 0; i < length && status >= 0; i++) { 242 status = i2c_write(data[i], timeout); 243 } 244 } 245 246 i2c_stop(); 247 248 return status; 249 } 250 251 i2c_status_t i2c_write_register16(uint8_t devaddr, uint16_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) { 252 i2c_status_t status = i2c_start(devaddr | 0x00, timeout); 253 if (status >= 0) { 254 status = i2c_write(regaddr >> 8, timeout); 255 256 if (status >= 0) { 257 status = i2c_write(regaddr & 0xFF, timeout); 258 259 for (uint16_t i = 0; i < length && status >= 0; i++) { 260 status = i2c_write(data[i], timeout); 261 } 262 } 263 } 264 265 i2c_stop(); 266 267 return status; 268 } 269 270 i2c_status_t i2c_read_register(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) { 271 i2c_status_t status = i2c_start(devaddr, timeout); 272 if (status < 0) { 273 goto error; 274 } 275 276 status = i2c_write(regaddr, timeout); 277 if (status < 0) { 278 goto error; 279 } 280 281 status = i2c_start(devaddr | 0x01, timeout); 282 283 for (uint16_t i = 0; i < (length - 1) && status >= 0; i++) { 284 status = i2c_read_ack(timeout); 285 if (status >= 0) { 286 data[i] = status; 287 } 288 } 289 290 if (status >= 0) { 291 status = i2c_read_nack(timeout); 292 if (status >= 0) { 293 data[(length - 1)] = status; 294 } 295 } 296 297 error: 298 i2c_stop(); 299 300 return (status < 0) ? status : I2C_STATUS_SUCCESS; 301 } 302 303 i2c_status_t i2c_read_register16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) { 304 i2c_status_t status = i2c_start(devaddr, timeout); 305 if (status < 0) { 306 goto error; 307 } 308 309 status = i2c_write(regaddr >> 8, timeout); 310 if (status < 0) { 311 goto error; 312 } 313 status = i2c_write(regaddr & 0xFF, timeout); 314 if (status < 0) { 315 goto error; 316 } 317 318 status = i2c_start(devaddr | 0x01, timeout); 319 320 for (uint16_t i = 0; i < (length - 1) && status >= 0; i++) { 321 status = i2c_read_ack(timeout); 322 if (status >= 0) { 323 data[i] = status; 324 } 325 } 326 327 if (status >= 0) { 328 status = i2c_read_nack(timeout); 329 if (status >= 0) { 330 data[(length - 1)] = status; 331 } 332 } 333 334 error: 335 i2c_stop(); 336 337 return (status < 0) ? status : I2C_STATUS_SUCCESS; 338 } 339 340 __attribute__((weak)) i2c_status_t i2c_ping_address(uint8_t address, uint16_t timeout) { 341 i2c_status_t status = i2c_start(address, timeout); 342 i2c_stop(); 343 return status; 344 }