aboutsummaryrefslogtreecommitdiff
path: root/drivers/avr/i2c_master.c
diff options
context:
space:
mode:
authorJoel Challis <git@zvecr.com>2021-08-17 23:43:09 +0100
committerGitHub <noreply@github.com>2021-08-17 23:43:09 +0100
commit1bb7af4d446174b7181c9bb22dbd14c93642ea10 (patch)
tree894eceeb29cc2c00f6b0f08a4ca177da7f172424 /drivers/avr/i2c_master.c
parent483691dd73e5260fac958c524e0a12e705db43f6 (diff)
downloadqmk_firmware-1bb7af4d446174b7181c9bb22dbd14c93642ea10.tar.gz
qmk_firmware-1bb7af4d446174b7181c9bb22dbd14c93642ea10.zip
Relocate platform specific drivers (#13894)
* Relocate platform specific drivers * Move stm eeprom * Tidy up slightly
Diffstat (limited to 'drivers/avr/i2c_master.c')
-rw-r--r--drivers/avr/i2c_master.c241
1 files changed, 0 insertions, 241 deletions
diff --git a/drivers/avr/i2c_master.c b/drivers/avr/i2c_master.c
deleted file mode 100644
index 2773e0077..000000000
--- a/drivers/avr/i2c_master.c
+++ /dev/null
@@ -1,241 +0,0 @@
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
27#ifndef F_SCL
28# define F_SCL 400000UL // SCL frequency
29#endif
30
31#ifndef I2C_START_RETRY_COUNT
32# define I2C_START_RETRY_COUNT 20
33#endif // I2C_START_RETRY_COUNT
34
35#define TWBR_val (((F_CPU / F_SCL) - 16) / 2)
36
37#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
38
39void i2c_init(void) {
40 TWSR = 0; /* no prescaler */
41 TWBR = (uint8_t)TWBR_val;
42
43#ifdef __AVR_ATmega32A__
44 // set pull-up resistors on I2C bus pins
45 PORTC |= 0b11;
46
47 // enable TWI (two-wire interface)
48 TWCR |= (1 << TWEN);
49
50 // enable TWI interrupt and slave address ACK
51 TWCR |= (1 << TWIE);
52 TWCR |= (1 << TWEA);
53#endif
54}
55
56static i2c_status_t i2c_start_impl(uint8_t address, uint16_t timeout) {
57 // reset TWI control register
58 TWCR = 0;
59 // transmit START condition
60 TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
61
62 uint16_t timeout_timer = timer_read();
63 while (!(TWCR & (1 << TWINT))) {
64 if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
65 return I2C_STATUS_TIMEOUT;
66 }
67 }
68
69 // check if the start condition was successfully transmitted
70 if (((TW_STATUS & 0xF8) != TW_START) && ((TW_STATUS & 0xF8) != TW_REP_START)) {
71 return I2C_STATUS_ERROR;
72 }
73
74 // load slave address into data register
75 TWDR = address;
76 // start transmission of address
77 TWCR = (1 << TWINT) | (1 << TWEN);
78
79 timeout_timer = timer_read();
80 while (!(TWCR & (1 << TWINT))) {
81 if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
82 return I2C_STATUS_TIMEOUT;
83 }
84 }
85
86 // check if the device has acknowledged the READ / WRITE mode
87 uint8_t twst = TW_STATUS & 0xF8;
88 if ((twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK)) {
89 return I2C_STATUS_ERROR;
90 }
91
92 return I2C_STATUS_SUCCESS;
93}
94
95i2c_status_t i2c_start(uint8_t address, uint16_t timeout) {
96 // Retry i2c_start_impl a bunch times in case the remote side has interrupts disabled.
97 uint16_t timeout_timer = timer_read();
98 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
99 i2c_status_t status;
100 do {
101 status = i2c_start_impl(address, time_slice);
102 } while ((status < 0) && ((timeout == I2C_TIMEOUT_INFINITE) || (timer_elapsed(timeout_timer) < timeout)));
103 return status;
104}
105
106i2c_status_t i2c_write(uint8_t data, uint16_t timeout) {
107 // load data into data register
108 TWDR = data;
109 // start transmission of data
110 TWCR = (1 << TWINT) | (1 << TWEN);
111
112 uint16_t timeout_timer = timer_read();
113 while (!(TWCR & (1 << TWINT))) {
114 if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
115 return I2C_STATUS_TIMEOUT;
116 }
117 }
118
119 if ((TW_STATUS & 0xF8) != TW_MT_DATA_ACK) {
120 return I2C_STATUS_ERROR;
121 }
122
123 return I2C_STATUS_SUCCESS;
124}
125
126int16_t i2c_read_ack(uint16_t timeout) {
127 // start TWI module and acknowledge data after reception
128 TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA);
129
130 uint16_t timeout_timer = timer_read();
131 while (!(TWCR & (1 << TWINT))) {
132 if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
133 return I2C_STATUS_TIMEOUT;
134 }
135 }
136
137 // return received data from TWDR
138 return TWDR;
139}
140
141int16_t i2c_read_nack(uint16_t timeout) {
142 // start receiving without acknowledging reception
143 TWCR = (1 << TWINT) | (1 << TWEN);
144
145 uint16_t timeout_timer = timer_read();
146 while (!(TWCR & (1 << TWINT))) {
147 if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
148 return I2C_STATUS_TIMEOUT;
149 }
150 }
151
152 // return received data from TWDR
153 return TWDR;
154}
155
156i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout) {
157 i2c_status_t status = i2c_start(address | I2C_WRITE, timeout);
158
159 for (uint16_t i = 0; i < length && status >= 0; i++) {
160 status = i2c_write(data[i], timeout);
161 }
162
163 i2c_stop();
164
165 return status;
166}
167
168i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout) {
169 i2c_status_t status = i2c_start(address | I2C_READ, timeout);
170
171 for (uint16_t i = 0; i < (length - 1) && status >= 0; i++) {
172 status = i2c_read_ack(timeout);
173 if (status >= 0) {
174 data[i] = status;
175 }
176 }
177
178 if (status >= 0) {
179 status = i2c_read_nack(timeout);
180 if (status >= 0) {
181 data[(length - 1)] = status;
182 }
183 }
184
185 i2c_stop();
186
187 return (status < 0) ? status : I2C_STATUS_SUCCESS;
188}
189
190i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) {
191 i2c_status_t status = i2c_start(devaddr | 0x00, timeout);
192 if (status >= 0) {
193 status = i2c_write(regaddr, timeout);
194
195 for (uint16_t i = 0; i < length && status >= 0; i++) {
196 status = i2c_write(data[i], timeout);
197 }
198 }
199
200 i2c_stop();
201
202 return status;
203}
204
205i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) {
206 i2c_status_t status = i2c_start(devaddr, timeout);
207 if (status < 0) {
208 goto error;
209 }
210
211 status = i2c_write(regaddr, timeout);
212 if (status < 0) {
213 goto error;
214 }
215
216 status = i2c_start(devaddr | 0x01, timeout);
217
218 for (uint16_t i = 0; i < (length - 1) && status >= 0; i++) {
219 status = i2c_read_ack(timeout);
220 if (status >= 0) {
221 data[i] = status;
222 }
223 }
224
225 if (status >= 0) {
226 status = i2c_read_nack(timeout);
227 if (status >= 0) {
228 data[(length - 1)] = status;
229 }
230 }
231
232error:
233 i2c_stop();
234
235 return (status < 0) ? status : I2C_STATUS_SUCCESS;
236}
237
238void i2c_stop(void) {
239 // transmit STOP condition
240 TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
241}