/* * This file is part of Betaflight. * * Betaflight is free software. You can redistribute this software * and/or modify this software 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. * * Betaflight 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 this software. * * If not, see . */ #include #include #include #include "platform.h" #if defined(USE_I2C) && !defined(SOFT_I2C) #include "drivers/io.h" #include "drivers/nvic.h" #include "drivers/time.h" #include "platform/rcc.h" #include "drivers/bus_i2c.h" #include "drivers/bus_i2c_impl.h" #include "drivers/bus_i2c_timing.h" #include "drivers/bus_i2c_utils.h" #define IOCFG_I2C_PU IO_CONFIG(GPIO_MODE_AF_OD, GPIO_SPEED_FREQ_VERY_HIGH, GPIO_PULLUP) #define IOCFG_I2C IO_CONFIG(GPIO_MODE_AF_OD, GPIO_SPEED_FREQ_VERY_HIGH, GPIO_NOPULL) const i2cHardware_t i2cHardware[I2CDEV_COUNT] = { #ifdef USE_I2C_DEVICE_1 { .device = I2CDEV_1, .reg = I2C1, .sclPins = { I2CPINDEF(PB6, GPIO_AF4_I2C1), I2CPINDEF(PB8, GPIO_AF4_I2C1) }, .sdaPins = { I2CPINDEF(PB7, GPIO_AF4_I2C1), I2CPINDEF(PB9, GPIO_AF4_I2C1) }, .rcc = RCC_APB1(I2C1), .ev_irq = I2C1_EV_IRQn, .er_irq = I2C1_ER_IRQn, }, #endif #ifdef USE_I2C_DEVICE_2 { .device = I2CDEV_2, .reg = I2C2, .sclPins = { I2CPINDEF(PB10, GPIO_AF4_I2C2), I2CPINDEF(PF1, GPIO_AF4_I2C2) }, .sdaPins = { I2CPINDEF(PB11, GPIO_AF4_I2C2), I2CPINDEF(PF0, GPIO_AF4_I2C2) }, .rcc = RCC_APB1(I2C2), .ev_irq = I2C2_EV_IRQn, .er_irq = I2C2_ER_IRQn, }, #endif #ifdef USE_I2C_DEVICE_3 { .device = I2CDEV_3, .reg = I2C3, .sclPins = { I2CPINDEF(PA8, GPIO_AF4_I2C3) }, .sdaPins = { I2CPINDEF(PC9, GPIO_AF4_I2C3) }, .rcc = RCC_APB1(I2C3), .ev_irq = I2C3_EV_IRQn, .er_irq = I2C3_ER_IRQn, }, #endif }; i2cDevice_t i2cDevice[I2CDEV_COUNT]; void i2cInit(I2CDevice device) { if (device == I2CINVALID) { return; } i2cDevice_t *pDev = &i2cDevice[device]; const i2cHardware_t *hardware = pDev->hardware; const IO_t scl = pDev->scl; const IO_t sda = pDev->sda; if (!hardware || IOGetOwner(scl) || IOGetOwner(sda)) { return; } IOInit(scl, OWNER_I2C_SCL, RESOURCE_INDEX(device)); IOInit(sda, OWNER_I2C_SDA, RESOURCE_INDEX(device)); // Enable RCC RCC_ClockCmd(hardware->rcc, ENABLE); i2cUnstick(scl, sda); // Init pins IOConfigGPIOAF(scl, pDev->pullUp ? IOCFG_I2C_PU : IOCFG_I2C, pDev->sclAF); IOConfigGPIOAF(sda, pDev->pullUp ? IOCFG_I2C_PU : IOCFG_I2C, pDev->sdaAF); // Init I2C peripheral I2C_HandleTypeDef *pHandle = &pDev->handle; memset(pHandle, 0, sizeof(*pHandle)); pHandle->Instance = pDev->hardware->reg; // Compute TIMINGR value based on peripheral clock for this device instance pHandle->Init.ClockSpeed = pDev->clockSpeed * 1000; pHandle->Init.OwnAddress1 = 0x0; pHandle->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; pHandle->Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; pHandle->Init.OwnAddress2 = 0x0; pHandle->Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; pHandle->Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; DAL_I2C_Init(pHandle); // Setup interrupt handlers DAL_NVIC_SetPriority(hardware->er_irq, NVIC_PRIORITY_BASE(NVIC_PRIO_I2C_ER), NVIC_PRIORITY_SUB(NVIC_PRIO_I2C_ER)); DAL_NVIC_EnableIRQ(hardware->er_irq); DAL_NVIC_SetPriority(hardware->ev_irq, NVIC_PRIORITY_BASE(NVIC_PRIO_I2C_EV), NVIC_PRIORITY_SUB(NVIC_PRIO_I2C_EV)); DAL_NVIC_EnableIRQ(hardware->ev_irq); } #endif