diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e65047..8cc7608 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,6 +46,7 @@ if(FAMILY STREQUAL "rp2040") ${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 + ${CMAKE_CURRENT_SOURCE_DIR}/rtconf.c ) # Example include diff --git a/README.md b/README.md index e425794..e18936a 100644 --- a/README.md +++ b/README.md @@ -125,13 +125,25 @@ libco is licensed under the [ISC license](https://opensource.org/licenses/ISC) - [x] Flashrom/SPI support using Serprog - [ ] Parallel ROM flashing support, too, by having the device switch into a separate mode that temporarily disables all other IO protocols -- [ ] UART with CTS/RTS flow control - - Needs configurable stuff as well, as some UART interfaces won't use this. +- [x] UART with CTS/RTS flow control + - [x] Needs configurable stuff as well, as some UART interfaces won't use this. - [ ] 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 - [ ] Expose RP2040-internal temperature ADC on I2C-over-USB bus? - Does SMBus stuff need special treatment here? +- [ ] Host-side script that is an XVC (or hw_server) cable and communicates + with the device to perform the JTAG commands, because Vivado no likey + OpenOCD. + - CMSIS-DAP interface can be used directly, see CMSIS_5/CMSIS/DoxyGen/DAP/src/dap_USB_cmds.txt + - https://github.com/BerkeleyLab/XVC-FTDI-JTAG + - https://www.eevblog.com/forum/fpga/xilinx-jtag-and-tcf/ + - https://git.eclipse.org/c/tcf/org.eclipse.tcf.git/plain/docs/TCF%20Linux%20Agent%20Prototype.html + - http://www.eclipse.org/tcf/ + - https://debugmo.de/2012/02/xvcd-the-xilinx-virtual-cable-daemon/ + - https://github.com/Xilinx/XilinxVirtualCable/ + - https://github.com/derekmulcahy/xvcpi + - OpenOCD as XVC client?? - [ ] Maybe use the ADCs for something? - [ ] AVR programming (USBavr emulation?) - AVR ISP is hardly used anymore diff --git a/cdc_serprog.c b/cdc_serprog.c index b6b2388..ce8f177 100644 --- a/cdc_serprog.c +++ b/cdc_serprog.c @@ -10,6 +10,7 @@ #include "protos.h" #include "thread.h" +#include "rtconf.h" #include "serprog.h" @@ -26,7 +27,16 @@ 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 + 0, // 18..1f + 0, // 20..27 + 0, // 28..2f + 0, // 30..37 + 0, // 38..3f + 0, // 40..47 + 0, // 48..4f + (1<<3), // 50..57: enable 0x53 + 0, // 58..5f + 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 @@ -219,6 +229,16 @@ static void handle_cmd(void) { } break; + case S_CMD_MAGIC_SETTINGS: { + uint8_t a = read_byte(); + uint8_t b = read_byte(); + + tx_buf[0] = S_ACK; + tx_buf[1] = rtconf_do(a, b); + nresp = 2; + } + break; + default: //printf("ill %d\n", cmd); tx_buf[0] = S_NAK; @@ -232,54 +252,6 @@ static void handle_cmd(void) { } } -//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)); -// } -//} void cdc_serprog_task(void) { handle_cmd(); //printf("d\n"); diff --git a/dmctl.py b/dmctl.py new file mode 100644 index 0000000..4b0db08 --- /dev/null +++ b/dmctl.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 + +import serial, struct +from typing import * + +S_ACK = b'\x06' +S_NAK = b'\x15' + +S_CMD_NOP = b'\x00' +S_CMD_Q_IFACE = b'\x01' +S_CMD_Q_CMDMAP = b'\x02' +S_CMD_Q_PGMNAME = b'\x03' +S_CMD_SYNCNOP = b'\x10' +S_CMD_MAGIC_SETTINGS = b'\x53' + +def do_xfer(cmd:int, arg:int, port: str, baudrate:int=115200) -> Optional[int]: + with serial.Serial(port, baudrate, timeout=1) as ser: + cmdmap = [0]*32 + syncok = False + for i in range(8): + ser.write(S_CMD_SYNCNOP) + a = ser.read() + b = ser.read() + if a == S_NAK and b == S_ACK: + syncok = True + break + + if not syncok: + print("sync failed") + return None + + ser.write(S_CMD_NOP) + if ser.read() != S_ACK: + print("nop failed") + return None + + ser.write(S_CMD_Q_IFACE) + if ser.read() != S_ACK: + print("q_iface failed") + return None + serprogver = struct.unpack('> 3] & (1<<(S_CMD_MAGIC_SETTINGS[0]&7))) == 0: + print("serprog programmer has no S_CMD_MAGIC_SETTINGS") + return None + + if (cmdmap[S_CMD_Q_PGMNAME[0] >> 3] & (1<<(S_CMD_Q_PGMNAME[0]&7))) != 0: + ser.write(S_CMD_Q_PGMNAME) + if ser.read() != S_ACK: + print("q_pgmname failed") + else: + name = ser.read(16).decode('utf-8') + print("programmer is '%s'" % name) + + ser.write(S_CMD_MAGIC_SETTINGS) + ser.write(bytes([cmd,arg])) + acknak = ser.read() + + if acknak == S_ACK: + return ser.read()[0] + else: + print("settings command failed") + return None + +do_xfer(1, 1, "/dev/ttyACM1") +do_xfer(1, 0, "/dev/ttyACM1") + diff --git a/rtconf.c b/rtconf.c new file mode 100644 index 0000000..2dba1e2 --- /dev/null +++ b/rtconf.c @@ -0,0 +1,22 @@ + +#include +#include + +#include "protos.h" + +#include "rtconf.h" + +uint8_t rtconf_do(uint8_t a, uint8_t b) { + //printf("rtconf %02x,%02x\n", a, b); + + switch ((enum rtconf_opt)a) { +#ifdef DBOARD_HAS_UART + case opt_uart_hwfc_endis: + cdc_uart_set_hwflow(b != 0); + return 0; +#endif + default: + return 0xff; + } +} + diff --git a/rtconf.h b/rtconf.h new file mode 100644 index 0000000..8beb24b --- /dev/null +++ b/rtconf.h @@ -0,0 +1,21 @@ + +#ifndef RTCONF_H_ +#define RTCONF_H_ + +#include + +#include "protocfg.h" + +enum rtconf_opt { +#ifdef DBOARD_HAS_UART + // enable_disable UART flow control + // b: 0 -> disable, nonzero -> enable + // return: 0 + opt_uart_hwfc_endis = 1, +#endif +}; + +uint8_t rtconf_do(uint8_t a, uint8_t b); + +#endif +