Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

egpio in c #166

Merged
merged 2 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions drivers/micropython.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,10 @@ include(${CMAKE_CURRENT_LIST_DIR}/tildagon_power/tildagon_power.cmake)
# Add OTA helpers
include(${CMAKE_CURRENT_LIST_DIR}/ota/micropython.cmake)

# Add AW9523B GPIO Expander and micropython tildagon.Pin bindings
include(${CMAKE_CURRENT_LIST_DIR}/tildagon_pin/micropython.cmake)

include(${CMAKE_CURRENT_LIST_DIR}/tildagon/micropython.cmake)

# Add burnt-in HMAC
include(${CMAKE_CURRENT_LIST_DIR}/tildagon_hmac/micropython.cmake)
12 changes: 12 additions & 0 deletions drivers/tildagon/micropython.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Create an INTERFACE library for our C module.
add_library(usermod_tildagon INTERFACE)

# Add our source files to the lib
target_sources(usermod_tildagon INTERFACE
${CMAKE_CURRENT_LIST_DIR}/tildagon.c
)


# Link our INTERFACE library to the usermod target.
target_link_libraries(usermod_tildagon INTERFACE usermod_tildagon_pin)
target_link_libraries(usermod INTERFACE usermod_tildagon)
20 changes: 20 additions & 0 deletions drivers/tildagon/tildagon.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#include "py/builtin.h"
#include "py/runtime.h"

extern mp_obj_module_t tildagon_pin_type;


static const mp_rom_map_elem_t mp_module_tildagon_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_egpio) },
// { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&tildagon_i2c_obj) },
{ MP_ROM_QSTR(MP_QSTR_ePin), MP_ROM_PTR(&tildagon_pin_type)}
};
static MP_DEFINE_CONST_DICT(mp_module_tildagon_globals, mp_module_tildagon_globals_table);

const mp_obj_module_t mp_module_tildagon = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&mp_module_tildagon_globals,
};

MP_REGISTER_MODULE(MP_QSTR_egpio, mp_module_tildagon);

10 changes: 10 additions & 0 deletions drivers/tildagon_i2c/tildagon_i2c.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@
#define TILDAGON_HOST_I2C_PORT (0)
#define TILDAGON_HOST_I2C_TIMEOUT (50000)

#define TILDAGON_TOP_I2C_PORT (0)
#define TILDAGON_HX0_I2C_PORT (1)
#define TILDAGON_HX1_I2C_PORT (2)
#define TILDAGON_HX2_I2C_PORT (3)
#define TILDAGON_HX3_I2C_PORT (4)
#define TILDAGON_HX4_I2C_PORT (5)
#define TILDAGON_HX5_I2C_PORT (6)
#define TILDAGON_SYS_I2C_PORT (7)


