Merge pull request #11198 from SteveCEvans/sce_rc2
[betaflight.git] / src / main / drivers / bus_i2c_soft.c
blob95b4bbef3d6817ef7cd1a3344c2e66100a633ec9
1 /*
2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
8 * any later version.
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
21 #include <stdbool.h>
22 #include <stdint.h>
24 #include "platform.h"
26 #ifdef SOFT_I2C
28 #include "build/build_config.h"
30 #include "drivers/bus_i2c.h"
31 #include "drivers/io.h"
33 // Software I2C driver, using same pins as hardware I2C, with hw i2c module disabled.
34 // Can be configured for I2C2 pinout (SCL: PB10, SDA: PB11) or I2C1 pinout (SCL: PB6, SDA: PB7)
36 static IO_t scl;
37 static IO_t sda;
38 static volatile uint16_t i2cErrorCount = 0;
40 #define SCL_H IOHi(scl)
41 #define SCL_L IOLo(scl)
43 #define SDA_H IOHi(sda)
44 #define SDA_L IOLo(sda)
46 #define SCL_read IORead(scl)
47 #define SDA_read IORead(sda)
49 #if !defined(SOFT_I2C_SCL) || !defined(SOFT_I2C_SDA)
50 #error "Must define the software i2c pins (SOFT_I2C_SCL and SOFT_I2C_SDA) in target.h"
51 #endif
53 static void I2C_delay(void)
55 volatile int i = 7;
56 while (i) {
57 i--;
61 static bool I2C_Start(void)
63 SDA_H;
64 SCL_H;
65 I2C_delay();
66 if (!SDA_read) {
67 return false;
69 SDA_L;
70 I2C_delay();
71 if (SDA_read) {
72 return false;
74 SDA_L;
75 I2C_delay();
76 return true;
79 static void I2C_Stop(void)
81 SCL_L;
82 I2C_delay();
83 SDA_L;
84 I2C_delay();
85 SCL_H;
86 I2C_delay();
87 SDA_H;
88 I2C_delay();
91 static void I2C_Ack(void)
93 SCL_L;
94 I2C_delay();
95 SDA_L;
96 I2C_delay();
97 SCL_H;
98 I2C_delay();
99 SCL_L;
100 I2C_delay();
103 static void I2C_NoAck(void)
105 SCL_L;
106 I2C_delay();
107 SDA_H;
108 I2C_delay();
109 SCL_H;
110 I2C_delay();
111 SCL_L;
112 I2C_delay();
115 static bool I2C_WaitAck(void)
117 SCL_L;
118 I2C_delay();
119 SDA_H;
120 I2C_delay();
121 SCL_H;
122 I2C_delay();
123 if (SDA_read) {
124 SCL_L;
125 return false;
127 SCL_L;
128 return true;
131 static void I2C_SendByte(uint8_t byte)
133 uint8_t i = 8;
134 while (i--) {
135 SCL_L;
136 I2C_delay();
137 if (byte & 0x80) {
138 SDA_H;
140 else {
141 SDA_L;
143 byte <<= 1;
144 I2C_delay();
145 SCL_H;
146 I2C_delay();
148 SCL_L;
151 static uint8_t I2C_ReceiveByte(void)
153 uint8_t i = 8;
154 uint8_t byte = 0;
156 SDA_H;
157 while (i--) {
158 byte <<= 1;
159 SCL_L;
160 I2C_delay();
161 SCL_H;
162 I2C_delay();
163 if (SDA_read) {
164 byte |= 0x01;
167 SCL_L;
168 return byte;
171 void i2cInit(I2CDevice device)
173 UNUSED(device);
175 scl = IOGetByTag(IO_TAG(SOFT_I2C_SCL));
176 sda = IOGetByTag(IO_TAG(SOFT_I2C_SDA));
178 IOConfigGPIO(scl, IOCFG_OUT_OD);
179 IOConfigGPIO(sda, IOCFG_OUT_OD);
182 bool i2cWriteBuffer(I2CDevice device, uint8_t addr, uint8_t reg, uint8_t len, uint8_t * data)
184 UNUSED(device);
186 int i;
187 if (!I2C_Start()) {
188 i2cErrorCount++;
189 return false;
191 I2C_SendByte(addr << 1 | I2C_Direction_Transmitter);
192 if (!I2C_WaitAck()) {
193 I2C_Stop();
194 return false;
196 I2C_SendByte(reg);
197 I2C_WaitAck();
198 for (i = 0; i < len; i++) {
199 I2C_SendByte(data[i]);
200 if (!I2C_WaitAck()) {
201 I2C_Stop();
202 i2cErrorCount++;
203 return false;
206 I2C_Stop();
207 return true;
210 bool i2cWrite(I2CDevice device, uint8_t addr, uint8_t reg, uint8_t data)
212 UNUSED(device);
214 if (!I2C_Start()) {
215 return false;
217 I2C_SendByte(addr << 1 | I2C_Direction_Transmitter);
218 if (!I2C_WaitAck()) {
219 I2C_Stop();
220 i2cErrorCount++;
221 return false;
223 I2C_SendByte(reg);
224 I2C_WaitAck();
225 I2C_SendByte(data);
226 I2C_WaitAck();
227 I2C_Stop();
228 return true;
231 bool i2cRead(I2CDevice device, uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf)
233 UNUSED(device);
235 if (!I2C_Start()) {
236 return false;
238 I2C_SendByte(addr << 1 | I2C_Direction_Transmitter);
239 if (!I2C_WaitAck()) {
240 I2C_Stop();
241 i2cErrorCount++;
242 return false;
244 I2C_SendByte(reg);
245 I2C_WaitAck();
246 I2C_Start();
247 I2C_SendByte(addr << 1 | I2C_Direction_Receiver);
248 I2C_WaitAck();
249 while (len) {
250 *buf = I2C_ReceiveByte();
251 if (len == 1) {
252 I2C_NoAck();
254 else {
255 I2C_Ack();
257 buf++;
258 len--;
260 I2C_Stop();
261 return true;
264 uint16_t i2cGetErrorCounter(void)
266 return i2cErrorCount;
269 #endif