/* * This file is part of Cleanflight. * * Cleanflight is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Cleanflight is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Cleanflight. If not, see . */ #include #include #include #include "build_config.h" #include "gpio.h" // Software I2C driver, using same pins as hardware I2C, with hw i2c module disabled. // Can be configured for I2C2 pinout (SCL: PB10, SDA: PB11) or I2C1 pinout (SCL: PB6, SDA: PB7) #ifdef SOFT_I2C #ifdef SOFT_I2C_PB1011 #define SCL_H GPIOB->BSRR = Pin_10 #define SCL_L GPIOB->BRR = Pin_10 #define SDA_H GPIOB->BSRR = Pin_11 #define SDA_L GPIOB->BRR = Pin_11 #define SCL_read (GPIOB->IDR & Pin_10) #define SDA_read (GPIOB->IDR & Pin_11) #define I2C_PINS (Pin_10 | Pin_11) #define I2C_GPIO GPIOB #endif #ifdef SOFT_I2C_PB67 #define SCL_H GPIOB->BSRR = Pin_6 #define SCL_L GPIOB->BRR = Pin_6 #define SDA_H GPIOB->BSRR = Pin_7 #define SDA_L GPIOB->BRR = Pin_7 #define SCL_read (GPIOB->IDR & Pin_6) #define SDA_read (GPIOB->IDR & Pin_7) #define I2C_PINS (Pin_6 | Pin_7) #define I2C_GPIO GPIOB #endif #ifndef SCL_H #error Need to define SOFT_I2C_PB1011 or SOFT_I2C_PB67 (see board.h) #endif static void I2C_delay(void) { volatile int i = 7; while (i) { i--; } } static bool I2C_Start(void) { SDA_H; SCL_H; I2C_delay(); if (!SDA_read) { return false; } SDA_L; I2C_delay(); if (SDA_read) { return false; } SDA_L; I2C_delay(); return true; } static void I2C_Stop(void) { SCL_L; I2C_delay(); SDA_L; I2C_delay(); SCL_H; I2C_delay(); SDA_H; I2C_delay(); } static void I2C_Ack(void) { SCL_L; I2C_delay(); SDA_L; I2C_delay(); SCL_H; I2C_delay(); SCL_L; I2C_delay(); } static void I2C_NoAck(void) { SCL_L; I2C_delay(); SDA_H; I2C_delay(); SCL_H; I2C_delay(); SCL_L; I2C_delay(); } static bool I2C_WaitAck(void) { SCL_L; I2C_delay(); SDA_H; I2C_delay(); SCL_H; I2C_delay(); if (SDA_read) { SCL_L; return false; } SCL_L; return true; } static void I2C_SendByte(uint8_t byte) { uint8_t i = 8; while (i--) { SCL_L; I2C_delay(); if (byte & 0x80) { SDA_H; } else { SDA_L; } byte <<= 1; I2C_delay(); SCL_H; I2C_delay(); } SCL_L; } static uint8_t I2C_ReceiveByte(void) { uint8_t i = 8; uint8_t byte = 0; SDA_H; while (i--) { byte <<= 1; SCL_L; I2C_delay(); SCL_H; I2C_delay(); if (SDA_read) { byte |= 0x01; } } SCL_L; return byte; } void i2cInit(I2C_TypeDef * I2C) { gpio_config_t gpio; gpio.pin = I2C_PINS; gpio.speed = Speed_2MHz; gpio.mode = Mode_Out_OD; gpioInit(I2C_GPIO, &gpio); } bool i2cWriteBuffer(uint8_t addr, uint8_t reg, uint8_t len, uint8_t * data) { int i; if (!I2C_Start()) { return false; } I2C_SendByte(addr << 1 | I2C_Direction_Transmitter); if (!I2C_WaitAck()) { I2C_Stop(); return false; } I2C_SendByte(reg); I2C_WaitAck(); for (i = 0; i < len; i++) { I2C_SendByte(data[i]); if (!I2C_WaitAck()) { I2C_Stop(); return false; } } I2C_Stop(); return true; } bool i2cWrite(uint8_t addr, uint8_t reg, uint8_t data) { if (!I2C_Start()) { return false; } I2C_SendByte(addr << 1 | I2C_Direction_Transmitter); if (!I2C_WaitAck()) { I2C_Stop(); return false; } I2C_SendByte(reg); I2C_WaitAck(); I2C_SendByte(data); I2C_WaitAck(); I2C_Stop(); return true; } bool i2cRead(uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf) { if (!I2C_Start()) { return false; } I2C_SendByte(addr << 1 | I2C_Direction_Transmitter); if (!I2C_WaitAck()) { I2C_Stop(); return false; } I2C_SendByte(reg); I2C_WaitAck(); I2C_Start(); I2C_SendByte(addr << 1 | I2C_Direction_Receiver); I2C_WaitAck(); while (len) { *buf = I2C_ReceiveByte(); if (len == 1) { I2C_NoAck(); } else { I2C_Ack(); } buf++; len--; } I2C_Stop(); return true; } uint16_t i2cGetErrorCounter(void) { // TODO maybe fix this, but since this is test code, doesn't matter. return 0; } #endif