diff --git a/CMakeLists.txt b/CMakeLists.txt index a0477b4..9f0c9f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,9 @@ set(TOP "./tinyusb") get_filename_component(TOP "${TOP}" REALPATH) option(USE_SYSTEMWIDE_PICOSDK "Use the systemwide Pico SDK instead of relying on the one from a deeply nested Git submodule (OFF by default)" OFF) +# OPTION: PICO_NO_FLASH: load only into RAM (useful for testing) +# OPTION: PICO_COPY_TO_RAM: place the code/rodata into RAM at startup (while still stored in flash) +# TODO: add option for FAMILY and BOARD # Check for -DFAMILY= if(FAMILY STREQUAL "rp2040") @@ -25,6 +28,10 @@ if(FAMILY STREQUAL "rp2040") include(${TOP}/hw/bsp/${FAMILY}/family.cmake) + # need uart stdio, usb is busy doing other stuff + pico_enable_stdio_uart(${PROJECT} 1) + pico_enable_stdio_usb(${PROJECT} 0) + # Example source target_sources(${PROJECT} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/main.c @@ -35,6 +42,8 @@ if(FAMILY STREQUAL "rp2040") ${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Source/SWO.c ${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Source/SW_DP.c ${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/cdc_uart.c + ${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/spi_serprog.c + ${CMAKE_CURRENT_SOURCE_DIR}/cdc_serprog.c ) # Example include @@ -50,7 +59,8 @@ if(FAMILY STREQUAL "rp2040") target_compile_definitions(${PROJECT} PUBLIC ) - target_link_libraries(${PROJECT} pico_stdlib pico_fix_rp2040_usb_device_enumeration pico_unique_id) + target_link_libraries(${PROJECT} pico_stdlib pico_unique_id hardware_spi + pico_fix_rp2040_usb_device_enumeration) pico_add_extra_outputs(${PROJECT}) diff --git a/Makefile b/Makefile index ef97f38..67af816 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ INC += \ ./bsp/default \ $(TOP)/hw -APP_SOURCE += $(wildcard ./*.c) +APP_SOURCE += $(wildcard ./*.c) $(wildcard ./bsp/$(BOARD)/*.c) SRC_C += $(addprefix $(CURRENT_PATH)/, $(APP_SOURCE)) @@ -17,7 +17,6 @@ SRC_C += \ ./CMSIS_5/CMSIS/DAP/Firmware/Source/JTAG_DP.c \ ./CMSIS_5/CMSIS/DAP/Firmware/Source/DAP_vendor.c \ ./CMSIS_5/CMSIS/DAP/Firmware/Source/SWO.c \ - ./CMSIS_5/CMSIS/DAP/Firmware/Source/SW_DP.c \ - ./bsp/$(BOARD)/cdc_uart.c + ./CMSIS_5/CMSIS/DAP/Firmware/Source/SW_DP.c include ./tinyusb/examples/rules.mk diff --git a/README.md b/README.md index cb325f4..dd3f4ea 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,8 @@ The pin mapping for the RP2040 is as follows: The UART pins are for connecting to the device to be debugged, the data is echoed back over the USB CDC interface (typically a `/dev/ttyACMx` device on -Linux). +Linux). If you want to get stdio readout on your computer, connect GP0 to GP5, +and GP1 to GP4. In SWD mode, the pin mapping is entirely as with the standard Picoprobe setup, as described in Chapter 5 and Appendix A of [Getting Started with Raspberry Pi @@ -94,7 +95,23 @@ ARM's CMSIS_5 code is licensed under the [Apache 2.0 license](https://opensource ## TODO +- [x] CMSIS-DAP JTAG implementation - [ ] Flashrom/SPI support using Serprog +- [ ] UART with CTS/RTS flow control - [ ] 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? +- [ ] Maybe add some way of reconfiguring features while the device is running. + Eg. CTS/RTS enable/disable, temperature ADC I2C address, ... + - Maybe use the Serprog USB serial interface for this, with some extension + commands not typically used for Serprog. - [ ] AVR programming (USBavr emulation?) +- Renesas E7-{0,1,2} programming thing???? + - Renesas tell us how this works pls +- Maybe steal other features from the Bus Pirate or Glasgow or so + - 1-wire? Never seen this one in the wild + - MIDI? Feels mostly gimmicky... + - PS/2? Hmmmm idk + - HD44780 LCD? See MIDI + - CAN? If I'd first be able to find a CAN device to test it with, sure diff --git a/bsp/default/protocfg.h b/bsp/default/protocfg.h new file mode 100644 index 0000000..b04867f --- /dev/null +++ b/bsp/default/protocfg.h @@ -0,0 +1,11 @@ + +#ifndef PROTOCFG_H_ +#define PROTOCFG_H_ + +/*#define DBOARD_HAS_UART*/ +#define DBOARD_HAS_CMSISDAP +/*#define DBOARD_HAS_SERPROG*/ +/*#define DBOARD_HAS_TINYI2C*/ + +#endif + diff --git a/bsp/rp2040/DAP_config.h b/bsp/rp2040/DAP_config.h index 321609f..5a3329b 100644 --- a/bsp/rp2040/DAP_config.h +++ b/bsp/rp2040/DAP_config.h @@ -57,6 +57,7 @@ This information includes: #include #include #include +#include #include "picoprobe_config.h" @@ -559,6 +560,17 @@ __STATIC_INLINE void DAP_SETUP (void) { hw_write_masked(&padsbank0_hw->io[PICOPROBE_LED], 0, PADS_BANK0_GPIO0_IE_BITS | PADS_BANK0_GPIO0_OD_BITS); iobank0_hw->io[PICOPROBE_LED].ctrl = GPIO_FUNC_SIO << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB; + + bi_decl(bi_2pins_with_names( + PROBE_PIN_JTAG_TCK, "TCK / SWCLK", + PROBE_PIN_JTAG_TMS, "TMS / SWDIO" + )); + bi_decl(bi_4pins_with_names( + PROBE_PIN_JTAG_TDI , "TDI", + PROBE_PIN_JTAG_TDO , "TDO", + PROBE_PIN_JTAG_nTRST , "nTRST", + PROBE_PIN_JTAG_nRESET, "nRESET" + )); } /** Reset Target Device with custom specific I/O pin or command sequence. diff --git a/bsp/rp2040/cdc_uart.c b/bsp/rp2040/cdc_uart.c index 3963246..a8d9fa9 100644 --- a/bsp/rp2040/cdc_uart.c +++ b/bsp/rp2040/cdc_uart.c @@ -24,39 +24,49 @@ */ #include +#include #include "tusb.h" #include "picoprobe_config.h" +#include "protocfg.h" +#include "protos.h" + +// declare these so other CDC interfaces can use the same buffers, decreasing +// overall memory usage. however, this means the contents of these buffers +// can't be relied upon to persist between two cdc_*_task() calls +extern uint8_t rx_buf[CFG_TUD_CDC_RX_BUFSIZE]; +extern uint8_t tx_buf[CFG_TUD_CDC_TX_BUFSIZE]; +__attribute__((__weak__)) uint8_t rx_buf[CFG_TUD_CDC_RX_BUFSIZE]; +__attribute__((__weak__)) uint8_t tx_buf[CFG_TUD_CDC_TX_BUFSIZE]; void cdc_uart_init(void) { gpio_set_function(PICOPROBE_UART_TX, GPIO_FUNC_UART); gpio_set_function(PICOPROBE_UART_RX, GPIO_FUNC_UART); uart_init(PICOPROBE_UART_INTERFACE, PICOPROBE_UART_BAUDRATE); + + bi_decl(bi_2pins_with_func(PICOPROBE_UART_TX, PICOPROBE_UART_RX, GPIO_FUNC_UART)); } -void cdc_task(void) { - uint8_t rx_buf[CFG_TUD_CDC_RX_BUFSIZE]; - uint8_t tx_buf[CFG_TUD_CDC_TX_BUFSIZE]; - +void cdc_uart_task(void) { // Consume uart fifo regardless even if not connected uint rx_len = 0; - while(uart_is_readable(PICOPROBE_UART_INTERFACE) && (rx_len < sizeof(rx_buf))) { + while (uart_is_readable(PICOPROBE_UART_INTERFACE) && (rx_len < sizeof(rx_buf))) { rx_buf[rx_len++] = uart_getc(PICOPROBE_UART_INTERFACE); } - if (tud_cdc_connected()) { + if (tud_cdc_n_connected(CDC_N_UART)) { // Do we have anything to display on the host's terminal? if (rx_len) { for (uint i = 0; i < rx_len; i++) { - tud_cdc_write_char(rx_buf[i]); + tud_cdc_n_write_char(CDC_N_UART, rx_buf[i]); } - tud_cdc_write_flush(); + tud_cdc_n_write_flush(CDC_N_UART); } - if (tud_cdc_available()) { + if (tud_cdc_n_available(CDC_N_UART)) { // Is there any data from the host for us to tx - uint tx_len = tud_cdc_read(tx_buf, sizeof(tx_buf)); + uint tx_len = tud_cdc_n_read(CDC_N_UART, tx_buf, sizeof(tx_buf)); uart_write_blocking(PICOPROBE_UART_INTERFACE, tx_buf, tx_len); } } @@ -66,3 +76,4 @@ void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* line_coding) { picoprobe_info("New baud rate %d\n", line_coding->bit_rate); uart_init(PICOPROBE_UART_INTERFACE, line_coding->bit_rate); } + diff --git a/bsp/rp2040/picoprobe_config.h b/bsp/rp2040/picoprobe_config.h index 15c5274..47686d9 100644 --- a/bsp/rp2040/picoprobe_config.h +++ b/bsp/rp2040/picoprobe_config.h @@ -66,6 +66,13 @@ #define PROBE_PIN_JTAG_nTRST 8 #define PROBE_PIN_JTAG_nRESET 9 +// SPI config +#define PROBE_SPI_DEV spi1 +#define PROBE_SPI_SCLK 10 +#define PROBE_SPI_MOSI 11 +#define PROBE_SPI_MISO 12 +#define PROBE_SPI_nCS 13 + // LED config // you can change these two as you like diff --git a/bsp/rp2040/protocfg.h b/bsp/rp2040/protocfg.h new file mode 100644 index 0000000..d53d617 --- /dev/null +++ b/bsp/rp2040/protocfg.h @@ -0,0 +1,15 @@ + +#ifndef PROTOCFG_H_ +#define PROTOCFG_H_ + +#define DBOARD_HAS_UART +#define DBOARD_HAS_CMSISDAP +#define DBOARD_HAS_SERPROG +/*#define DBOARD_HAS_TINYI2C*/ + +#define HID_N_CMSISDAP 0 +#define CDC_N_UART 0 +#define CDC_N_SERPROG 1 + +#endif + diff --git a/bsp/rp2040/spi_serprog.c b/bsp/rp2040/spi_serprog.c new file mode 100644 index 0000000..b637d35 --- /dev/null +++ b/bsp/rp2040/spi_serprog.c @@ -0,0 +1,65 @@ + +#include + +#include +#include +#include + +#include "protocfg.h" +#include "protos.h" + +#include "serprog.h" + +#include "picoprobe_config.h" + +static bool cs_asserted; + +void sp_spi_init(void) { + printf("spi init!\n"); + + cs_asserted = false; + + spi_init(PROBE_SPI_DEV, 512*1000); // default to 512 kHz + + gpio_init(PROBE_SPI_nCS); + gpio_put(PROBE_SPI_nCS, 1); + gpio_set_dir(PROBE_SPI_nCS, GPIO_OUT); + + gpio_set_function(PROBE_SPI_MISO, GPIO_FUNC_SPI); + gpio_set_function(PROBE_SPI_MOSI, GPIO_FUNC_SPI); + gpio_set_function(PROBE_SPI_SCLK, GPIO_FUNC_SPI); + + bi_decl(bi_3pins_with_func(PROBE_SPI_MISO, PROBE_SPI_MOSI, PROBE_SPI_SCLK, GPIO_FUNC_SPI)); + bi_decl(bi_1pin_with_name(PROBE_SPI_nCS, "SPI #CS")); +} +uint32_t __not_in_flash_func(sp_spi_set_freq)(uint32_t freq_wanted) { + return spi_set_baudrate(PROBE_SPI_DEV, freq_wanted); +} +void __not_in_flash_func(sp_spi_cs_deselect)(void) { + asm volatile("nop\nnop\nnop"); // idk if this is needed + gpio_put(PROBE_SPI_nCS, 1); + asm volatile("nop\nnop\nnop"); // idk if this is needed + cs_asserted = false; +} +void __not_in_flash_func(sp_spi_cs_select)(void) { + asm volatile("nop\nnop\nnop"); // idk if this is needed + gpio_put(PROBE_SPI_nCS, 0); + asm volatile("nop\nnop\nnop"); // idk if this is needed + cs_asserted = true; +} + +void __not_in_flash_func(sp_spi_op_begin)(void) { + if (!cs_asserted) sp_spi_cs_select(); +} +void __not_in_flash_func(sp_spi_op_end)(void) { + if (cs_asserted) sp_spi_cs_deselect(); +} + +// TODO: use dma? +void __not_in_flash_func(sp_spi_op_write)(uint32_t write_len, const uint8_t* write_data) { + spi_write_blocking(PROBE_SPI_DEV, write_data, write_len); +} +void __not_in_flash_func(sp_spi_op_read)(uint32_t read_len, uint8_t* read_data) { + spi_read_blocking(PROBE_SPI_DEV, 0, read_data, read_len); +} + diff --git a/bsp/stm32f072disco/cdc_uart.c b/bsp/stm32f072disco/cdc_uart.c index fb9474f..6c8f495 100644 --- a/bsp/stm32f072disco/cdc_uart.c +++ b/bsp/stm32f072disco/cdc_uart.c @@ -2,6 +2,6 @@ void cdc_uart_init(void) { } -void cdc_task(void) +void cdc_uart_task(void) { } diff --git a/bsp/stm32f072disco/protocfg.h b/bsp/stm32f072disco/protocfg.h new file mode 100644 index 0000000..b04867f --- /dev/null +++ b/bsp/stm32f072disco/protocfg.h @@ -0,0 +1,11 @@ + +#ifndef PROTOCFG_H_ +#define PROTOCFG_H_ + +/*#define DBOARD_HAS_UART*/ +#define DBOARD_HAS_CMSISDAP +/*#define DBOARD_HAS_SERPROG*/ +/*#define DBOARD_HAS_TINYI2C*/ + +#endif + diff --git a/bsp/stm32f072disco/spi_serprog.c b/bsp/stm32f072disco/spi_serprog.c new file mode 100644 index 0000000..cf640e0 --- /dev/null +++ b/bsp/stm32f072disco/spi_serprog.c @@ -0,0 +1,17 @@ + +#include "serprog.h" + +void sp_spi_init(void) { +} +uint32_t sp_spi_set_freq(uint32_t freq_wanted) { + return 0; +} +void sp_spi_cs_deselect(void) { +} +void sp_spi_cs_select(void) { +} +void sp_spi_op_begin(void){} +void sp_spi_op_write(uint32_t write_len, uint8_t* write_data){} +void sp_spi_op_read(uint32_t read_len, const uint8_t* read_data){} +void sp_spi_op_end(void){} + diff --git a/cdc_serprog.c b/cdc_serprog.c new file mode 100644 index 0000000..636288b --- /dev/null +++ b/cdc_serprog.c @@ -0,0 +1,241 @@ +// vim: set et: + +#include + +#include "tusb.h" + +#include "protocfg.h" + +#ifdef DBOARD_HAS_SERPROG + +#include "protos.h" + +#include "serprog.h" + +// TODO: refactor some of this stuff into another header & split off serprog +// protocol handling from the SPI stuff. one thing we should think about +// when performing this refactor is, would other boards support +// parallell, LPC, or FWH, or only SPI? if only SPI, the entire proto +// handler can just be made reusable verbatim. + +// kinda refactored this already but it still has a good note for non-SPI stuff, +// so leaving it here for now + +static const uint8_t serprog_cmdmap[32] = { + 0x3f, // cmd 00..05 not 0x06 (Q_CHIPSIZE) and 0x07 (Q_OPBUF), as this is a SPI-only device + 0x01, // only cmd 08 + 0x1f, // cmd 10..15 supported + 0, // rest is 0 +}; +static const char serprog_pgmname[16] = { + 'D','a','p','p','e','r','M','i','m','e','-','J','T','A','G',0 // TODO +}; + +// declare these so other CDC interfaces can use the same buffers, decreasing +// overall memory usage. however, this means the contents of these buffers +// can't be relied upon to persist between two cdc_*_task() calls +extern uint8_t rx_buf[CFG_TUD_CDC_RX_BUFSIZE]; +extern uint8_t tx_buf[CFG_TUD_CDC_TX_BUFSIZE]; +__attribute__((__weak__)) uint8_t rx_buf[CFG_TUD_CDC_RX_BUFSIZE]; +__attribute__((__weak__)) uint8_t tx_buf[CFG_TUD_CDC_TX_BUFSIZE]; + +static uint32_t bufpos; + +void cdc_serprog_init(void) { + bufpos = 0; + + sp_spi_init(); +} + +static uint32_t serprog_handle_cmd(const uint8_t* buf, uint32_t nread) { + if (nread == 0) return 0; + + uint32_t nresp = 0, rv = 1; + + switch (buf[0]) { + case S_CMD_NOP: + printf("nop\n"); + tx_buf[0] = S_ACK; + nresp = 1; + break; + case S_CMD_SYNCNOP: + printf("syncnop\n"); + tx_buf[0] = S_NAK; + tx_buf[1] = S_ACK; + nresp = 2; + break; + case S_CMD_Q_IFACE: + printf("q_iface\n"); + tx_buf[0] = S_ACK; + tx_buf[1] = SERPROG_IFACE_VERSION & 0xff; + tx_buf[2] = (SERPROG_IFACE_VERSION >> 8) & 0xff; + nresp = 3; + break; + case S_CMD_Q_CMDMAP: + printf("q_cmdmap\n"); + tx_buf[0] = S_ACK; + memcpy(&tx_buf[1], serprog_cmdmap, sizeof serprog_cmdmap); + nresp = sizeof(serprog_cmdmap) + 1; + break; + case S_CMD_Q_PGMNAME: + printf("q_pgmname\n"); + tx_buf[0] = S_ACK; + memcpy(&tx_buf[1], serprog_pgmname, sizeof serprog_pgmname); + nresp = sizeof(serprog_pgmname) + 1; + break; + case S_CMD_Q_SERBUF: + printf("q_serbuf\n"); + tx_buf[0] = S_ACK; + tx_buf[1] = sizeof(rx_buf) & 0xff; + tx_buf[2] = (sizeof(rx_buf) >> 8) & 0xff; + nresp = 3; + break; + case S_CMD_Q_BUSTYPE: + printf("q_bustype\n"); + tx_buf[0] = S_ACK; + tx_buf[1] = 1<<3; // SPI only + nresp = 2; + break; + case S_CMD_Q_WRNMAXLEN: + printf("q_wrnmaxlen\n"); + tx_buf[0] = S_ACK; + tx_buf[1] = (sizeof(tx_buf)-1) & 0xff; + tx_buf[2] = ((sizeof(tx_buf)-1) >> 8) & 0xff; + nresp = 3; + break; + case S_CMD_Q_RDNMAXLEN: + printf("q_rdnmaxlen\n"); + tx_buf[0] = S_ACK; + tx_buf[1] = (sizeof(rx_buf)-1) & 0xff; + tx_buf[2] = ((sizeof(rx_buf)-1) >> 8) & 0xff; + nresp = 3; + break; + case S_CMD_S_BUSTYPE: + printf("s_bustype\n"); + if (nread < 2) return 0; // need more data + + if (buf[1] == (1<<3)) { + tx_buf[0] = S_ACK; + } else { + tx_buf[0] = S_NAK; + } + nresp = 1; + rv = 2; + break; + + case S_CMD_SPIOP: { + printf("spiop\n"); + if (nread < 7) return 0; // need more data + + uint32_t + slen = (uint32_t)buf[1] | ((uint32_t)buf[2] << 8) | ((uint32_t)buf[3]), + rlen = (uint32_t)buf[4] | ((uint32_t)buf[5] << 8) | ((uint32_t)buf[6]); + + if (7 + slen > sizeof(rx_buf) || 1 + rlen > sizeof(tx_buf)) { + // TODO: stream buffers in and out here for larger xfers + tx_buf[0] = S_NAK; + nresp = 1; + } else { + if (nread < 7 + slen) return 0; + + tx_buf[0] = S_ACK; + sp_spi_op_do(slen, &buf[7], rlen, &tx_buf[1]); + nresp = 7 + rlen; + rv = 7 + slen; + } + } + break; + case S_CMD_S_SPI_FREQ: { + printf("s_spi_freq\n"); + if (nread < 5) return 0; // need more data + uint32_t freq = (uint32_t)buf[1] | ((uint32_t)buf[2] << 8) | ((uint32_t)buf[3] << 16) | ((uint32_t)buf[4] << 24); + + uint32_t nfreq = sp_spi_set_freq(freq); + tx_buf[0] = S_ACK; + tx_buf[1] = nfreq & 0xff; + tx_buf[2] = (nfreq >> 8) & 0xff; + tx_buf[3] = (nfreq >> 16) & 0xff; + tx_buf[4] = (nfreq >> 24) & 0xff; + nresp = 5; + rv = 5; + } + break; + case S_CMD_S_PINSTATE: { + printf("s_pinstate\n"); + if (nread < 2) return 0; // need more data + + if (buf[1] == 0) sp_spi_cs_deselect(); + else sp_spi_cs_select(); + + tx_buf[0] = S_ACK; + nresp = 1; + rv = 2; + } + break; + + default: + printf("illcmd %d\n", buf[0]); + tx_buf[0] = S_NAK; + nresp = 1; + break; + } + + if (nresp > 0) { + tud_cdc_n_write(CDC_N_SERPROG, tx_buf, nresp); + tud_cdc_n_write_flush(CDC_N_SERPROG); + } + + return rv; +} + +extern void cdc_uart_task(); +void cdc_serprog_task(void) { + bool conn = tud_cdc_n_connected(CDC_N_SERPROG), + avail = tud_cdc_n_available(CDC_N_SERPROG); + //printf("hi conn=%c avail=%c\n", conn?'y':'n', avail?'y':'n'); + // TODO: this is, apparently, not at all how this works: in practice, + // bytes seem to be sent one by one, so its probably better to rework + // this, a lot + if (conn && avail) { + printf("rbp=%d\n", bufpos); + uint32_t nread = tud_cdc_n_read(CDC_N_SERPROG, &rx_buf[bufpos], sizeof(rx_buf) - bufpos); + printf("got %d\n", nread); + cdc_uart_task(); + + bufpos = 0; + do { + printf("hbp=%d\n", /*rx_buf[bufpos],*/ bufpos); + cdc_uart_task(); + uint32_t dec = serprog_handle_cmd(&rx_buf[bufpos], nread); + cdc_uart_task(); + printf("dec=%d\n", dec); + + cdc_uart_task(); + + // didn't do a decrement => not enough data, wait for the next + // task() call to read it in + if (dec == 0) { + // so we move the leftover data to the start of the buffer, + // and make sure the next call will put the new data right + // after it + printf("mv %d %d %d ", nread, bufpos, rx_buf[bufpos]); + memmove(rx_buf, &rx_buf[bufpos], nread); + printf("%d\n", rx_buf[0]); + bufpos = nread; + break; + } + + nread -= dec; + bufpos += dec; + // read everything left in the buffer => we're done here + if (nread == 0) { + // and we can start using the full rx buffer again + bufpos = 0; + break; + } + } while (tud_cdc_n_connected(CDC_N_SERPROG) && tud_cdc_n_available(CDC_N_SERPROG)); + } +} + +#endif /* DBOARD_HAS_SERPROG */ + diff --git a/main.c b/main.c index da9267a..3a1c969 100644 --- a/main.c +++ b/main.c @@ -27,27 +27,50 @@ #include #include -#include "bsp/board.h" +#include "bsp/board.h" /* a tinyusb header */ #include "tusb.h" #include "DAP_config.h" /* ARM code *assumes* this is included prior to DAP.h */ #include "DAP.h" -void cdc_uart_init(void); -void cdc_task(void); +#include "protocfg.h" +#include "protos.h" + +#ifdef PICO_BOARD +#include +#endif int main(void) { + // TODO: split this out in a bsp-specific file +#ifdef PICO_BOARD + // use hardcoded values from TinyUSB board.h + bi_decl(bi_2pins_with_func(0, 1, GPIO_FUNC_UART)); +#endif board_init(); + +#ifdef DBOARD_HAS_UART cdc_uart_init(); +#endif +#ifdef DBOARD_HAS_SERPROG + cdc_serprog_init(); +#endif +#ifdef DBOARD_HAS_CMSISDAP DAP_Setup(); +#endif tusb_init(); while (1) { tud_task(); // tinyusb device task - cdc_task(); +#ifdef DBOARD_HAS_UART + cdc_uart_task(); +#endif +#ifdef DBOARD_HAS_SERPROG + cdc_serprog_task(); +#endif + sleep_ms(100); } return 0; @@ -80,7 +103,9 @@ void tud_hid_set_report_cb(uint8_t report_id, hid_report_type_t report_type, uin (void) report_id; (void) report_type; +#ifdef DBOARD_HAS_CMSISDAP DAP_ProcessCommand(RxDataBuffer, TxDataBuffer); +#endif tud_hid_report(0, TxDataBuffer, response_size); } diff --git a/protos.h b/protos.h new file mode 100644 index 0000000..7f19fac --- /dev/null +++ b/protos.h @@ -0,0 +1,18 @@ + +#ifndef PROTOS_H_ +#define PROTOS_H_ + +#include "protocfg.h" + +#ifdef DBOARD_HAS_UART +void cdc_uart_init(void); +void cdc_uart_task(void); +#endif + +#ifdef DBOARD_HAS_SERPROG +void cdc_serprog_init(void); +void cdc_serprog_task(void); +#endif + +#endif + diff --git a/serprog.h b/serprog.h new file mode 100644 index 0000000..0fd5dfa --- /dev/null +++ b/serprog.h @@ -0,0 +1,55 @@ + +#ifndef SERPROG_H_ +#define SERPROG_H_ + +enum serprog_cmd { + S_CMD_NOP = 0x00, + S_CMD_Q_IFACE = 0x01, + S_CMD_Q_CMDMAP = 0x02, + S_CMD_Q_PGMNAME = 0x03, + S_CMD_Q_SERBUF = 0x04, + S_CMD_Q_BUSTYPE = 0x05, + S_CMD_Q_CHIPSIZE = 0x06, + S_CMD_Q_OPBUF = 0x07, + S_CMD_Q_WRNMAXLEN = 0x08, + S_CMD_R_BYTE = 0x09, + S_CMD_R_NBYTES = 0x0a, + S_CMD_O_INIT = 0x0b, + S_CMD_O_WRITEB = 0x0c, + S_CMD_O_WRITEN = 0x0d, + S_CMD_O_DELAY = 0x0e, + S_CMD_O_EXEC = 0x0f, + S_CMD_SYNCNOP = 0x10, + S_CMD_Q_RDNMAXLEN = 0x11, + S_CMD_S_BUSTYPE = 0x12, + S_CMD_SPIOP = 0x13, + S_CMD_S_SPI_FREQ = 0x14, + S_CMD_S_PINSTATE = 0x15, +}; + +enum serprog_response { + S_ACK = 0x06, + S_NAK = 0x15 +}; + +#define SERPROG_IFACE_VERSION 0x0001 + +void sp_spi_init(void); +uint32_t/*freq_applied*/ sp_spi_set_freq(uint32_t freq_wanted); +void sp_spi_cs_deselect(void); +void sp_spi_cs_select(void); +void sp_spi_op_begin(void); +void sp_spi_op_write(uint32_t write_len, const uint8_t* write_data); +void sp_spi_op_read(uint32_t read_len, uint8_t* read_data); +void sp_spi_op_end(void); + +static inline void sp_spi_op_do(uint32_t write_len, const uint8_t* write_data, + uint32_t read_len, uint8_t* read_data) { + sp_spi_op_begin(); + sp_spi_op_write(write_len, write_data); + sp_spi_op_write(read_len, read_data); + sp_spi_op_end(); +} + +#endif + diff --git a/tusb_config.h b/tusb_config.h index 0e99859..1ceb580 100644 --- a/tusb_config.h +++ b/tusb_config.h @@ -65,7 +65,11 @@ #endif // This example doesn't use an RTOS +#ifdef PICO_BOARD +#define CFG_TUSB_OS OPT_OS_PICO +#else #define CFG_TUSB_OS OPT_OS_NONE +#endif // CFG_TUSB_DEBUG is defined by compiler in DEBUG build // #define CFG_TUSB_DEBUG 0 @@ -94,7 +98,7 @@ #endif //------------- CLASS -------------// -#define CFG_TUD_CDC 1 +#define CFG_TUD_CDC 2 #define CFG_TUD_MSC 0 #define CFG_TUD_HID 1 #define CFG_TUD_MIDI 0 diff --git a/usb_descriptors.c b/usb_descriptors.c index aff5b34..146c45f 100644 --- a/usb_descriptors.c +++ b/usb_descriptors.c @@ -26,6 +26,8 @@ #include "tusb.h" #include "unique.h" +#include "protocfg.h" + /* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug. * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC. * @@ -52,13 +54,13 @@ tusb_desc_device_t const desc_device = { .bLength = sizeof(tusb_desc_device_t), .bDescriptorType = TUSB_DESC_DEVICE, - .bcdUSB = 0x0200, + .bcdUSB = 0x0110, // FIXME: 0x0200 ? .bDeviceClass = 0x00, .bDeviceSubClass = 0x00, .bDeviceProtocol = 0x00, .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, - .idVendor = 0xCafe, + .idVendor = 0xCafe, // TODO .idProduct = USB_PID, .bcdDevice = 0x0101, @@ -99,29 +101,65 @@ uint8_t const * tud_hid_descriptor_report_cb(void) enum { - ITF_NUM_HID, - ITF_NUM_CDC_COM, - ITF_NUM_CDC_DATA, +#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 + ITF_NUM_TOTAL }; -#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_HID_INOUT_DESC_LEN) +/*#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_HID_INOUT_DESC_LEN)*/ -#define EPNUM_HID 0x01 -#define EPNUM_CDC_NOTIF 0x83 -#define EPNUM_CDC_OUT 0x02 -#define EPNUM_CDC_IN 0x82 +static const int CONFIG_TOTAL_LEN = TUD_CONFIG_DESC_LEN +#ifdef DBOARD_HAS_UART + + TUD_CDC_DESC_LEN +#endif +#ifdef DBOARD_HAS_CMSISDAP + + TUD_HID_INOUT_DESC_LEN +#endif +#ifdef DBOARD_HAS_SERPROG + + TUD_CDC_DESC_LEN +#endif + ; +#define EPNUM_CDC_UART_OUT 0x02 // 2 +#define EPNUM_CDC_UART_IN 0x82 // 83 +#define EPNUM_CDC_UART_NOTIF 0x83 // 1 +#define EPNUM_HID_CMSISDAP 0x04 // 4,5? +#define EPNUM_CDC_SERPROG_OUT 0x05 // 7 +#define EPNUM_CDC_SERPROG_IN 0x85 // 8 +#define EPNUM_CDC_SERPROG_NOTIF 0x86 // 6 + +// NOTE: if you modify this table, don't forget to keep tusb_config.h up to date as well! uint8_t const desc_configuration[] = { // Config number, interface count, string index, total length, attribute, power in mA TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), - // Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval - TUD_HID_INOUT_DESCRIPTOR(ITF_NUM_HID, 0, HID_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, 0x80 | EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 1), - +#ifdef DBOARD_HAS_UART // Interface number, string index, EP notification address and size, EP data address (out, in) and size. - TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_COM, 0, EPNUM_CDC_NOTIF, 64, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64), + TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_UART_COM, 0, EPNUM_CDC_UART_NOTIF, 64, EPNUM_CDC_UART_OUT, EPNUM_CDC_UART_IN, 64), +#endif + +#ifdef DBOARD_HAS_CMSISDAP + // Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval + TUD_HID_INOUT_DESCRIPTOR(ITF_NUM_HID_CMSISDAP, 0, HID_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID_CMSISDAP, 0x80 | (EPNUM_HID_CMSISDAP+0), CFG_TUD_HID_EP_BUFSIZE, 1), +#endif + +#ifdef DBOARD_HAS_SERPROG + // Interface number, string index, EP notification address and size, EP data address (out, in) and size. + TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_SERPROG_COM, 0, EPNUM_CDC_SERPROG_NOTIF, 64, EPNUM_CDC_SERPROG_OUT, EPNUM_CDC_SERPROG_IN, 64), +#endif }; // Invoked when received GET CONFIGURATION DESCRIPTOR @@ -141,8 +179,8 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index) char const* string_desc_arr [] = { [STRID_LANGID] = (const char[]) { 0x09, 0x04 }, // supported language is English (0x0409) - [STRID_MANUFACTURER] = "TinyUSB", // Manufacturer - [STRID_PRODUCT] = PRODUCT_PREFIX "CMSIS-DAP", // Product + [STRID_MANUFACTURER] = "TinyUSB", // Manufacturer // TODO + [STRID_PRODUCT] = PRODUCT_PREFIX "CMSIS-DAP", // Product // TODO }; static uint16_t _desc_str[32];