typedef struct _tildagon_mux_i2c_obj_t {
mp_obj_base_t base;
const tca9548a_i2c_mux_t *mux;
Expand Down
252 changes: 252 additions & 0 deletions drivers/tildagon_pin/aw9523b.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
#include "aw9523b.h"
#include <assert.h>

#include "tildagon_i2c.h"

#define READ ( MP_MACHINE_I2C_FLAG_WRITE1 | MP_MACHINE_I2C_FLAG_READ | MP_MACHINE_I2C_FLAG_STOP )
#define WRITE MP_MACHINE_I2C_FLAG_STOP

static void aw9523b_check_valid_pin(aw9523b_pin_t pin) {
assert(pin <= 15);
}

static uint8_t aw9523b_portnum(aw9523b_pin_t pin) {
return pin / 8;
}
static uint8_t aw9523b_portpin(aw9523b_pin_t pin) {
return pin % 8;
}

static esp_err_t aw9523b_readregs(aw9523b_device_t *dev, uint8_t reg, uint8_t *regs, size_t nregs) {

tildagon_mux_i2c_obj_t *mux = tildagon_get_mux_obj(7);
mp_machine_i2c_buf_t buffer[2] = { { .len = 1, .buf = &reg },
{ .len = nregs, .buf = regs } };
return tildagon_mux_i2c_transaction(mux, dev->i2c_addr, 2, (mp_machine_i2c_buf_t*)&buffer, READ);
}

static esp_err_t aw9523b_writeregs(aw9523b_device_t *dev, uint8_t reg, const uint8_t *regs, size_t nregs) {
uint8_t buf[nregs+1];
buf[0] = reg;
memcpy(buf+1, regs, nregs);
tildagon_mux_i2c_obj_t *mux = tildagon_get_mux_obj(7);
mp_machine_i2c_buf_t buffer[1] = { { .len = nregs+1, .buf = buf } };
return tildagon_mux_i2c_transaction(mux, dev->i2c_addr, 1, (mp_machine_i2c_buf_t*)&buffer, WRITE);
}

void aw9523b_init(aw9523b_device_t *dev) {
aw9523b_writeregs(dev, 0x06, (const uint8_t*)"\xff\xff", 2);
aw9523b_writeregs(dev, 0x04, (const uint8_t*)"\xff\xff", 2);
aw9523b_writeregs(dev, 0x11, (const uint8_t*)"\x10", 1);
aw9523b_writeregs(dev, 0x20, (const uint8_t*)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16);
}


bool aw9523b_pin_get_input(aw9523b_device_t *dev, aw9523b_pin_t pin) {
aw9523b_check_valid_pin(pin);
uint8_t port = aw9523b_portnum(pin);
uint8_t pin_mask = 1 << aw9523b_portpin(pin);

uint8_t reg = 0x00 + port;
uint8_t reg_val = 0;
esp_err_t err = aw9523b_readregs(dev, reg, &reg_val, 1);
if (err < 0) {
return false;
}
bool pin_val = (reg_val & pin_mask) != 0;
return pin_val;
}

bool aw9523b_pin_get_output(aw9523b_device_t *dev, aw9523b_pin_t pin) {
aw9523b_check_valid_pin(pin);
uint8_t port = aw9523b_portnum(pin);
uint8_t pin_mask = 1 << aw9523b_portpin(pin);

uint8_t reg = 0x02 + port;
uint8_t reg_val = 0;
esp_err_t err = aw9523b_readregs(dev, reg, &reg_val, 1);
if (err < 0) {
return false;
}
bool pin_val = (reg_val & pin_mask) != 0;
return pin_val;
}

void aw9523b_pin_set_output(aw9523b_device_t *dev, aw9523b_pin_t pin, aw9523b_pin_state_t state) {
aw9523b_check_valid_pin(pin);
uint8_t port = aw9523b_portnum(pin);
uint8_t pin_mask = 1 << aw9523b_portpin(pin);

uint8_t reg = 0x02 + port;
uint8_t reg_val = 0;
esp_err_t err = aw9523b_readregs(dev, reg, &reg_val, 1);
if (err < 0) {
return;
}
if (state) {
reg_val |= pin_mask;
} else {
reg_val &= ~pin_mask;
}
err = aw9523b_writeregs(dev, reg, &reg_val, 1);
}

bool aw9523b_pin_get_direction(aw9523b_device_t *dev, aw9523b_pin_t pin) {
aw9523b_check_valid_pin(pin);
uint8_t port = aw9523b_portnum(pin);
uint8_t pin_mask = 1 << aw9523b_portpin(pin);

uint8_t reg = 0x04 + port;
uint8_t reg_val = 0;
esp_err_t err = aw9523b_readregs(dev, reg, &reg_val, 1);
if (err < 0) {
return false;
}
dev->last_input_values[port] = reg_val;
bool pin_val = (reg_val & pin_mask) != 0;
return pin_val;
}

void aw9523b_pin_set_direction(aw9523b_device_t *dev, aw9523b_pin_t pin, aw9523b_pin_state_t state) {
aw9523b_check_valid_pin(pin);
uint8_t port = aw9523b_portnum(pin);
uint8_t pin_mask = 1 << aw9523b_portpin(pin);

uint8_t reg = 0x04 + port;
uint8_t reg_val = 0;
esp_err_t err = aw9523b_readregs(dev, reg, &reg_val, 1);
if (err < 0) {
return;
}
if (state) {
reg_val |= pin_mask;
} else {
reg_val &= ~pin_mask;
}
err = aw9523b_writeregs(dev, reg, &reg_val, 1);
}

aw9523b_pin_mode_t aw9523b_pin_get_mode(aw9523b_device_t *dev, aw9523b_pin_t pin) {
aw9523b_check_valid_pin(pin);
uint8_t port = aw9523b_portnum(pin);
uint8_t pin_mask = 1 << aw9523b_portpin(pin);

uint8_t reg = 0x12 + port;
uint8_t reg_val = 0;
esp_err_t err = aw9523b_readregs(dev, reg, &reg_val, 1);
if (err < 0) {
return AW9523B_PIN_MODE_INVALID;
}
aw9523b_pin_mode_t pin_mode = (reg_val & pin_mask)? AW9523B_PIN_MODE_GPIO : AW9523B_PIN_MODE_LED;
return pin_mode;
}

void aw9523b_pin_set_mode(aw9523b_device_t *dev, aw9523b_pin_t pin, aw9523b_pin_mode_t mode) {
aw9523b_check_valid_pin(pin);
uint8_t port = aw9523b_portnum(pin);
uint8_t pin_mask = 1 << aw9523b_portpin(pin);

uint8_t reg = 0x12 + port;
uint8_t reg_val = 0;
esp_err_t err = aw9523b_readregs(dev, reg, &reg_val, 1);
if (err < 0) {
return;
}
if (mode == AW9523B_PIN_MODE_GPIO) {
reg_val |= pin_mask;
} else {
reg_val &= ~pin_mask;
}
err = aw9523b_writeregs(dev, reg, &reg_val, 1);
}

void aw9523b_irq_register(aw9523b_device_t *dev, aw9523b_pin_t pin, aw9523b_irq_callback_t callback, void* args) {
aw9523b_check_valid_pin(pin);
uint8_t port = aw9523b_portnum(pin);
uint8_t pin_index = aw9523b_portpin(pin);

dev->irq_handlers[port][pin_index] = (struct aw9523b_irq_handler) {
.callback = callback,
.args = args
};
}

void aw9523b_irq_unregister(aw9523b_device_t *dev, aw9523b_pin_t pin) {
aw9523b_check_valid_pin(pin);
uint8_t port = aw9523b_portnum(pin);
dev->irq_handlers[port][pin] = (struct aw9523b_irq_handler) {
.callback = NULL,
.args = NULL
};
}

void aw9523b_irq_enable(aw9523b_device_t *dev, aw9523b_pin_t pin) {
aw9523b_check_valid_pin(pin);
uint8_t port = aw9523b_portnum(pin);
uint8_t pin_mask = 1 << aw9523b_portpin(pin);

uint8_t reg = 0x06 + port;
uint8_t reg_val = 0;
esp_err_t err = aw9523b_readregs(dev, reg, &reg_val, 1);
if (err < 0) {
return;
}
reg_val |= pin_mask;
reg_val = ~reg_val;
err = aw9523b_writeregs(dev, reg, &reg_val, 1);
reg_val = ~reg_val;
dev->irq_enables[port] = reg_val;
dev->irq_got[port] &= ~pin_mask;
}

void aw9523b_irq_disable(aw9523b_device_t *dev, aw9523b_pin_t pin) {
aw9523b_check_valid_pin(pin);
uint8_t port = aw9523b_portnum(pin);
uint8_t pin_mask = 1 << aw9523b_portpin(pin);

uint8_t reg = 0x06 + port;
uint8_t reg_val = 0;
esp_err_t err = aw9523b_readregs(dev, reg, &reg_val, 1);
if (err < 0) {
return;
}
reg_val &= ~pin_mask;
reg_val = ~reg_val;
err = aw9523b_writeregs(dev, reg, &reg_val, 1);
reg_val = ~reg_val;
dev->irq_enables[port] = reg_val;
}

void aw9523b_irq_handler(aw9523b_device_t *dev) {
uint8_t irq_enables[2];
uint8_t input_values[2];
if (aw9523b_readregs(dev, 0x06, irq_enables, 2) != ESP_OK
|| aw9523b_readregs(dev, 0x00, input_values, 2) != ESP_OK) {
return;
}
for (uint8_t port = 0; port < 2; port++) {
uint8_t changed = input_values[port] ^ dev->last_input_values[port];
dev->last_input_values[port] = input_values[port];
for (uint8_t pin = 0; pin < 8; pin++) {
uint8_t pin_mask = 1 << pin;
if (((~irq_enables[port]) & pin_mask & changed)
&& dev->irq_handlers[port][pin].callback ) {
dev->irq_handlers[port][pin].callback(dev->irq_handlers[port][pin].args);
}
}
}
}

void aw9523b_pin_set_drive(aw9523b_device_t *dev, aw9523b_pin_t pin, uint8_t drive) {
aw9523b_check_valid_pin(pin);
uint8_t port = aw9523b_portnum(pin);
uint8_t pin_index = aw9523b_portpin(pin);

uint8_t drive_regs[2][8] = {
{0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b},
{0x20, 0x21, 0x22, 0x23, 0x2c, 0x2d, 0x2e, 0x2f}
};

uint8_t reg = drive_regs[port][pin_index];
aw9523b_writeregs(dev, reg, &drive, 1);
}
55 changes: 55 additions & 0 deletions drivers/tildagon_pin/aw9523b.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#ifndef _AW9523B_H_
#define _AW9523B_H_

#include "tildagon_i2c.h"
#include <stdint.h>

typedef uint8_t aw9523b_pin_t;
typedef enum{
AW9523B_PIN_MODE_LED = 0,
AW9523B_PIN_MODE_GPIO = 1,
AW9523B_PIN_MODE_INVALID = -1

} aw9523b_pin_mode_t;
typedef bool aw9523b_pin_state_t;
typedef void (*aw9523b_irq_callback_t)(void*);

struct aw9523b_irq_handler{
aw9523b_irq_callback_t callback;
void* args;
};

typedef struct aw9523b_device{
const tca9548a_i2c_mux_t *mux;
tca9548a_i2c_port_t i2c_port;
uint16_t i2c_addr;
uint8_t last_input_values[2];
uint8_t last_port_values[2];
uint8_t direction[2];
uint8_t irq_enables[2];
uint8_t irq_got[2]; // 1 if input value is cached
struct aw9523b_irq_handler irq_handlers[2][8];
} aw9523b_device_t;

void aw9523b_init(aw9523b_device_t *dev);

void aw9523b_irq_handler(aw9523b_device_t *dev);

void aw9523b_irq_register(aw9523b_device_t *dev, aw9523b_pin_t pin, aw9523b_irq_callback_t callback, void* args);
void aw9523b_irq_unregister(aw9523b_device_t *dev, aw9523b_pin_t pin);
void aw9523b_irq_enable(aw9523b_device_t *dev, aw9523b_pin_t pin);
void aw9523b_irq_disable(aw9523b_device_t *dev, aw9523b_pin_t pin);
void aw9523b_irq_configure(aw9523b_device_t *dev, aw9523b_pin_t pin, uint8_t mode);

bool aw9523b_pin_get_input(aw9523b_device_t *dev, aw9523b_pin_t pin);
bool aw9523b_pin_get_output(aw9523b_device_t *dev, aw9523b_pin_t pin);
void aw9523b_pin_set_output(aw9523b_device_t *dev, aw9523b_pin_t pin, aw9523b_pin_state_t state);
bool aw9523b_pin_get_direction(aw9523b_device_t *dev, aw9523b_pin_t pin);
void aw9523b_pin_set_direction(aw9523b_device_t *dev, aw9523b_pin_t pin, aw9523b_pin_state_t state);
aw9523b_pin_mode_t aw9523b_pin_get_mode(aw9523b_device_t *dev, aw9523b_pin_t pin);
void aw9523b_pin_set_mode(aw9523b_device_t *dev, aw9523b_pin_t pin, aw9523b_pin_mode_t mode);

void aw9523b_pin_set_drive(aw9523b_device_t *dev, aw9523b_pin_t pin, uint8_t drive);
uint8_t aw9523b_pin_get_drive(aw9523b_device_t *dev, aw9523b_pin_t pin);

#endif // _AW9523B_H_
Loading
Loading