mirror of
https://github.com/betaflight/betaflight.git
synced 2025-07-13 11:29:58 +03:00
PICO: Initial implementation of i2c (#14434)
* PICO: Initial implementation of i2c - also adding first part of DMA * Correcting incorrect commits.
This commit is contained in:
parent
7b0bc3de7d
commit
3e2949f659
7 changed files with 356 additions and 21 deletions
210
src/platform/PICO/bus_i2c_pico.c
Normal file
210
src/platform/PICO/bus_i2c_pico.c
Normal file
|
@ -0,0 +1,210 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#if defined(USE_I2C) && !defined(SOFT_I2C)
|
||||
|
||||
#include "hardware/i2c.h"
|
||||
#include "hardware/dma.h"
|
||||
#include "hardware/irq.h"
|
||||
|
||||
#include "drivers/bus_i2c.h"
|
||||
#include "drivers/bus_i2c_impl.h"
|
||||
#include "drivers/io.h"
|
||||
#include "drivers/io_impl.h"
|
||||
|
||||
#define I2C_TX_BUFFER_LENGTH 32
|
||||
|
||||
static volatile uint16_t i2cErrorCount = 0;
|
||||
|
||||
i2cDevice_t i2cDevice[I2CDEV_COUNT];
|
||||
|
||||
const i2cHardware_t i2cHardware[I2CDEV_COUNT] = {
|
||||
#ifdef USE_I2C_DEVICE_0
|
||||
{
|
||||
.device = I2CDEV_0,
|
||||
.reg = I2C0,
|
||||
.sclPins = {
|
||||
{ DEFIO_TAG_E(PA1) },
|
||||
{ DEFIO_TAG_E(PA5) },
|
||||
{ DEFIO_TAG_E(PA9) },
|
||||
{ DEFIO_TAG_E(PA13) },
|
||||
},
|
||||
.sdaPins = {
|
||||
{ DEFIO_TAG_E(PA0) },
|
||||
{ DEFIO_TAG_E(PA4) },
|
||||
{ DEFIO_TAG_E(PA8) },
|
||||
{ DEFIO_TAG_E(PA12) },
|
||||
},
|
||||
},
|
||||
#endif
|
||||
#ifdef USE_I2C_DEVICE_1
|
||||
{
|
||||
.device = I2CDEV_1,
|
||||
.reg = I2C1,
|
||||
.sclPins = {
|
||||
{ DEFIO_TAG_E(PA3) },
|
||||
{ DEFIO_TAG_E(PA7) },
|
||||
{ DEFIO_TAG_E(PA11) },
|
||||
{ DEFIO_TAG_E(PA15) },
|
||||
},
|
||||
.sdaPins = {
|
||||
{ DEFIO_TAG_E(PA2) },
|
||||
{ DEFIO_TAG_E(PA6) },
|
||||
{ DEFIO_TAG_E(PA10) },
|
||||
{ DEFIO_TAG_E(PA14) },
|
||||
}
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
static bool i2cHandleHardwareFailure(I2CDevice device)
|
||||
{
|
||||
UNUSED(device);
|
||||
i2cErrorCount++;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t i2cGetErrorCounter(void)
|
||||
{
|
||||
return i2cErrorCount;
|
||||
}
|
||||
|
||||
bool i2cWrite(I2CDevice device, uint8_t addr_, uint8_t reg_, uint8_t data)
|
||||
{
|
||||
return i2cWriteBuffer(device, addr_, reg_, 1, &data);
|
||||
}
|
||||
|
||||
bool i2cWriteBuffer(I2CDevice device, uint8_t addr_, uint8_t reg_, uint8_t len_, uint8_t *data)
|
||||
{
|
||||
// TODO: Implement non-blocking write using DMA or similar mechanism
|
||||
if (device == I2CINVALID || device >= I2CDEV_COUNT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
i2c_inst_t *port = I2C_INST(&i2cHardware[device].reg);
|
||||
|
||||
if (!port) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (len_ > I2C_TX_BUFFER_LENGTH - 1) {
|
||||
return false; // Buffer too long
|
||||
}
|
||||
|
||||
uint8_t buf[I2C_TX_BUFFER_LENGTH] = { reg_, 0 };
|
||||
memcpy(&buf[1], data, len_);
|
||||
int status = i2c_write_timeout_us(port, addr_ << 1, buf, len_ + 1, true, I2C_TIMEOUT_US);
|
||||
|
||||
if (status < 0) {
|
||||
return i2cHandleHardwareFailure(device);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool i2cRead(I2CDevice device, uint8_t addr_, uint8_t reg_, uint8_t len, uint8_t* buf)
|
||||
{
|
||||
if (device == I2CINVALID || device >= I2CDEV_COUNT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
i2c_inst_t *port = I2C_INST(&i2cHardware[device].reg);
|
||||
|
||||
if (!port) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int status = i2c_write_timeout_us(port, addr_ << 1, ®_, 1, true, I2C_TIMEOUT_US);
|
||||
if (status < 0) {
|
||||
return i2cHandleHardwareFailure(device);
|
||||
}
|
||||
|
||||
status = i2c_read_timeout_us(port, addr_ << 1, buf, len, true, I2C_TIMEOUT_US);
|
||||
if (status < 0) {
|
||||
return i2cHandleHardwareFailure(device);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool i2cReadBuffer(I2CDevice device, uint8_t addr_, uint8_t reg_, uint8_t len, uint8_t* buf)
|
||||
{
|
||||
// TODO: Implement genuine non-blocking read using DMA or similar mechanism
|
||||
return i2cRead(device, addr_, reg_, len, buf);
|
||||
}
|
||||
|
||||
bool i2cBusy(I2CDevice device, bool *error)
|
||||
{
|
||||
if (device == I2CINVALID || device >= I2CDEV_COUNT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
i2c_inst_t *port = I2C_INST(&i2cHardware[device].reg);
|
||||
|
||||
if (!port) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
*error = 0;
|
||||
}
|
||||
|
||||
// Read the IC_STATUS register
|
||||
uint32_t status_reg = port->hw->status;
|
||||
|
||||
// The bit for MST_ACTIVITY is (1 << 5).
|
||||
return (status_reg & (1 << 5)) != 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
i2c_init(I2C_INST(hardware->reg), pDev->clockSpeed);
|
||||
|
||||
// Set up GPIO pins for I2C
|
||||
gpio_set_function(IO_Pin(sda), GPIO_FUNC_I2C);
|
||||
gpio_set_function(IO_Pin(scl), GPIO_FUNC_I2C);
|
||||
|
||||
// Enable internal pull-up resistors
|
||||
gpio_pull_up(IO_Pin(sda));
|
||||
gpio_pull_up(IO_Pin(scl));
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue