diff --git a/.gitignore b/.gitignore index 7113aed..42bfd6f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ cmake-build/ +ex/ diff --git a/bsp/rp2040/i2c_tinyusb.c b/bsp/rp2040/i2c_tinyusb.c index 155188d..378276c 100644 --- a/bsp/rp2040/i2c_tinyusb.c +++ b/bsp/rp2040/i2c_tinyusb.c @@ -1,4 +1,6 @@ +#include + #include #include #include @@ -10,337 +12,340 @@ #include "pinout.h" #include "i2ctinyusb.h" -//static int delay = 10, delay2 = 5; -// -//// I2C bitbang reimpl because ugh, synopsys -//// (mostly inspired by original I2CTinyUSB AVR firmware) -//__attribute__((__always_inline__)) inline static void i2cio_set_sda(bool hi) { -// if (hi) { -// sio_hw->gpio_oe_clr = (1< pullup configured, so it'll go high -// } else { -// sio_hw->gpio_oe_set = (1<gpio_clr = (1<gpio_in & (1<gpio_oe_set = (1<gpio_set = (1<gpio_clr = (1<= 0; --i) { -// i2cio_set_sda((v & (1<= 0; --i) { -// i2cio_set_sda((v & (1<= 0; --i) { -// i2cio_set_scl(true); -// bool c = i2cio_get_sda(); -// rv <<= 1; -// if (c) rv |= 1; -// i2cio_set_scl(false); -// } -// -// if (last) i2cio_set_sda(true); -// else i2cio_set_sda(false); -// -// i2cio_scl_toggle(); -// i2cio_set_sda(true); -//} -// -//// replicating/rewriting some SDK functions because they don't do what I want -//// so I'm making better ones -// -//static int __no_inline_not_in_flash_func(i2cex_probe_address)(uint16_t addr, bool a10bit) { -// // I2C pins to SIO -// gpio_set_function(PINOUT_I2C_SCL, GPIO_FUNC_SIO); -// gpio_set_function(PINOUT_I2C_SDA, GPIO_FUNC_SIO); -// -// int rv; -// i2cio_start(); -// -// if (a10bit) { -// // A10 magic higher 2 addr bits r/#w bit -// uint8_t addr1 = 0x70 | (((addr >> 8) & 3) << 1) | 0, -// addr2 = addr & 0xff; -// -// if (i2cio_write7(addr1)) { -// if (i2cio_write8(addr2)) rv = 0; -// else rv = PICO_ERROR_GENERIC; -// } else rv = PICO_ERROR_GENERIC; -// } else { -// if (i2cio_write8((addr << 1) & 0xff)) rv = 0; // acked: ok -// else rv = PICO_ERROR_GENERIC; // nak :/ -// } -// i2cio_stop(); -// -// // I2C back to I2C -// gpio_set_function(PINOUT_I2C_SCL, GPIO_FUNC_I2C); -// gpio_set_function(PINOUT_I2C_SDA, GPIO_FUNC_I2C); -// -// return rv; -//} -// -//static void i2cex_abort_xfer(i2c_inst_t* i2c) { -// // now do the abort -// i2c->hw->enable = 1 /*| (1<<2)*/ | (1<<1); -// // wait for M_TX_ABRT irq -// do { -// /*if (timeout_check) { -// timeout = timeout_check(ts); -// abort |= timeout; -// }*/ -// tight_loop_contents(); -// } while (/*!timeout &&*/ !(i2c->hw->raw_intr_stat & I2C_IC_RAW_INTR_STAT_TX_ABRT_BITS)); -// // reset irq -// //if (!timeout) -// (void)i2c->hw->clr_tx_abrt; -//} -// -//static int i2cex_write_blocking_until(i2c_inst_t* i2c, uint16_t addr, bool a10bit, -// const uint8_t* src, size_t len, bool nostop, absolute_time_t until) { -// timeout_state_t ts_; -// struct timeout_state* ts = &ts_; -// check_timeout_fn timeout_check = init_single_timeout_until(&ts_, until); -// -// if ((int)len < 0) return PICO_ERROR_GENERIC; -// if (a10bit) { // addr too high -// if (addr & ~(uint16_t)((1<<10)-1)) return PICO_ERROR_GENERIC; -// } else if (addr & 0x80) -// return PICO_ERROR_GENERIC; -// -// if (len == 0) return i2cex_probe_address(addr, a10bit); -// -// bool abort = false, timeout = false; -// uint32_t abort_reason = 0; -// int byte_ctr; -// -// i2c->hw->enable = 0; -// // enable 10bit mode if requested -// hw_write_masked(&i2c->hw->con, I2C_IC_CON_IC_10BITADDR_MASTER_BITS, (a10bit -// ? I2C_IC_CON_IC_10BITADDR_MASTER_VALUE_ADDR_10BITS -// : I2C_IC_CON_IC_10BITADDR_MASTER_VALUE_ADDR_7BITS ) << I2C_IC_CON_IC_10BITADDR_MASTER_LSB); -// i2c->hw->tar = addr; -// i2c->hw->enable = 1; -// -// for (byte_ctr = 0; byte_ctr < (int)len; ++byte_ctr) { -// bool first = byte_ctr == 0, -// last = byte_ctr == (int)len - 1; -// -// i2c->hw->data_cmd = -// bool_to_bit(first && i2c->restart_on_next) << I2C_IC_DATA_CMD_RESTART_LSB | -// bool_to_bit(last && !nostop) << I2C_IC_DATA_CMD_STOP_LSB | -// *src++; -// -// do { -// if (timeout_check) { -// timeout = timeout_check(ts); -// abort |= timeout; -// } -// tight_loop_contents(); -// } while (!timeout && !(i2c->hw->raw_intr_stat & I2C_IC_RAW_INTR_STAT_TX_EMPTY_BITS)); -// -// if (!timeout) { -// abort_reason = i2c->hw->tx_abrt_source; -// if (abort_reason) { -// (void)i2c->hw->clr_tx_abrt; -// abort = true; -// } -// -// if (abort || (last && !nostop)) { -// do { -// if (timeout_check) { -// timeout = timeout_check(ts); -// abort |= timeout; -// } -// tight_loop_contents(); -// } while (!timeout && !(i2c->hw->raw_intr_stat & I2C_IC_RAW_INTR_STAT_STOP_DET_BITS)); -// -// if (!timeout) (void)i2c->hw->clr_stop_det; -// else -// // if we had a timeout, send an abort request to the hardware, -// // so that the bus gets released -// i2cex_abort_xfer(i2c); -// } -// } else i2cex_abort_xfer(i2c); -// -// if (abort) break; -// } -// -// int rval; -// -// if (abort) { -// const int addr_noack = I2C_IC_TX_ABRT_SOURCE_ABRT_7B_ADDR_NOACK_BITS -// | I2C_IC_TX_ABRT_SOURCE_ABRT_10ADDR1_NOACK_BITS -// | I2C_IC_TX_ABRT_SOURCE_ABRT_10ADDR2_NOACK_BITS; -// -// if (timeout) rval = PICO_ERROR_TIMEOUT; -// else if (!abort_reason || (abort_reason & addr_noack)) -// rval = PICO_ERROR_GENERIC; -// else if (abort_reason & I2C_IC_TX_ABRT_SOURCE_ABRT_TXDATA_NOACK_BITS) -// rval = byte_ctr; -// else rval = PICO_ERROR_GENERIC; -// } else rval = byte_ctr; -// -// i2c->restart_on_next = nostop; -// return rval; -//} -//static int i2cex_read_blocking_until(i2c_inst_t* i2c, uint16_t addr, bool a10bit, -// uint8_t* dst, size_t len, bool nostop, absolute_time_t until) { -// timeout_state_t ts_; -// struct timeout_state* ts = &ts_; -// check_timeout_fn timeout_check = init_single_timeout_until(&ts_, until); -// -// if ((int)len < 0) return PICO_ERROR_GENERIC; -// if (a10bit) { // addr too high -// if (addr & ~(uint16_t)((1<<10)-1)) return PICO_ERROR_GENERIC; -// } else if (addr & 0x80) -// return PICO_ERROR_GENERIC; -// -// i2c->hw->enable = 0; -// // enable 10bit mode if requested -// hw_write_masked(&i2c->hw->con, I2C_IC_CON_IC_10BITADDR_MASTER_BITS, (a10bit -// ? I2C_IC_CON_IC_10BITADDR_MASTER_VALUE_ADDR_10BITS -// : I2C_IC_CON_IC_10BITADDR_MASTER_VALUE_ADDR_7BITS ) << I2C_IC_CON_IC_10BITADDR_MASTER_LSB); -// i2c->hw->tar = addr; -// i2c->hw->enable = 1; -// -// if (len == 0) return i2cex_probe_address(addr, a10bit); -// -// bool abort = false, timeout = false; -// uint32_t abort_reason = 0; -// int byte_ctr; -// -// for (byte_ctr = 0; byte_ctr < (int)len; ++byte_ctr) { -// bool first = byte_ctr == 0; -// bool last = byte_ctr == (int)len - 1; -// -// while (!i2c_get_write_available(i2c) && !abort) { -// tight_loop_contents(); -// // ? -// if (timeout_check) { -// timeout = timeout_check(ts); -// abort |= timeout; -// } -// } -// -// if (timeout) { -// // if we had a timeout, send an abort request to the hardware, -// // so that the bus gets released -// i2cex_abort_xfer(i2c); -// } -// if (abort) break; -// -// i2c->hw->data_cmd = -// bool_to_bit(first && i2c->restart_on_next) << I2C_IC_DATA_CMD_RESTART_LSB | -// bool_to_bit(last && !nostop) << I2C_IC_DATA_CMD_STOP_LSB | -// I2C_IC_DATA_CMD_CMD_BITS; // -> 1 for read -// -// do { -// abort_reason = i2c->hw->tx_abrt_source; -// abort = (bool)i2c->hw->clr_tx_abrt; -// -// if (timeout_check) { -// timeout = timeout_check(ts); -// abort |= timeout; -// } -// tight_loop_contents(); // ? -// } while (!abort && !i2c_get_read_available(i2c)); -// -// if (timeout) { -// // if we had a timeout, send an abort request to the hardware, -// // so that the bus gets released -// i2cex_abort_xfer(i2c); -// } -// if (abort) break; -// -// *dst++ = (uint8_t)i2c->hw->data_cmd; -// } -// -// int rval; -// -// if (abort) { -// const int addr_noack = I2C_IC_TX_ABRT_SOURCE_ABRT_7B_ADDR_NOACK_BITS -// | I2C_IC_TX_ABRT_SOURCE_ABRT_10ADDR1_NOACK_BITS -// | I2C_IC_TX_ABRT_SOURCE_ABRT_10ADDR2_NOACK_BITS; -// -// if (timeout) rval = PICO_ERROR_TIMEOUT; -// else if (!abort_reason || (abort_reason & addr_noack)) -// rval = PICO_ERROR_GENERIC; -// else rval = PICO_ERROR_GENERIC; -// } else rval = byte_ctr; -// -// i2c->restart_on_next = nostop; -// return rval; -//} -//static inline int i2cex_write_timeout_us(i2c_inst_t* i2c, uint16_t addr, bool a10bit, -// const uint8_t* src, size_t len, bool nostop, uint32_t timeout_us) { -// absolute_time_t t = make_timeout_time_us(timeout_us); -// return i2cex_write_blocking_until(i2c, addr, a10bit, src, len, nostop, t); -//} -//static inline int i2cex_read_timeout_us(i2c_inst_t* i2c, uint16_t addr, bool a10bit, -// uint8_t* dst, size_t len, bool nostop, uint32_t timeout_us) { -// absolute_time_t t = make_timeout_time_us(timeout_us); -// return i2cex_read_blocking_until(i2c, addr, a10bit, dst, len, nostop, t); -//} +static int delay = 10, delay2 = 5; + +// I2C bitbang reimpl because ugh, synopsys +// (mostly inspired by original I2CTinyUSB AVR firmware) +__attribute__((__always_inline__)) inline static void i2cio_set_sda(bool hi) { + if (hi) { + sio_hw->gpio_oe_clr = (1< pullup configured, so it'll go high + } else { + sio_hw->gpio_oe_set = (1<gpio_clr = (1<gpio_in & (1<gpio_oe_set = (1<gpio_set = (1<gpio_clr = (1<= 0; --i) { + i2cio_set_sda((v & (1<= 0; --i) { + i2cio_set_sda((v & (1<= 0; --i) { + i2cio_set_scl(true); + bool c = i2cio_get_sda(); + rv <<= 1; + if (c) rv |= 1; + i2cio_set_scl(false); + } + + if (last) i2cio_set_sda(true); + else i2cio_set_sda(false); + + i2cio_scl_toggle(); + i2cio_set_sda(true); +} + +// replicating/rewriting some SDK functions because they don't do what I want +// so I'm making better ones + +static int __no_inline_not_in_flash_func(i2cex_probe_address)(uint16_t addr, bool a10bit) { + // I2C pins to SIO + gpio_set_function(PINOUT_I2C_SCL, GPIO_FUNC_SIO); + gpio_set_function(PINOUT_I2C_SDA, GPIO_FUNC_SIO); + + int rv; + i2cio_start(); + + if (a10bit) { + // A10 magic higher 2 addr bits r/#w bit + uint8_t addr1 = 0x70 | (((addr >> 8) & 3) << 1) | 0, + addr2 = addr & 0xff; + + if (i2cio_write7(addr1)) { + if (i2cio_write8(addr2)) rv = 0; + else rv = PICO_ERROR_GENERIC; + } else rv = PICO_ERROR_GENERIC; + } else { + if (i2cio_write8((addr << 1) & 0xff)) rv = 0; // acked: ok + else rv = PICO_ERROR_GENERIC; // nak :/ + } + i2cio_stop(); + + // I2C back to I2C + gpio_set_function(PINOUT_I2C_SCL, GPIO_FUNC_I2C); + gpio_set_function(PINOUT_I2C_SDA, GPIO_FUNC_I2C); + + return rv; +} + +static void i2cex_abort_xfer(i2c_inst_t* i2c) { + // now do the abort + i2c->hw->enable = 1 /*| (1<<2)*/ | (1<<1); + // wait for M_TX_ABRT irq + do { + /*if (timeout_check) { + timeout = timeout_check(ts); + abort |= timeout; + }*/ + tight_loop_contents(); + } while (/*!timeout &&*/ !(i2c->hw->raw_intr_stat & I2C_IC_RAW_INTR_STAT_TX_ABRT_BITS)); + // reset irq + //if (!timeout) + (void)i2c->hw->clr_tx_abrt; +} + +static int i2cex_write_blocking_until(i2c_inst_t* i2c, uint16_t addr, bool a10bit, + const uint8_t* src, size_t len, bool nostop, absolute_time_t until) { + timeout_state_t ts_; + struct timeout_state* ts = &ts_; + check_timeout_fn timeout_check = init_single_timeout_until(&ts_, until); + + if ((int)len < 0) return PICO_ERROR_GENERIC; + if (a10bit) { // addr too high + if (addr & ~(uint16_t)((1<<10)-1)) return PICO_ERROR_GENERIC; + } else if (addr & 0x80) + return PICO_ERROR_GENERIC; + + if (len == 0) return i2cex_probe_address(addr, a10bit); + + bool abort = false, timeout = false; + uint32_t abort_reason = 0; + int byte_ctr; + + i2c->hw->enable = 0; + // enable 10bit mode if requested + hw_write_masked(&i2c->hw->con, I2C_IC_CON_IC_10BITADDR_MASTER_BITS, (a10bit + ? I2C_IC_CON_IC_10BITADDR_MASTER_VALUE_ADDR_10BITS + : I2C_IC_CON_IC_10BITADDR_MASTER_VALUE_ADDR_7BITS ) << I2C_IC_CON_IC_10BITADDR_MASTER_LSB); + i2c->hw->tar = addr; + i2c->hw->enable = 1; + + for (byte_ctr = 0; byte_ctr < (int)len; ++byte_ctr) { + bool first = byte_ctr == 0, + last = byte_ctr == (int)len - 1; + + i2c->hw->data_cmd = + bool_to_bit(first && i2c->restart_on_next) << I2C_IC_DATA_CMD_RESTART_LSB | + bool_to_bit(last && !nostop) << I2C_IC_DATA_CMD_STOP_LSB | + *src++; + + do { + if (timeout_check) { + timeout = timeout_check(ts); + abort |= timeout; + } + tight_loop_contents(); + } while (!timeout && !(i2c->hw->raw_intr_stat & I2C_IC_RAW_INTR_STAT_TX_EMPTY_BITS)); + + if (!timeout) { + abort_reason = i2c->hw->tx_abrt_source; + if (abort_reason) { + (void)i2c->hw->clr_tx_abrt; + abort = true; + } + + if (abort || (last && !nostop)) { + do { + if (timeout_check) { + timeout = timeout_check(ts); + abort |= timeout; + } + tight_loop_contents(); + } while (!timeout && !(i2c->hw->raw_intr_stat & I2C_IC_RAW_INTR_STAT_STOP_DET_BITS)); + + if (!timeout) (void)i2c->hw->clr_stop_det; + else + // if we had a timeout, send an abort request to the hardware, + // so that the bus gets released + i2cex_abort_xfer(i2c); + } + } else i2cex_abort_xfer(i2c); + + if (abort) break; + } + + int rval; + + if (abort) { + const int addr_noack = I2C_IC_TX_ABRT_SOURCE_ABRT_7B_ADDR_NOACK_BITS + | I2C_IC_TX_ABRT_SOURCE_ABRT_10ADDR1_NOACK_BITS + | I2C_IC_TX_ABRT_SOURCE_ABRT_10ADDR2_NOACK_BITS; + + if (timeout) rval = PICO_ERROR_TIMEOUT; + else if (!abort_reason || (abort_reason & addr_noack)) + rval = PICO_ERROR_GENERIC; + else if (abort_reason & I2C_IC_TX_ABRT_SOURCE_ABRT_TXDATA_NOACK_BITS) + rval = byte_ctr; + else rval = PICO_ERROR_GENERIC; + } else rval = byte_ctr; + + i2c->restart_on_next = nostop; + return rval; +} +static int i2cex_read_blocking_until(i2c_inst_t* i2c, uint16_t addr, bool a10bit, + uint8_t* dst, size_t len, bool nostop, absolute_time_t until) { + timeout_state_t ts_; + struct timeout_state* ts = &ts_; + check_timeout_fn timeout_check = init_single_timeout_until(&ts_, until); + + if ((int)len < 0) return PICO_ERROR_GENERIC; + if (a10bit) { // addr too high + if (addr & ~(uint16_t)((1<<10)-1)) return PICO_ERROR_GENERIC; + } else if (addr & 0x80) + return PICO_ERROR_GENERIC; + + i2c->hw->enable = 0; + // enable 10bit mode if requested + hw_write_masked(&i2c->hw->con, I2C_IC_CON_IC_10BITADDR_MASTER_BITS, (a10bit + ? I2C_IC_CON_IC_10BITADDR_MASTER_VALUE_ADDR_10BITS + : I2C_IC_CON_IC_10BITADDR_MASTER_VALUE_ADDR_7BITS ) << I2C_IC_CON_IC_10BITADDR_MASTER_LSB); + i2c->hw->tar = addr; + i2c->hw->enable = 1; + + if (len == 0) return i2cex_probe_address(addr, a10bit); + + bool abort = false, timeout = false; + uint32_t abort_reason = 0; + int byte_ctr; + + for (byte_ctr = 0; byte_ctr < (int)len; ++byte_ctr) { + bool first = byte_ctr == 0; + bool last = byte_ctr == (int)len - 1; + + while (!i2c_get_write_available(i2c) && !abort) { + tight_loop_contents(); + // ? + if (timeout_check) { + timeout = timeout_check(ts); + abort |= timeout; + } + } + + if (timeout) { + // if we had a timeout, send an abort request to the hardware, + // so that the bus gets released + i2cex_abort_xfer(i2c); + } + if (abort) break; + + i2c->hw->data_cmd = + bool_to_bit(first && i2c->restart_on_next) << I2C_IC_DATA_CMD_RESTART_LSB | + bool_to_bit(last && !nostop) << I2C_IC_DATA_CMD_STOP_LSB | + I2C_IC_DATA_CMD_CMD_BITS; // -> 1 for read + + do { + abort_reason = i2c->hw->tx_abrt_source; + abort = (bool)i2c->hw->clr_tx_abrt; + + if (timeout_check) { + timeout = timeout_check(ts); + abort |= timeout; + } + tight_loop_contents(); // ? + } while (!abort && !i2c_get_read_available(i2c)); + + if (timeout) { + // if we had a timeout, send an abort request to the hardware, + // so that the bus gets released + i2cex_abort_xfer(i2c); + } + if (abort) break; + + uint8_t v = (uint8_t)i2c->hw->data_cmd; + printf("\ngot read %02x\n", v); + *dst++ = v; + } + + int rval; + + if (abort) { + printf("\ngot abrt: "); + const int addr_noack = I2C_IC_TX_ABRT_SOURCE_ABRT_7B_ADDR_NOACK_BITS + | I2C_IC_TX_ABRT_SOURCE_ABRT_10ADDR1_NOACK_BITS + | I2C_IC_TX_ABRT_SOURCE_ABRT_10ADDR2_NOACK_BITS; + + if (timeout) { printf("timeout\n"); rval = PICO_ERROR_TIMEOUT; } + else if (!abort_reason || (abort_reason & addr_noack)) {printf("disconn\n"); + rval = PICO_ERROR_GENERIC; } + else {printf("unk\n"); rval = PICO_ERROR_GENERIC;} + } else rval = byte_ctr; + + i2c->restart_on_next = nostop; + return rval; +} +static inline int i2cex_write_timeout_us(i2c_inst_t* i2c, uint16_t addr, bool a10bit, + const uint8_t* src, size_t len, bool nostop, uint32_t timeout_us) { + absolute_time_t t = make_timeout_time_us(timeout_us); + return i2cex_write_blocking_until(i2c, addr, a10bit, src, len, nostop, t); +} +static inline int i2cex_read_timeout_us(i2c_inst_t* i2c, uint16_t addr, bool a10bit, + uint8_t* dst, size_t len, bool nostop, uint32_t timeout_us) { + absolute_time_t t = make_timeout_time_us(timeout_us); + return i2cex_read_blocking_until(i2c, addr, a10bit, dst, len, nostop, t); +} __attribute__((__const__)) enum ki2c_funcs i2ctu_get_func(void) { @@ -352,7 +357,7 @@ enum ki2c_funcs i2ctu_get_func(void) { void i2ctu_init(void) { // default to 100 kHz (SDK example default so should be ok) - //delay = 10; delay2 = 5; + delay = 10; delay2 = 5; i2c_init(PINOUT_I2C_DEV, 100*1000); gpio_set_function(PINOUT_I2C_SCL, GPIO_FUNC_I2C); @@ -364,24 +369,25 @@ void i2ctu_init(void) { } uint32_t i2ctu_set_freq(uint32_t freq, uint32_t us) { - //delay = us; - //delay2 = us >> 1; - //if (!delay2) delay2 = 1; + delay = us; + delay2 = us >> 1; + if (!delay2) delay2 = 1; return i2c_set_baudrate(PINOUT_I2C_DEV, freq); } +// TODO: FIX START AND STOP COND HANDLING enum itu_status i2ctu_write(enum ki2c_flags flags, enum itu_command startstopflags, uint16_t addr, const uint8_t* buf, size_t len) { if (len == 0) { // do a read, that's less hazardous uint8_t stuff = 0; - int rv = i2c_read_timeout_us(PINOUT_I2C_DEV, addr/*&0x7f*/, /*false,*/ &stuff, 1, + int rv = i2cex_read_timeout_us(PINOUT_I2C_DEV, addr, false, &stuff, 1, !(startstopflags & ITU_CMD_I2C_IO_END), 1000*1000); if (rv < 0) return ITU_STATUS_ADDR_NAK; return ITU_STATUS_ADDR_ACK; } else { - int rv = i2c_write_timeout_us(PINOUT_I2C_DEV, addr, /*false,*/ buf, len, + int rv = i2cex_write_timeout_us(PINOUT_I2C_DEV, addr, false, buf, len, !(startstopflags & ITU_CMD_I2C_IO_END), 1000*1000); if (rv < 0 || (size_t)rv < len) return ITU_STATUS_ADDR_NAK; return ITU_STATUS_ADDR_ACK; @@ -391,13 +397,14 @@ enum itu_status i2ctu_read(enum ki2c_flags flags, enum itu_command startstopflag uint16_t addr, uint8_t* buf, size_t len) { if (len == 0) { uint8_t stuff = 0; - int rv = i2c_read_timeout_us(PINOUT_I2C_DEV, addr, /*false,*/ &stuff, 1, + int rv = i2cex_read_timeout_us(PINOUT_I2C_DEV, addr, false, &stuff, 1, !(startstopflags & ITU_CMD_I2C_IO_END), 1000*1000); if (rv < 0) return ITU_STATUS_ADDR_NAK; return ITU_STATUS_ADDR_ACK; } else { - int rv = i2c_read_timeout_us(PINOUT_I2C_DEV, addr, /*false,*/ buf, len, + int rv = i2cex_read_timeout_us(PINOUT_I2C_DEV, addr, false, buf, len, !(startstopflags & ITU_CMD_I2C_IO_END), 1000*1000); + printf("p le rv=%d buf=%02x ", rv, buf[0]); if (rv < 0 || (size_t)rv < len) return ITU_STATUS_ADDR_NAK; return ITU_STATUS_ADDR_ACK; } diff --git a/bsp/rp2040/protocfg.h b/bsp/rp2040/protocfg.h index 692c551..6c4f207 100644 --- a/bsp/rp2040/protocfg.h +++ b/bsp/rp2040/protocfg.h @@ -20,6 +20,7 @@ #define USB_VID 0xcafe /* TinyUSB */ /*#define USB_VID 0x1209*/ /* Generic */ /*#define USB_VID 0x1d50*/ /* OpenMoko */ +#define USB_PID 0x1312 // TODO: other RP2040 boards #define INFO_BOARDNAME "RP2040 Pico" diff --git a/bsp/stm32f072disco/protocfg.h b/bsp/stm32f072disco/protocfg.h index fa3de2f..f14ecc1 100644 --- a/bsp/stm32f072disco/protocfg.h +++ b/bsp/stm32f072disco/protocfg.h @@ -10,6 +10,7 @@ #define USB_VID 0xcafe /* TinyUSB */ /*#define USB_VID 0x1209*/ /* Generic */ /*#define USB_VID 0x1d50*/ /* OpenMoko */ +#define USB_PID 0x1312 #define INFO_BOARDNAME "STM32F072 Disco" diff --git a/i2c-tiny-usb-misc/i2c-tiny-usb.c b/i2c-tiny-usb-misc/i2c-tiny-usb.c index b978e38..9bfab3e 100644 --- a/i2c-tiny-usb-misc/i2c-tiny-usb.c +++ b/i2c-tiny-usb-misc/i2c-tiny-usb.c @@ -160,7 +160,12 @@ static const struct i2c_algorithm usb_algorithm = { static const struct usb_device_id i2c_tiny_usb_table[] = { { USB_DEVICE(0x0403, 0xc631) }, /* FTDI */ { USB_DEVICE(0x1c40, 0x0534) }, /* EZPrototypes */ - { USB_DEVICE_INTERFACE_CLASS(0xcafe, 0x6043, 0/*255*/) }, /* TinyUSB DapperMime: we want the Vendor interface */ + { /* TinyUSB DapperMime: we want the Vendor interface on I2C-enabled ones */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION | USB_DEVICE_ID_MATCH_INT_CLASS, + .idVendor = 0xcafe, .idProduct = 0x1312, + .bcdDevice_lo = 0x6000, .bcdDevice_hi = 0x6fff, + .bInterfaceClass = 0 + }, { } /* Terminating entry */ }; diff --git a/src/usb_descriptors.c b/src/usb_descriptors.c index 026de40..fb9e4f3 100644 --- a/src/usb_descriptors.c +++ b/src/usb_descriptors.c @@ -34,12 +34,12 @@ * [MSB] HID | MSC | CDC [LSB] */ #ifdef DBOARD_HAS_I2C -#define USB_PID_BASE 0x6000 +#define USB_BCD_BASE 0x6000 #else -#define USB_PID_BASE 0x4000 +#define USB_BCD_BASE 0x4000 #endif #define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) ) -#define USB_PID (USB_PID_BASE | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 3) | _PID_MAP(HID, 6) | \ +#define USB_BCD (USB_BCD_BASE | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 3) | _PID_MAP(HID, 6) | \ _PID_MAP(MIDI, 9) | _PID_MAP(VENDOR, 12) ) \ @@ -73,7 +73,7 @@ tusb_desc_device_t const desc_device = { .idVendor = USB_VID, .idProduct = USB_PID, - .bcdDevice = 0x0101, // TODO + .bcdDevice = USB_BCD, .iManufacturer = STRID_MANUFACTURER, .iProduct = STRID_PRODUCT, @@ -110,14 +110,24 @@ uint8_t const * tud_hid_descriptor_report_cb(uint8_t instance) { //--------------------------------------------------------------------+ enum { +#ifdef DBOARD_HAS_I2C + ITF_NUM_VND_I2CTINYUSB, +#endif +#ifdef DBOARD_HAS_CMSISDAP ITF_NUM_HID_CMSISDAP, +#endif +#ifdef DBOARD_HAS_UART ITF_NUM_CDC_UART_COM, ITF_NUM_CDC_UART_DATA, +#endif +#ifdef DBOARD_HAS_SERPROG ITF_NUM_CDC_SERPROG_COM, ITF_NUM_CDC_SERPROG_DATA, +#endif +#ifdef USE_USBCDC_FOR_STDIO ITF_NUM_CDC_STDIO_COM, ITF_NUM_CDC_STDIO_DATA, - ITF_NUM_VND_I2CTINYUSB, +#endif ITF_NUM_TOTAL }; diff --git a/src/vnd_i2ctinyusb.c b/src/vnd_i2ctinyusb.c index 5330a28..fb83687 100644 --- a/src/vnd_i2ctinyusb.c +++ b/src/vnd_i2ctinyusb.c @@ -121,15 +121,23 @@ static bool iub_ctl_req(uint8_t rhport, uint8_t stage, tusb_control_request_t co // does it also get split up into buffers of eg. 64 bytes? uint8_t buf[cmd.len]; + printf("flags=%04x\n", cmd.flags); if (cmd.flags & I2C_M_RD) { // read from I2C device + printf("read addr=%04hx len=%04hx ", cmd.addr, cmd.len); state = i2ctu_read(cmd.flags, cmd.cmd & ITU_CMD_I2C_IO_DIR_MASK, cmd.addr, buf, sizeof buf); + printf("data=%02x %02x...\n", buf[0], buf[1]); return tud_control_xfer(rhport, req, buf, cmd.len); } else { // write + printf("write addr=%04hx len=%04hx ", cmd.addr, cmd.len); bool rv = tud_control_xfer(rhport, req, buf, cmd.len); if (rv) { + printf("data=%02x %02x...\n", buf[0], buf[1]); state = i2ctu_write(cmd.flags, cmd.cmd & ITU_CMD_I2C_IO_DIR_MASK, cmd.addr, buf, sizeof buf); + } else { + printf("no data :/\n"); + state = ITU_STATUS_ADDR_NAK; } return rv; }