Skip to content

Commit

Permalink
Merge branch 'Klipper3d:master' into STEVAL3DP001V1_work
Browse files Browse the repository at this point in the history
  • Loading branch information
h-oussama authored Jan 12, 2022
2 parents 45c7911 + babb067 commit 78941d2
Show file tree
Hide file tree
Showing 6 changed files with 231 additions and 2 deletions.
2 changes: 1 addition & 1 deletion docs/Config_Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -2560,7 +2560,7 @@ pin:
# Neopixel is connected to the pin).
#color_order: GRB
# Set the pixel order required by the LED hardware. Options are GRB,
# RGB, GRBW, or RGBW. The default is GRB.
# RGB, BRG, GRBW, or RGBW. The default is GRB.
#initial_RED: 0.0
#initial_GREEN: 0.0
#initial_BLUE: 0.0
Expand Down
4 changes: 3 additions & 1 deletion klippy/extras/neopixel.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def __init__(self, config):
self.oid = self.mcu.create_oid()
self.pin = pin_params['pin']
self.mcu.register_config_callback(self.build_config)
formats = {v: v for v in ["RGB", "GRB", "RGBW", "GRBW"]}
formats = {v: v for v in ["RGB", "GRB", "BRG", "RGBW", "GRBW"]}
self.color_order = config.getchoice("color_order", formats, "GRB")
elem_size = len(self.color_order)
self.chain_count = config.getint('chain_count', 1, minval=1,
Expand Down Expand Up @@ -67,6 +67,8 @@ def update_color_data(self, red, green, blue, white, index=None):
color_data = [green, red, blue]
elif self.color_order == "RGB":
color_data = [red, green, blue]
elif self.color_order == "BRG":
color_data = [blue, red, green]
elif self.color_order == "GRBW":
color_data = [green, red, blue, white]
else:
Expand Down
1 change: 1 addition & 0 deletions src/rp2040/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ config RP2040_SELECT
select HAVE_GPIO
select HAVE_GPIO_ADC
select HAVE_GPIO_SPI
select HAVE_GPIO_I2C
select HAVE_GPIO_BITBANGING
select HAVE_STRICT_TIMING
select HAVE_CHIPID
Expand Down
1 change: 1 addition & 0 deletions src/rp2040/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ src-$(CONFIG_USBSERIAL) += rp2040/chipid.c
src-$(CONFIG_SERIAL) += rp2040/serial.c generic/serial_irq.c
src-$(CONFIG_HAVE_GPIO_HARD_PWM) += rp2040/hard_pwm.c
src-$(CONFIG_HAVE_GPIO_SPI) += rp2040/spi.c
src-$(CONFIG_HAVE_GPIO_I2C) += rp2040/i2c.c

# rp2040 stage2 building
$(OUT)stage2.o: lib/rp2040/boot_stage2/boot2_w25q080.S
Expand Down
10 changes: 10 additions & 0 deletions src/rp2040/gpio.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,14 @@ void spi_prepare(struct spi_config config);
void spi_transfer(struct spi_config config, uint8_t receive_data
, uint8_t len, uint8_t *data);

struct i2c_config {
void *i2c;
uint8_t addr;
};

struct i2c_config i2c_setup(uint32_t bus, uint32_t rate, uint8_t addr);
void i2c_write(struct i2c_config config, uint8_t write_len, uint8_t *write);
void i2c_read(struct i2c_config config, uint8_t reg_len, uint8_t *reg
, uint8_t read_len, uint8_t *read);

#endif // gpio.h
215 changes: 215 additions & 0 deletions src/rp2040/i2c.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
// I2C functions for rp2040
//
// Copyright (C) 2022 Lasse Dalegaard <[email protected]>
//
// This file may be distributed under the terms of the GNU GPLv3 license.

#include "board/misc.h" // timer_is_before
#include "gpio.h" // i2c_setup, i2c_read, i2c_write
#include "command.h" // shutdown
#include "sched.h" // sched_shutdown
#include "internal.h" // pclock, gpio_peripheral
#include "hardware/regs/resets.h" // RESETS_RESET_I2C*_BITS
#include "hardware/structs/i2c.h"

struct i2c_info {
i2c_hw_t *i2c;
uint8_t sda_pin, scl_pin, pclk;
};

DECL_ENUMERATION("i2c_bus", "i2c0a", 0);
DECL_ENUMERATION("i2c_bus", "i2c0b", 1);
DECL_ENUMERATION("i2c_bus", "i2c0c", 2);
DECL_ENUMERATION("i2c_bus", "i2c0d", 3);
DECL_ENUMERATION("i2c_bus", "i2c0e", 4);
DECL_ENUMERATION("i2c_bus", "i2c0f", 5);
DECL_ENUMERATION("i2c_bus", "i2c0g", 6);
DECL_ENUMERATION("i2c_bus", "i2c0h", 7);
DECL_ENUMERATION("i2c_bus", "i2c1a", 8);
DECL_ENUMERATION("i2c_bus", "i2c1b", 9);
DECL_ENUMERATION("i2c_bus", "i2c1c", 10);
DECL_ENUMERATION("i2c_bus", "i2c1d", 11);
DECL_ENUMERATION("i2c_bus", "i2c1e", 12);
DECL_ENUMERATION("i2c_bus", "i2c1f", 13);
DECL_ENUMERATION("i2c_bus", "i2c1g", 14);
DECL_CONSTANT_STR("BUS_PINS_i2c0a", "gpio0,gpio1");
DECL_CONSTANT_STR("BUS_PINS_i2c0b", "gpio4,gpio5");
DECL_CONSTANT_STR("BUS_PINS_i2c0c", "gpio8,gpio9");
DECL_CONSTANT_STR("BUS_PINS_i2c0d", "gpio12,gpio13");
DECL_CONSTANT_STR("BUS_PINS_i2c0e", "gpio16,gpio17");
DECL_CONSTANT_STR("BUS_PINS_i2c0f", "gpio20,gpio21");
DECL_CONSTANT_STR("BUS_PINS_i2c0g", "gpio24,gpio25");
DECL_CONSTANT_STR("BUS_PINS_i2c0h", "gpio28,gpio29");
DECL_CONSTANT_STR("BUS_PINS_i2c1a", "gpio2,gpio3");
DECL_CONSTANT_STR("BUS_PINS_i2c1b", "gpio6,gpio7");
DECL_CONSTANT_STR("BUS_PINS_i2c1c", "gpio10,gpio11");
DECL_CONSTANT_STR("BUS_PINS_i2c1d", "gpio14,gpio15");
DECL_CONSTANT_STR("BUS_PINS_i2c1e", "gpio18,gpio19");
DECL_CONSTANT_STR("BUS_PINS_i2c1f", "gpio22,gpio23");
DECL_CONSTANT_STR("BUS_PINS_i2c1g", "gpio26,gpio27");

static const struct i2c_info i2c_bus[] = {
{ i2c0_hw, 0, 1, RESETS_RESET_I2C0_BITS },
{ i2c0_hw, 4, 5, RESETS_RESET_I2C0_BITS },
{ i2c0_hw, 8, 9, RESETS_RESET_I2C0_BITS },
{ i2c0_hw, 12, 13, RESETS_RESET_I2C0_BITS },
{ i2c0_hw, 16, 17, RESETS_RESET_I2C0_BITS },
{ i2c0_hw, 20, 21, RESETS_RESET_I2C0_BITS },
{ i2c0_hw, 24, 25, RESETS_RESET_I2C0_BITS },
{ i2c0_hw, 28, 29, RESETS_RESET_I2C0_BITS },

{ i2c1_hw, 2, 3, RESETS_RESET_I2C1_BITS },
{ i2c1_hw, 6, 7, RESETS_RESET_I2C1_BITS },
{ i2c1_hw, 10, 11, RESETS_RESET_I2C1_BITS },
{ i2c1_hw, 14, 15, RESETS_RESET_I2C1_BITS },
{ i2c1_hw, 18, 19, RESETS_RESET_I2C1_BITS },
{ i2c1_hw, 22, 23, RESETS_RESET_I2C1_BITS },
{ i2c1_hw, 26, 27, RESETS_RESET_I2C1_BITS },
};

struct i2c_config
i2c_setup(uint32_t bus, uint32_t rate, uint8_t addr)
{
if (bus > ARRAY_SIZE(i2c_bus))
shutdown("Invalid i2c bus");

const struct i2c_info *info = &i2c_bus[bus];

gpio_peripheral(info->sda_pin, 3, 0);
gpio_peripheral(info->scl_pin, 3, 0);

if (!is_enabled_pclock(info->pclk)) {
enable_pclock(info->pclk);

i2c_hw_t *i2c = info->i2c;

i2c->enable = 0;

// We set up the bus in 400 kHz mode, but then set timings afterwards
// to match either 100k or 400k mode. This simplifies the setup.

i2c->con = I2C_IC_CON_SPEED_VALUE_FAST << I2C_IC_CON_SPEED_LSB
| I2C_IC_CON_MASTER_MODE_BITS
| I2C_IC_CON_IC_SLAVE_DISABLE_BITS
| I2C_IC_CON_IC_RESTART_EN_BITS;

i2c->tx_tl = 0;
i2c->rx_tl = 0;

uint32_t pclk = get_pclock_frequency(info->pclk);

// See `i2c_set_baudrate` in the Pico SDK `hardware_i2c/i2c.c` file
// for details on the calculations here.
if (rate > 1000000)
rate = 1000000; // Clamp the rate to 1Mbps
uint32_t period = (pclk + rate / 2) / rate;
uint32_t lcnt = period * 3 / 5;
uint32_t hcnt = period - lcnt;
uint32_t sda_tx_hold_count = ((pclk * 3) / 10000000) + 1;

i2c->fs_scl_hcnt = hcnt;
i2c->fs_scl_lcnt = lcnt;
i2c->fs_spklen = lcnt < 16 ? 1 : lcnt / 16;
hw_write_masked(&i2c->sda_hold,
sda_tx_hold_count << I2C_IC_SDA_HOLD_IC_SDA_TX_HOLD_LSB,
I2C_IC_SDA_HOLD_IC_SDA_TX_HOLD_BITS);
}

return (struct i2c_config){ .i2c=info->i2c, .addr=addr };
}

static void
i2c_start(i2c_hw_t *i2c, uint8_t addr)
{
i2c->enable = 0;
i2c->tar = addr;
i2c->enable = 1;
}

static void
i2c_stop(i2c_hw_t *i2c)
{
i2c->enable = 0;
}

static void
i2c_do_write(i2c_hw_t *i2c, uint8_t addr, uint8_t write_len, uint8_t *write
, uint8_t send_stop, uint32_t timeout)
{
for (int i = 0; i < write_len; i++) {
int first = i == 0;
int last = send_stop && (i == write_len - 1);

// Wait until there's a spot in the TX FIFO
while (i2c->txflr == 16) {
if (!timer_is_before(timer_read_time(), timeout))
shutdown("i2c timeout");
}

i2c->data_cmd = first << I2C_IC_DATA_CMD_RESTART_LSB
| last << I2C_IC_DATA_CMD_STOP_LSB
| write[i];
}

if (!send_stop)
return;

// Drain the transmit buffer
while (i2c->txflr != 0) {
if (!timer_is_before(timer_read_time(), timeout))
shutdown("i2c timeout");
}
}

static void
i2c_do_read(i2c_hw_t *i2c, uint8_t addr, uint8_t read_len, uint8_t *read
, uint32_t timeout)
{
int have_read = 0;
int to_send = read_len;
while (have_read < read_len) {
if (!timer_is_before(timer_read_time(), timeout))
shutdown("i2c timeout");

if (to_send > 0 && i2c->txflr < 16) {
int first = to_send == read_len;
int last = to_send == 1;

// Put a read command in the TX FIFO
i2c->data_cmd = first << I2C_IC_DATA_CMD_RESTART_LSB
| last << I2C_IC_DATA_CMD_STOP_LSB
| I2C_IC_DATA_CMD_CMD_BITS;
to_send--;
}

if (have_read < read_len && i2c->rxflr > 0) {
*read++ = i2c->data_cmd & 0xFF;
have_read++;
}
}
}

void
i2c_write(struct i2c_config config, uint8_t write_len, uint8_t *write)
{
i2c_hw_t *i2c = (i2c_hw_t*)config.i2c;
uint32_t timeout = timer_read_time() + timer_from_us(5000);

i2c_start(i2c, config.addr);
i2c_do_write(i2c, config.addr, write_len, write, 1, timeout);
i2c_stop(i2c);
}

void
i2c_read(struct i2c_config config, uint8_t reg_len, uint8_t *reg
, uint8_t read_len, uint8_t *read)
{
i2c_hw_t *i2c = (i2c_hw_t*)config.i2c;
uint32_t timeout = timer_read_time() + timer_from_us(5000);

i2c_start(i2c, config.addr);
if (reg_len != 0)
i2c_do_write(i2c, config.addr, reg_len, reg, 0, timeout);
i2c_do_read(i2c, config.addr, read_len, read, timeout);
i2c_stop(i2c);
}

0 comments on commit 78941d2

Please sign in to comment.