Skip to content

Commit

Permalink
Merge pull request #129 from pimoroni/patch-gpio-int-types
Browse files Browse the repository at this point in the history
Add a common header for pins and settings + common I2C class for managing I2C busses across drivers
  • Loading branch information
Gadgetoid authored May 19, 2021
2 parents 76bdf3f + 0bda2ab commit cb958a7
Show file tree
Hide file tree
Showing 121 changed files with 1,195 additions and 1,088 deletions.
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ include_directories(
${CMAKE_CURRENT_LIST_DIR}
)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror")

add_subdirectory(common)
add_subdirectory(drivers)
add_subdirectory(libraries)

Expand Down
9 changes: 9 additions & 0 deletions common/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
add_library(pimoroni_i2c INTERFACE)

target_sources(pimoroni_i2c INTERFACE
${CMAKE_CURRENT_LIST_DIR}/pimoroni_i2c.cpp)

target_include_directories(pimoroni_i2c INTERFACE ${CMAKE_CURRENT_LIST_DIR})

# Pull in pico libraries that we need
target_link_libraries(pimoroni_i2c INTERFACE pico_stdlib)
41 changes: 41 additions & 0 deletions common/pimoroni_common.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#pragma once
#include <stdint.h>
#include <climits>

#define PIMORONI_I2C_DEFAULT_INSTANCE i2c0
#define PIMORONI_SPI_DEFAULT_INSTANCE spi0

namespace pimoroni {
static const unsigned int PIN_UNUSED = INT_MAX; // Intentionally INT_MAX to avoid overflowing MicroPython's int type

// I2C
static const unsigned int I2C_DEFAULT_BAUDRATE = 400000;
static const unsigned int I2C_DEFAULT_SDA = 20;
static const unsigned int I2C_DEFAULT_SCL = 21;
static const unsigned int I2C_DEFAULT_INT = 22;

static const unsigned int I2C_BG_SDA = 4;
static const unsigned int I2C_BG_SCL = 5;
static const unsigned int I2C_BG_INT = 3;

// SPI
static const unsigned int SPI_DEFAULT_MOSI = 19;
static const unsigned int SPI_DEFAULT_MISO = 16;
static const unsigned int SPI_DEFAULT_SCK = 18;

static const unsigned int SPI_BG_FRONT_PWM = 20;
static const unsigned int SPI_BG_FRONT_CS = 17;

static const unsigned int SPI_BG_BACK_PWM = 21;
static const unsigned int SPI_BG_BACK_CS = 22;

enum BG_SPI_SLOT {
BG_SPI_FRONT,
BG_SPI_BACK
};

enum BOARD {
BREAKOUT_GARDEN,
PICO_EXPLORER
};
}
91 changes: 91 additions & 0 deletions common/pimoroni_i2c.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#include "pimoroni_common.hpp"
#include "pimoroni_i2c.hpp"

