i2c-tiny-usb works!
This commit is contained in:
parent
ff45c13498
commit
df797cbeb4
|
@ -33,8 +33,8 @@ if(FAMILY STREQUAL "rp2040")
|
|||
family_initialize_project(PROJECT ${CMAKE_CURRENT_LIST_DIR}) # calls pico_sdk_init()
|
||||
#pico_sdk_init()
|
||||
|
||||
pico_set_program_name(PROJECT "${PROJECT}")
|
||||
pico_set_program_version(PROJECT "0.1")
|
||||
#pico_set_program_name(${PROJECT} "${PROJECT}")
|
||||
#pico_set_program_version(${PROJECT} "0.1")
|
||||
|
||||
add_executable(${PROJECT})
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ These microcontrollers support the following protocols:
|
|||
|
||||
| MCU | SWD | JTAG | UART | SPI (flashrom) | I2C | Other stuff |
|
||||
|:------ |:---:|:----:|:----:|:-------------- |:--- |:--------------- |
|
||||
| RP2040 | X | X | X | X | WIP | Planned |
|
||||
| RP2040 | X | X | X | X | X | Planned |
|
||||
| STM32F072B Discovery | X | | | | | |
|
||||
|
||||
The [original repository](https://github.com/majbthrd/DapperMime/) (Dapper
|
||||
|
@ -164,10 +164,10 @@ libco is licensed under the [ISC license](https://opensource.org/licenses/ISC)
|
|||
separate mode that temporarily disables all other IO protocols
|
||||
- [x] UART with CTS/RTS flow control
|
||||
- [x] Needs configurable stuff as well, as some UART interfaces won't use this.
|
||||
- [ ] Second UART port for when stdio UART is disabled?
|
||||
- [x] Debug interface to send printf stuff directly to USB, instead of having
|
||||
to use the UART interface as a loopback thing.
|
||||
- [ ] I2C support by emulating the I2C Tiny USB
|
||||
- [ ] Second UART port for when stdio UART is disabled?
|
||||
- [x] I2C support by emulating the I2C Tiny USB
|
||||
- [ ] Expose RP2040-internal temperature ADC on I2C-over-USB bus?
|
||||
- ~~Does SMBus stuff need special treatment here?~~ ~~No.~~ Actually, some
|
||||
parts do, but, laziness.
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
/*#define DBOARD_HAS_SERPROG*/
|
||||
/*#define DBOARD_HAS_TINYI2C*/
|
||||
|
||||
#define CFG_TUD_CDC 0
|
||||
#define CFG_TUD_HID 0
|
||||
#define CFG_TUD_VENDOR 0
|
||||
|
||||
#define INFO_BOARDNAME "unknown"
|
||||
|
||||
#endif
|
||||
|
|
|
@ -377,33 +377,40 @@ uint32_t i2ctu_set_freq(uint32_t freq, uint32_t us) {
|
|||
}
|
||||
|
||||
// TODO: FIX START AND STOP COND HANDLING. MAYBE. BUG IN vnd_i2ctinyusb.c MORE SERIOUS
|
||||
// ALSO TODO: i2cex routines seem to mess with the I2C bus when a timeout (=> abort) happens?
|
||||
enum itu_status i2ctu_write(enum ki2c_flags flags, enum itu_command startstopflags,
|
||||
uint16_t addr, const uint8_t* buf, size_t len) {
|
||||
bool nostop = !(startstopflags & ITU_CMD_I2C_IO_END);
|
||||
printf("nostop=%c ", nostop?'t':'f');
|
||||
|
||||
if (len == 0) {
|
||||
// do a read, that's less hazardous
|
||||
uint8_t stuff = 0;
|
||||
int rv = i2cex_read_timeout_us(PINOUT_I2C_DEV, addr, false, &stuff, 1,
|
||||
!(startstopflags & ITU_CMD_I2C_IO_END), 1000*1000);
|
||||
int rv = i2c_read_timeout_us(PINOUT_I2C_DEV, addr, /*false,*/ &stuff, 1,
|
||||
nostop, 1000*1000);
|
||||
if (rv < 0) return ITU_STATUS_ADDR_NAK;
|
||||
return ITU_STATUS_ADDR_ACK;
|
||||
} else {
|
||||
int rv = i2cex_write_timeout_us(PINOUT_I2C_DEV, addr, false, buf, len,
|
||||
!(startstopflags & ITU_CMD_I2C_IO_END), 1000*1000);
|
||||
int rv = i2c_write_timeout_us(PINOUT_I2C_DEV, addr, /*false,*/ buf, len,
|
||||
nostop, 1000*1000);
|
||||
if (rv < 0 || (size_t)rv < len) return ITU_STATUS_ADDR_NAK;
|
||||
return ITU_STATUS_ADDR_ACK;
|
||||
}
|
||||
}
|
||||
enum itu_status i2ctu_read(enum ki2c_flags flags, enum itu_command startstopflags,
|
||||
uint16_t addr, uint8_t* buf, size_t len) {
|
||||
bool nostop = !(startstopflags & ITU_CMD_I2C_IO_END);
|
||||
printf("nostop=%c ", nostop?'t':'f');
|
||||
|
||||
if (len == 0) {
|
||||
uint8_t stuff = 0;
|
||||
int rv = i2cex_read_timeout_us(PINOUT_I2C_DEV, addr, false, &stuff, 1,
|
||||
!(startstopflags & ITU_CMD_I2C_IO_END), 1000*1000);
|
||||
int rv = i2c_read_timeout_us(PINOUT_I2C_DEV, addr, /*false,*/ &stuff, 1,
|
||||
nostop, 1000*1000);
|
||||
if (rv < 0) return ITU_STATUS_ADDR_NAK;
|
||||
return ITU_STATUS_ADDR_ACK;
|
||||
} else {
|
||||
int rv = i2cex_read_timeout_us(PINOUT_I2C_DEV, addr, false, buf, len,
|
||||
!(startstopflags & ITU_CMD_I2C_IO_END), 1000*1000);
|
||||
int rv = i2c_read_timeout_us(PINOUT_I2C_DEV, addr, /*false,*/ buf, len,
|
||||
nostop, 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;
|
||||
|
|
|
@ -7,15 +7,32 @@
|
|||
#define DBOARD_HAS_SERPROG
|
||||
#define DBOARD_HAS_I2C
|
||||
|
||||
#define HID_N_CMSISDAP 0
|
||||
#define CDC_N_UART 0
|
||||
#define CDC_N_SERPROG 1
|
||||
#define VND_N_I2CTINYUSB 0
|
||||
enum {
|
||||
HID_N_CMSISDAP = 0,
|
||||
|
||||
HID_N__NITF
|
||||
};
|
||||
enum {
|
||||
CDC_N_UART = 0,
|
||||
CDC_N_SERPROG,
|
||||
#ifdef USE_USBCDC_FOR_STDIO
|
||||
#define CDC_N_STDIO 2
|
||||
CDC_N_STDIO,
|
||||
#endif
|
||||
|
||||
CDC_N__NITF
|
||||
};
|
||||
enum {
|
||||
VND_N__NITF = 0
|
||||
};
|
||||
|
||||
#define CFG_TUD_HID 1
|
||||
#ifdef USE_USBCDC_FOR_STDIO
|
||||
#define CFG_TUD_CDC 3
|
||||
#else
|
||||
#define CFG_TUD_CDC 2
|
||||
#endif
|
||||
#define CFG_TUD_VENDOR 0
|
||||
|
||||
/*#define USB_VID 0x2e8a*/ /* Raspberry Pi */
|
||||
#define USB_VID 0xcafe /* TinyUSB */
|
||||
/*#define USB_VID 0x1209*/ /* Generic */
|
||||
|
|
|
@ -7,6 +7,22 @@
|
|||
/*#define DBOARD_HAS_SERPROG*/
|
||||
/*#define DBOARD_HAS_TINYI2C*/
|
||||
|
||||
enum {
|
||||
HID_N_CMSISDAP = 0,
|
||||
|
||||
HID_N__NITF
|
||||
};
|
||||
enum {
|
||||
CDC_N__NITF
|
||||
};
|
||||
enum {
|
||||
VND_N__NITF = 0
|
||||
};
|
||||
|
||||
#define CFG_TUD_HID 1
|
||||
#define CFG_TUD_CDC 0
|
||||
#define CFG_TUD_VENDOR 0
|
||||
|
||||
#define USB_VID 0xcafe /* TinyUSB */
|
||||
/*#define USB_VID 0x1209*/ /* Generic */
|
||||
/*#define USB_VID 0x1d50*/ /* OpenMoko */
|
||||
|
|
|
@ -84,11 +84,12 @@ enum ki2c_funcs {
|
|||
I2C_FUNC_SMBUS_BLOCK_PROC_CALL),
|
||||
};
|
||||
|
||||
__attribute__((__packed__))
|
||||
struct itu_cmd {
|
||||
uint8_t cmd;
|
||||
uint16_t flags;
|
||||
uint16_t addr;
|
||||
uint16_t len;
|
||||
uint8_t cmd;
|
||||
};
|
||||
|
||||
#ifdef DBOARD_HAS_I2C
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "protocfg.h"
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// COMMON CONFIGURATION
|
||||
//--------------------------------------------------------------------
|
||||
|
@ -98,17 +100,10 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
//------------- CLASS -------------//
|
||||
#ifdef USE_USBCDC_FOR_STDIO
|
||||
#define CFG_TUD_CDC 3
|
||||
#else
|
||||
#define CFG_TUD_CDC 2
|
||||
#endif
|
||||
|
||||
#define CFG_TUD_MSC 0
|
||||
#define CFG_TUD_HID 1
|
||||
#define CFG_TUD_MIDI 0
|
||||
#define CFG_TUD_VENDOR 0
|
||||
#define CFG_TUD_NET 0
|
||||
// see also: bsp/<family>/protocfg.h
|
||||
|
||||
#define CFG_TUD_HID_EP_BUFSIZE 64
|
||||
|
||||
|
|
|
@ -20,6 +20,9 @@ static uint8_t itf_num;
|
|||
static enum itu_status status;
|
||||
static struct itu_cmd curcmd;
|
||||
|
||||
static uint8_t rxbuf[128];
|
||||
static uint8_t txbuf[128];
|
||||
|
||||
static void iub_init(void) {
|
||||
status = ITU_STATUS_IDLE;
|
||||
memset(&curcmd, 0, sizeof curcmd);
|
||||
|
@ -51,41 +54,32 @@ static uint16_t iub_open(uint8_t rhport, tusb_desc_interface_t const* itf_desc,
|
|||
}
|
||||
|
||||
static bool iub_ctl_req(uint8_t rhport, uint8_t stage, tusb_control_request_t const* req) {
|
||||
// if (stage == CONTROL_STAGE_DATA && req->bmRequestType_bit.type == TUSB_REQ_TYPE_VENDOR) {
|
||||
// // TODO: should URB_CONTROL out data be read in this stage????
|
||||
// // FIXME: cond ^ has false-positives!
|
||||
// // FIXME: handle 0-byte writes in SETUP stage
|
||||
// // FIXME: use curcmd var for eliminating false-positives
|
||||
// // FIXME: other stuff???
|
||||
// if (req->bRequest >= ITU_CMD_I2C_IO && req->bRequest <= ITU_CMD_I2C_IO_BEGINEND
|
||||
// /*&& curcmd.cmd == req->bRequest && curcmd.flags == req->wValue
|
||||
// && curcmd.addr == req->wIndex && curcmd.len == req->wLength*/) {
|
||||
// uint8_t buf[req->wLength];
|
||||
// bool rv = tud_control_xfer(rhport, req, buf, req->wLength);
|
||||
// printf("write addr=%04hx len=%04hx ", req->wIndex, req->wLength);
|
||||
// if (rv) {
|
||||
// printf("data=%02x %02x...\n", buf[0], buf[1]);
|
||||
// status = i2ctu_write(req->wValue, req->bRequest & ITU_CMD_I2C_IO_DIR_MASK,
|
||||
// req->wIndex, buf, sizeof buf);
|
||||
// } else {
|
||||
// printf("no data :/\n");
|
||||
// status = ITU_STATUS_ADDR_NAK;
|
||||
// }
|
||||
// return rv;
|
||||
// } else {
|
||||
// //printf("I2C-Tiny-USB: bad command in DATA stage\n");
|
||||
// //return false;
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
static char* stages[]={"SETUP","DATA","ACK"};
|
||||
static char* types[]={"STD","CLS","VND","INV"};
|
||||
|
||||
if (stage != CONTROL_STAGE_SETUP) return true;
|
||||
/*printf("ctl req stage=%s rt=%s, wIndex=%04x, bReq=%02x, wValue=%04x wLength=%04x\n",
|
||||
stages[stage], types[req->bmRequestType_bit.type],
|
||||
req->wIndex, req->bRequest, req->wValue, req->wLength);*/
|
||||
|
||||
/*printf("ctl req rhport=%02x, stage=%02x, wIndex=%04x, bReq=%02x, wValue=%04x\n",
|
||||
rhport, stage,
|
||||
req->wIndex, req->bRequest, req->wValue);*/
|
||||
if (req->bmRequestType_bit.type != TUSB_REQ_TYPE_VENDOR) return true;
|
||||
|
||||
if (req->bmRequestType_bit.type == TUSB_REQ_TYPE_VENDOR) {
|
||||
if (stage == CONTROL_STAGE_DATA) {
|
||||
struct itu_cmd cmd = curcmd;
|
||||
|
||||
if (req->bRequest >= ITU_CMD_I2C_IO && req->bRequest <= ITU_CMD_I2C_IO_BEGINEND
|
||||
&& cmd.cmd == req->bRequest && cmd.flags == req->wValue
|
||||
&& cmd.addr == req->wIndex && cmd.len == req->wLength) {
|
||||
printf("WDATA a=%04hx l=%04hx ", cmd.addr, cmd.len);
|
||||
|
||||
printf("data=%02x %02x...\n", rxbuf[0], rxbuf[1]);
|
||||
status = i2ctu_write(cmd.flags, cmd.cmd & ITU_CMD_I2C_IO_DIR_MASK,
|
||||
cmd.addr, rxbuf, cmd.len > sizeof rxbuf ? sizeof rxbuf : cmd.len);
|
||||
|
||||
// cancel curcmd
|
||||
curcmd.cmd = 0xff;
|
||||
}
|
||||
return true;
|
||||
} else if (stage == CONTROL_STAGE_SETUP) {
|
||||
switch (req->bRequest) {
|
||||
case ITU_CMD_ECHO: { // flags to be echoed back, addr unused, len=2
|
||||
if (req->wLength != 2) return false; // bad length -> let's stall
|
||||
|
@ -100,12 +94,11 @@ static bool iub_ctl_req(uint8_t rhport, uint8_t stage, tusb_control_request_t co
|
|||
if (req->wLength != 4) return false;
|
||||
|
||||
const uint32_t func = i2ctu_get_func();
|
||||
uint8_t rv[4];
|
||||
rv[0]=func&0xff;
|
||||
rv[1]=(func>>8)&0xff;
|
||||
rv[2]=(func>>16)&0xff;
|
||||
rv[3]=(func>>24)&0xff;
|
||||
return tud_control_xfer(rhport, req, rv, sizeof rv);
|
||||
txbuf[0]=func&0xff;
|
||||
txbuf[1]=(func>>8)&0xff;
|
||||
txbuf[2]=(func>>16)&0xff;
|
||||
txbuf[3]=(func>>24)&0xff;
|
||||
return tud_control_xfer(rhport, req, txbuf, 4);
|
||||
}
|
||||
break;
|
||||
case ITU_CMD_SET_DELAY: { // flags=delay, addr unused, len=0
|
||||
|
@ -132,50 +125,42 @@ static bool iub_ctl_req(uint8_t rhport, uint8_t stage, tusb_control_request_t co
|
|||
case ITU_CMD_I2C_IO_BEGIN: // addr: I2C address
|
||||
case ITU_CMD_I2C_IO_END: // len: transfer size
|
||||
case ITU_CMD_I2C_IO_BEGINEND: { // (transfer dir is in flags)
|
||||
/*struct itu_cmd cmd;
|
||||
cmd.cmd = req->bRequest;
|
||||
struct itu_cmd cmd;
|
||||
cmd.flags = req->wValue;
|
||||
cmd.addr = req->wIndex;
|
||||
cmd.len = req->wLength;
|
||||
curcmd = cmd;*/
|
||||
cmd.cmd = req->bRequest;
|
||||
|
||||
// TODO: what's the max value of wLength? does this need
|
||||
// to be handled separately in the data stage as well?
|
||||
// will the entire thing be read into one big chunk, or
|
||||
// does it also get split up into buffers of eg. 64 bytes?
|
||||
uint8_t buf[req->wLength];
|
||||
|
||||
//printf("flags=%04x\n", req->wValue);
|
||||
if (req->wValue & I2C_M_RD) { // read from I2C device
|
||||
printf("read addr=%04hx len=%04hx ", req->wIndex, req->wLength);
|
||||
status = i2ctu_read(req->wValue, req->bRequest & ITU_CMD_I2C_IO_DIR_MASK,
|
||||
req->wIndex, buf, sizeof buf);
|
||||
printf("data=%02x %02x...\n", buf[0], buf[1]);
|
||||
return tud_control_xfer(rhport, req, buf, req->wLength);
|
||||
if (cmd.flags & I2C_M_RD) { // read from I2C device
|
||||
printf("read addr=%04hx len=%04hx ", cmd.addr, cmd.len);
|
||||
status = i2ctu_read(cmd.flags, cmd.cmd & ITU_CMD_I2C_IO_DIR_MASK,
|
||||
cmd.addr, txbuf, cmd.len);
|
||||
printf("data=%02x %02x...\n", txbuf[0], txbuf[1]);
|
||||
return tud_control_xfer(rhport, req, txbuf,
|
||||
cmd.len > sizeof txbuf ? sizeof txbuf : cmd.len);
|
||||
} else { // write
|
||||
return true; // handled in DATA stage
|
||||
/*// FIXME: THIS NO WORKY! STUFF IN BUFFER IS NONSENSE
|
||||
bool rv = tud_control_xfer(rhport, req, buf, req->wLength);
|
||||
if (rv) {
|
||||
printf("data=%02x %02x...\n", buf[0], buf[1]);
|
||||
status = i2ctu_write(req->wValue, req->bRequest & ITU_CMD_I2C_IO_DIR_MASK,
|
||||
req->wIndex, buf, sizeof buf);
|
||||
printf("write addr=%04hx len=%04hx ", cmd.addr, cmd.len);
|
||||
if (cmd.len == 0) { // address probe -> do this here
|
||||
uint8_t bleh = 0;
|
||||
status = i2ctu_write(cmd.flags, cmd.cmd & ITU_CMD_I2C_IO_DIR_MASK,
|
||||
cmd.addr, &bleh, 0);
|
||||
printf("probe -> %d\n", status);
|
||||
return tud_control_status(rhport, req);
|
||||
} else {
|
||||
printf("no data :/\n");
|
||||
status = ITU_STATUS_ADDR_NAK;
|
||||
// handled in DATA stage!
|
||||
curcmd = cmd;
|
||||
bool rv = tud_control_xfer(rhport, req, rxbuf,
|
||||
cmd.len > sizeof rxbuf ? sizeof rxbuf : cmd.len);
|
||||
return rv;
|
||||
}
|
||||
return rv;*/
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printf("I2C-Tiny-USB: unknown command %02x\n", req->bRequest);
|
||||
return false; // unknown!
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
printf("I2C-Tiny-USB: bad request type %02x\n", req->bmRequestType);
|
||||
return false; // not a vendor command? no clue what to do with it!
|
||||
}
|
||||
} else return true; // other stage...
|
||||
}
|
||||
|
||||
// never actually called fsr
|
||||
|
|
Loading…
Reference in New Issue