definitely not functuonal but hey its something
This commit is contained in:
parent
f73f890276
commit
144b351d74
|
@ -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})
|
||||
|
||||
|
|
5
Makefile
5
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
|
||||
|
|
19
README.md
19
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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
@ -57,6 +57,7 @@ This information includes:
|
|||
#include <hardware/regs/io_bank0.h>
|
||||
#include <hardware/structs/iobank0.h>
|
||||
#include <hardware/gpio.h>
|
||||
#include <pico/binary_info.h>
|
||||
|
||||
#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.
|
||||
|
|
|
@ -24,39 +24,49 @@
|
|||
*/
|
||||
|
||||
#include <pico/stdlib.h>
|
||||
#include <pico/binary_info.h>
|
||||
|
||||
#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))) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <pico/stdlib.h>
|
||||
#include <pico/binary_info.h>
|
||||
#include <hardware/spi.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
|
@ -2,6 +2,6 @@ void cdc_uart_init(void)
|
|||
{
|
||||
}
|
||||
|
||||
void cdc_task(void)
|
||||
void cdc_uart_task(void)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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){}
|
||||
|
|
@ -0,0 +1,241 @@
|
|||
// vim: set et:
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#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 */
|
||||
|
33
main.c
33
main.c
|
@ -27,27 +27,50 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#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 <pico/binary_info.h>
|
||||
#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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
|
||||
|
|
Loading…
Reference in New Issue