namespace pimoroni {
void I2C::init() {
i2c = ((sda / 2) & 0b1) ? i2c1 : i2c0;

i2c_init(i2c, baudrate);

gpio_set_function(sda, GPIO_FUNC_I2C); gpio_pull_up(sda);
gpio_set_function(scl, GPIO_FUNC_I2C); gpio_pull_up(scl);
}

/* Basic wrappers for devices using i2c functions directly */
int I2C::write_blocking(uint8_t addr, const uint8_t *src, size_t len, bool nostop) {
return i2c_write_blocking(i2c, addr, src, len, nostop);
}

int I2C::read_blocking(uint8_t addr, uint8_t *dst, size_t len, bool nostop) {
return i2c_read_blocking(i2c, addr, dst, len, nostop);
}

/* Convenience functions for various common i2c operations */
void I2C::reg_write_uint8(uint8_t address, uint8_t reg, uint8_t value) {
uint8_t buffer[2] = {reg, value};
i2c_write_blocking(i2c, address, buffer, 2, false);
}

uint8_t I2C::reg_read_uint8(uint8_t address, uint8_t reg) {
uint8_t value;
i2c_write_blocking(i2c, address, &reg, 1, false);
i2c_read_blocking(i2c, address, (uint8_t *)&value, sizeof(uint8_t), false);
return value;
}

uint16_t I2C::reg_read_uint16(uint8_t address, uint8_t reg) {
uint16_t value;
i2c_write_blocking(i2c, address, &reg, 1, true);
i2c_read_blocking(i2c, address, (uint8_t *)&value, sizeof(uint16_t), false);
return value;
}

uint32_t I2C::reg_read_uint32(uint8_t address, uint8_t reg) {
uint32_t value;
i2c_write_blocking(i2c, address, &reg, 1, true);
i2c_read_blocking(i2c, address, (uint8_t *)&value, sizeof(uint32_t), false);
return value;
}

int16_t I2C::reg_read_int16(uint8_t address, uint8_t reg) {
int16_t value;
i2c_write_blocking(i2c, address, &reg, 1, true);
i2c_read_blocking(i2c, address, (uint8_t *)&value, sizeof(int16_t), false);
return value;
}

int I2C::write_bytes(uint8_t address, uint8_t reg, uint8_t *buf, int len) {
uint8_t buffer[len + 1];
buffer[0] = reg;
for(int x = 0; x < len; x++) {
buffer[x + 1] = buf[x];
}
return i2c_write_blocking(i2c, address, buffer, len + 1, false);
};

int I2C::read_bytes(uint8_t address, uint8_t reg, uint8_t *buf, int len) {
i2c_write_blocking(i2c, address, &reg, 1, true);
i2c_read_blocking(i2c, address, buf, len, false);
return len;
};

uint8_t I2C::get_bits(uint8_t address, uint8_t reg, uint8_t shift, uint8_t mask) {
uint8_t value;
read_bytes(address, reg, &value, 1);
return value & (mask << shift);
}

void I2C::set_bits(uint8_t address, uint8_t reg, uint8_t shift, uint8_t mask) {
uint8_t value;
read_bytes(address, reg, &value, 1);
value |= mask << shift;
write_bytes(address, reg, &value, 1);
}

void I2C::clear_bits(uint8_t address, uint8_t reg, uint8_t shift, uint8_t mask) {
uint8_t value;
read_bytes(address, reg, &value, 1);
value &= ~(mask << shift);
write_bytes(address, reg, &value, 1);
}
}
72 changes: 72 additions & 0 deletions common/pimoroni_i2c.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#pragma once
#include <stdint.h>
#include <climits>
#include "hardware/i2c.h"
#include "hardware/gpio.h"
#include "pimoroni_common.hpp"
#include "pimoroni_i2c.hpp"

namespace pimoroni {
class I2C {
private:
i2c_inst_t *i2c = PIMORONI_I2C_DEFAULT_INSTANCE;
uint sda = I2C_DEFAULT_SDA;
uint scl = I2C_DEFAULT_SCL;
uint interrupt = PIN_UNUSED;
uint32_t baudrate = I2C_DEFAULT_BAUDRATE;

public:
I2C(BOARD board, uint32_t baudrate = I2C_DEFAULT_BAUDRATE) : baudrate(baudrate) {
switch(board) {
case BREAKOUT_GARDEN:
sda = I2C_BG_SDA;
scl = I2C_BG_SCL;
interrupt = I2C_BG_INT;
break;
case PICO_EXPLORER:
default:
sda = I2C_DEFAULT_SDA;
scl = I2C_DEFAULT_SCL;
interrupt = I2C_DEFAULT_INT;
break;
}
init();
}

I2C(uint sda, uint scl, uint32_t baudrate = I2C_DEFAULT_BAUDRATE) : sda(sda), scl(scl), baudrate(baudrate) {
init();
}

I2C() : I2C(I2C_DEFAULT_SDA, I2C_DEFAULT_SCL) {}

~I2C() {
i2c_deinit(i2c);
gpio_disable_pulls(sda);
gpio_set_function(sda, GPIO_FUNC_NULL);
gpio_disable_pulls(scl);
gpio_set_function(scl, GPIO_FUNC_NULL);
}

void reg_write_uint8(uint8_t address, uint8_t reg, uint8_t value);
uint8_t reg_read_uint8(uint8_t address, uint8_t reg);
uint16_t reg_read_uint16(uint8_t address, uint8_t reg);
int16_t reg_read_int16(uint8_t address, uint8_t reg);
uint32_t reg_read_uint32(uint8_t address, uint8_t reg);

int write_bytes(uint8_t address, uint8_t reg, uint8_t *buf, int len);
int read_bytes(uint8_t address, uint8_t reg, uint8_t *buf, int len);
uint8_t get_bits(uint8_t address, uint8_t reg, uint8_t shift, uint8_t mask=0b1);
void set_bits(uint8_t address, uint8_t reg, uint8_t shift, uint8_t mask=0b1);
void clear_bits(uint8_t address, uint8_t reg, uint8_t shift, uint8_t mask=0b1);

int write_blocking(uint8_t addr, const uint8_t *src, size_t len, bool nostop);
int read_blocking(uint8_t addr, uint8_t *dst, size_t len, bool nostop);

i2c_inst_t* get_i2c() {return i2c;}
uint get_scl() {return scl;}
uint get_sda() {return sda;}
uint32_t get_baudrate() {return baudrate;}
private:
void init();
};
}
2 changes: 1 addition & 1 deletion drivers/as7262/as7262.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ target_sources(${DRIVER_NAME} INTERFACE
target_include_directories(${DRIVER_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})

# Pull in pico libraries that we need
target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib hardware_i2c)
target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib hardware_i2c pimoroni_i2c)
19 changes: 6 additions & 13 deletions drivers/as7262/as7262.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,6 @@ namespace pimoroni {
bool AS7262::init() {
bool succeeded = false;

i2c_init(i2c, 400000);

gpio_set_function(sda, GPIO_FUNC_I2C);
gpio_pull_up(sda);
gpio_set_function(scl, GPIO_FUNC_I2C);
gpio_pull_up(scl);

if(interrupt != PIN_UNUSED) {
gpio_set_function(interrupt, GPIO_FUNC_SIO);
gpio_set_dir(interrupt, GPIO_IN);
Expand All @@ -71,15 +64,15 @@ namespace pimoroni {
}

i2c_inst_t* AS7262::get_i2c() const {
return i2c;
return i2c->get_i2c();
}

int AS7262::get_sda() const {
return sda;
return i2c->get_sda();
}

int AS7262::get_scl() const {
return scl;
return i2c->get_scl();
}

int AS7262::get_int() const {
Expand Down Expand Up @@ -216,13 +209,13 @@ namespace pimoroni {
// Plumbing for virtual i2c
void AS7262::_i2c_reg_write_uint8(uint8_t reg, uint8_t value) {
uint8_t buffer[2] = {reg, value};
i2c_write_blocking(i2c, address, buffer, 2, false);
i2c->write_blocking(address, buffer, 2, false);
}

uint8_t AS7262::_i2c_reg_read_uint8(uint8_t reg) {
uint8_t value;
i2c_write_blocking(i2c, address, &reg, 1, false);
i2c_read_blocking(i2c, address, (uint8_t *)&value, 1, false);
i2c->write_blocking(address, &reg, 1, false);
i2c->read_blocking(address, (uint8_t *)&value, 1, false);
return value;
}
}
20 changes: 9 additions & 11 deletions drivers/as7262/as7262.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#include "hardware/i2c.h"
#include "hardware/gpio.h"
#include "common/pimoroni_common.hpp"
#include "common/pimoroni_i2c.hpp"

namespace pimoroni {

Expand All @@ -13,10 +15,6 @@ namespace pimoroni {
//--------------------------------------------------
public:
static const uint8_t DEFAULT_I2C_ADDRESS = 0x49;
static const uint8_t DEFAULT_SDA_PIN = 20;
static const uint8_t DEFAULT_SCL_PIN = 21;
static const uint8_t DEFAULT_INT_PIN = 22;
static const uint8_t PIN_UNUSED = UINT8_MAX;


//--------------------------------------------------
Expand Down Expand Up @@ -70,23 +68,23 @@ namespace pimoroni {
// Variables
//--------------------------------------------------
private:
i2c_inst_t *i2c = i2c0;
I2C *i2c;

// interface pins with our standard defaults where appropriate
int8_t address = DEFAULT_I2C_ADDRESS;
int8_t sda = DEFAULT_SDA_PIN;
int8_t scl = DEFAULT_SCL_PIN;
int8_t interrupt = DEFAULT_INT_PIN;
uint interrupt = PIN_UNUSED;


//--------------------------------------------------
// Constructors/Destructor
//--------------------------------------------------
public:
AS7262() {}
AS7262(uint interrupt = PIN_UNUSED) : AS7262(new I2C(), interrupt) {};

AS7262(i2c_inst_t *i2c, uint8_t sda, uint8_t scl, uint8_t interrupt = PIN_UNUSED) :
i2c(i2c), sda(sda), scl(scl), interrupt(interrupt) {}
AS7262(I2C *i2c, uint interrupt = PIN_UNUSED) : i2c(i2c), interrupt(interrupt) {}

// TODO remove MicroPython-binding compatibility constructors
AS7262(uint sda, uint scl, uint interrupt = PIN_UNUSED) : AS7262(new I2C(), interrupt) {}


//--------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion drivers/ioexpander/ioexpander.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ target_sources(${DRIVER_NAME} INTERFACE
target_include_directories(${DRIVER_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})

# Pull in pico libraries that we need
target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib hardware_i2c)
target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib hardware_i2c pimoroni_i2c)
Loading

0 comments on commit cb958a7

Please sign in to comment.