Merge pull request #11494 from haslinghuis/dshot_gpio
[betaflight.git] / src / main / drivers / bus_i2c_stm32f30x.c
blob30a342f8c4c5a0950845b854ed47e414dcd02a44
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>
23 #include <string.h>
25 #include "platform.h"
27 #if defined(USE_I2C) && !defined(SOFT_I2C)
29 #include "build/debug.h"
31 #include "drivers/system.h"
32 #include "drivers/io.h"
33 #include "drivers/io_impl.h"
34 #include "drivers/rcc.h"
35 #include "drivers/time.h"
37 #include "drivers/bus_i2c.h"
38 #include "drivers/bus_i2c_impl.h"
39 #include "drivers/bus_i2c_timing.h"
41 #define IOCFG_I2C_PU IO_CONFIG(GPIO_Mode_AF, GPIO_Speed_50MHz, GPIO_OType_OD, GPIO_PuPd_UP)
42 #define IOCFG_I2C IO_CONFIG(GPIO_Mode_AF, GPIO_Speed_50MHz, GPIO_OType_OD, GPIO_PuPd_NOPULL)
44 #define I2C_GPIO_AF GPIO_AF_4
46 static volatile uint16_t i2cErrorCount = 0;
48 const i2cHardware_t i2cHardware[I2CDEV_COUNT] = {
49 #ifdef USE_I2C_DEVICE_1
51 .device = I2CDEV_1,
52 .reg = I2C1,
53 .sclPins = { I2CPINDEF(PA15), I2CPINDEF(PB6), I2CPINDEF(PB8) },
54 .sdaPins = { I2CPINDEF(PA14), I2CPINDEF(PB7), I2CPINDEF(PB9) },
55 .rcc = RCC_APB1(I2C1),
57 #endif
58 #ifdef USE_I2C_DEVICE_2
60 .device = I2CDEV_2,
61 .reg = I2C2,
62 .sclPins = { I2CPINDEF(PA9), I2CPINDEF(PF6) },
63 .sdaPins = { I2CPINDEF(PA10) },
64 .rcc = RCC_APB1(I2C2),
66 #endif
69 i2cDevice_t i2cDevice[I2CDEV_COUNT];
71 ///////////////////////////////////////////////////////////////////////////////
72 // I2C TimeoutUserCallback
73 ///////////////////////////////////////////////////////////////////////////////
75 uint32_t i2cTimeoutUserCallback(void)
77 i2cErrorCount++;
78 return false;
81 void i2cInit(I2CDevice device)
83 if (device == I2CINVALID || device >= I2CDEV_COUNT) {
84 return;
87 i2cDevice_t *pDev = &i2cDevice[device];
88 const i2cHardware_t *hw = pDev->hardware;
90 if (!hw) {
91 return;
94 I2C_TypeDef *I2Cx = pDev->reg;
96 IO_t scl = pDev->scl;
97 IO_t sda = pDev->sda;
99 RCC_ClockCmd(hw->rcc, ENABLE);
100 RCC_I2CCLKConfig(I2Cx == I2C2 ? RCC_I2C2CLK_SYSCLK : RCC_I2C1CLK_SYSCLK);
102 IOInit(scl, OWNER_I2C_SCL, RESOURCE_INDEX(device));
103 IOConfigGPIOAF(scl, pDev->pullUp ? IOCFG_I2C_PU : IOCFG_I2C, GPIO_AF_4);
105 IOInit(sda, OWNER_I2C_SDA, RESOURCE_INDEX(device));
106 IOConfigGPIOAF(sda, pDev->pullUp ? IOCFG_I2C_PU : IOCFG_I2C, GPIO_AF_4);
108 I2C_InitTypeDef i2cInit = {
109 .I2C_Mode = I2C_Mode_I2C,
110 .I2C_AnalogFilter = I2C_AnalogFilter_Enable,
111 .I2C_DigitalFilter = 0x00,
112 .I2C_OwnAddress1 = 0x00,
113 .I2C_Ack = I2C_Ack_Enable,
114 .I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit,
115 .I2C_Timing = i2cClockTIMINGR(SystemCoreClock, pDev->clockSpeed, 0)
118 I2C_Init(I2Cx, &i2cInit);
120 I2C_StretchClockCmd(I2Cx, ENABLE);
122 I2C_Cmd(I2Cx, ENABLE);
125 uint16_t i2cGetErrorCounter(void)
127 return i2cErrorCount;
130 bool i2cWrite(I2CDevice device, uint8_t addr_, uint8_t reg, uint8_t data)
132 if (device == I2CINVALID || device >= I2CDEV_COUNT) {
133 return false;
136 I2C_TypeDef *I2Cx = i2cDevice[device].reg;
138 if (!I2Cx) {
139 return false;
142 addr_ <<= 1;
144 timeUs_t timeoutStartUs;
146 /* Test on BUSY Flag */
147 timeoutStartUs = microsISR();
148 while (I2C_GetFlagStatus(I2Cx, I2C_ISR_BUSY) != RESET) {
149 if (cmpTimeUs(microsISR(), timeoutStartUs) >= I2C_TIMEOUT_US) {
150 return i2cTimeoutUserCallback();
154 /* Configure slave address, nbytes, reload, end mode and start or stop generation */
155 I2C_TransferHandling(I2Cx, addr_, 1, I2C_Reload_Mode, I2C_Generate_Start_Write);
157 /* Wait until TXIS flag is set */
158 timeoutStartUs = microsISR();
159 while (I2C_GetFlagStatus(I2Cx, I2C_ISR_TXIS) == RESET) {
160 if (cmpTimeUs(microsISR(), timeoutStartUs) >= I2C_TIMEOUT_US) {
161 return i2cTimeoutUserCallback();
165 /* Send Register address */
166 I2C_SendData(I2Cx, (uint8_t) reg);
168 /* Wait until TCR flag is set */
169 timeoutStartUs = microsISR();
170 while (I2C_GetFlagStatus(I2Cx, I2C_ISR_TCR) == RESET) {
171 if (cmpTimeUs(microsISR(), timeoutStartUs) >= I2C_TIMEOUT_US) {
172 return i2cTimeoutUserCallback();
176 /* Configure slave address, nbytes, reload, end mode and start or stop generation */
177 I2C_TransferHandling(I2Cx, addr_, 1, I2C_AutoEnd_Mode, I2C_No_StartStop);
179 /* Wait until TXIS flag is set */
180 timeoutStartUs = microsISR();
181 while (I2C_GetFlagStatus(I2Cx, I2C_ISR_TXIS) == RESET) {
182 if (cmpTimeUs(microsISR(), timeoutStartUs) >= I2C_TIMEOUT_US) {
183 return i2cTimeoutUserCallback();
187 /* Write data to TXDR */
188 I2C_SendData(I2Cx, data);
190 /* Wait until STOPF flag is set */
191 timeoutStartUs = microsISR();
192 while (I2C_GetFlagStatus(I2Cx, I2C_ISR_STOPF) == RESET) {
193 if (cmpTimeUs(microsISR(), timeoutStartUs) >= I2C_TIMEOUT_US) {
194 return i2cTimeoutUserCallback();
198 /* Clear STOPF flag */
199 I2C_ClearFlag(I2Cx, I2C_ICR_STOPCF);
201 return true;
204 bool i2cRead(I2CDevice device, uint8_t addr_, uint8_t reg, uint8_t len, uint8_t* buf)
206 if (device == I2CINVALID || device >= I2CDEV_COUNT) {
207 return false;
210 I2C_TypeDef *I2Cx = i2cDevice[device].reg;
212 if (!I2Cx) {
213 return false;
216 addr_ <<= 1;
218 timeUs_t timeoutStartUs;
220 /* Test on BUSY Flag */
221 timeoutStartUs = microsISR();
222 while (I2C_GetFlagStatus(I2Cx, I2C_ISR_BUSY) != RESET) {
223 if (cmpTimeUs(microsISR(), timeoutStartUs) >= I2C_TIMEOUT_US) {
224 return i2cTimeoutUserCallback();
228 /* Configure slave address, nbytes, reload, end mode and start or stop generation */
229 I2C_TransferHandling(I2Cx, addr_, 1, I2C_SoftEnd_Mode, I2C_Generate_Start_Write);
231 /* Wait until TXIS flag is set */
232 timeoutStartUs = microsISR();
233 while (I2C_GetFlagStatus(I2Cx, I2C_ISR_TXIS) == RESET) {
234 if (cmpTimeUs(microsISR(), timeoutStartUs) >= I2C_TIMEOUT_US) {
235 return i2cTimeoutUserCallback();
239 /* Send Register address */
240 I2C_SendData(I2Cx, (uint8_t) reg);
242 /* Wait until TC flag is set */
243 timeoutStartUs = microsISR();
244 while (I2C_GetFlagStatus(I2Cx, I2C_ISR_TC) == RESET) {
245 if (cmpTimeUs(microsISR(), timeoutStartUs) >= I2C_TIMEOUT_US) {
246 return i2cTimeoutUserCallback();
250 /* Configure slave address, nbytes, reload, end mode and start or stop generation */
251 I2C_TransferHandling(I2Cx, addr_, len, I2C_AutoEnd_Mode, I2C_Generate_Start_Read);
253 /* Wait until all data are received */
254 while (len) {
255 /* Wait until RXNE flag is set */
256 timeoutStartUs = microsISR();
257 while (I2C_GetFlagStatus(I2Cx, I2C_ISR_RXNE) == RESET) {
258 if (cmpTimeUs(microsISR(), timeoutStartUs) >= I2C_TIMEOUT_US) {
259 return i2cTimeoutUserCallback();
263 /* Read data from RXDR */
264 *buf = I2C_ReceiveData(I2Cx);
265 /* Point to the next location where the byte read will be saved */
266 buf++;
268 /* Decrement the read bytes counter */
269 len--;
272 /* Wait until STOPF flag is set */
273 timeoutStartUs = microsISR();
274 while (I2C_GetFlagStatus(I2Cx, I2C_ISR_STOPF) == RESET) {
275 if (cmpTimeUs(microsISR(), timeoutStartUs) >= I2C_TIMEOUT_US) {
276 return i2cTimeoutUserCallback();
280 /* Clear STOPF flag */
281 I2C_ClearFlag(I2Cx, I2C_ICR_STOPCF);
283 /* If all operations OK */
284 return true;
287 bool i2cWriteBuffer(I2CDevice device, uint8_t addr_, uint8_t reg_, uint8_t len_, uint8_t *data)
289 bool status = true;
291 for (uint8_t i = 0; i < len_; i++) {
292 status &= i2cWrite(device, addr_, reg_ + i, data[i]);
295 return status;
298 bool i2cReadBuffer(I2CDevice device, uint8_t addr_, uint8_t reg, uint8_t len, uint8_t* buf)
300 return i2cRead(device, addr_, reg, len, buf);
303 bool i2cBusy(I2CDevice device, bool *error)
305 UNUSED(device);
306 UNUSED(error);
308 return false;
310 #endif