vial-qmk/platforms/pico/drivers/i2c_master.c
JohSchneider 973c4588d7
pico: i2c: align code with chibios, avr, documentation (#217)
some defines and function signatures did not quite match the
documented ones - which lead to compile issues while building the same
code that uses an i2c-driver based vial-qmk/driver for multiple
platforms

Signed-off-by: Johannes Schneider <johschneider@googlemail.com>

Co-authored-by: Johannes Schneider <johannes.schneider@leica-geosystems.com>
2022-08-04 05:01:03 -06:00

111 lines
3 KiB
C

#include "quantum.h"
#include "i2c_master.h"
#undef i2c_init
#include <string.h>
#include "pico/binary_info.h"
#include "hardware/i2c.h"
#ifndef I2C1_SCL_PIN
# define I2C1_SCL_PIN 3
#endif
#ifndef I2C1_SDA_PIN
# define I2C1_SDA_PIN 2
#endif
#ifndef I2C_DRIVER
# define I2C_DRIVER i2c1
#endif
static uint8_t i2c_address;
static i2c_status_t pico_status_to_qmk(int res) {
if (res == PICO_ERROR_GENERIC) {
return I2C_STATUS_ERROR;
} else if (res == PICO_ERROR_TIMEOUT) {
return I2C_STATUS_TIMEOUT;
} else {
return I2C_STATUS_SUCCESS;
}
}
void i2c_init_pico(void) {
static bool is_initialised = false;
if (!is_initialised) {
is_initialised = true;
i2c_init(I2C_DRIVER, 50 * 1000);
gpio_set_function(I2C1_SCL_PIN, GPIO_FUNC_I2C);
gpio_set_function(I2C1_SDA_PIN, GPIO_FUNC_I2C);
gpio_pull_up(I2C1_SCL_PIN);
gpio_pull_up(I2C1_SDA_PIN);
// Make the I2C pins available to picotool
bi_decl(bi_2pins_with_func(I2C1_SDA_PIN, I2C1_SCL_PIN, GPIO_FUNC_I2C));
}
}
i2c_status_t i2c_start(uint8_t address, uint16_t timeout) {
i2c_address = address;
return I2C_STATUS_SUCCESS;
}
i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length,
uint16_t timeout) {
i2c_address = address;
int res = i2c_write_timeout_us(I2C_DRIVER, i2c_address >> 1, data, length,
true, timeout * 1000);
return pico_status_to_qmk(res);
}
i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length,
uint16_t timeout) {
i2c_address = address;
int res = i2c_read_timeout_us(I2C_DRIVER, i2c_address >> 1, data, length,
true, timeout * 1000);
return pico_status_to_qmk(res);
}
i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data,
uint16_t length, uint16_t timeout) {
i2c_address = devaddr;
uint8_t complete_packet[length + 1];
for (uint8_t i = 0; i < length; i++) {
complete_packet[i + 1] = data[i];
}
complete_packet[0] = regaddr;
int res =
i2c_write_timeout_us(I2C_DRIVER, (i2c_address >> 1), complete_packet,
length + 1, true, timeout * 1000);
return pico_status_to_qmk(res);
}
i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data,
uint16_t length, uint16_t timeout) {
i2c_address = devaddr;
i2c_write_timeout_us(I2C_DRIVER, (i2c_address >> 1), &regaddr, 1, true,
timeout * 1000);
int res = i2c_read_timeout_us(I2C_DRIVER, i2c_address >> 1, data, length,
true, timeout * 1000);
return pico_status_to_qmk(res);
}
void i2c_stop(void) {
// Abort
I2C_DRIVER->hw->enable |= (1 << 1);
I2C_DRIVER->restart_on_next = false;
while (I2C_DRIVER->hw->enable & (1 << 1)) {
continue;
}
// clear abort bit
I2C_DRIVER->hw->clr_tx_abrt;
}