From e57b71710e7681cd9d9065974fae9c5b7e6cb555 Mon Sep 17 00:00:00 2001 From: default Date: Sat, 30 Sep 2023 15:38:10 +0200 Subject: [PATCH 01/22] Support for CH347 JTAG itnerfaces added --- .github/workflows/OpenOCD EasyDevKits CI.yml | 59 + README.md | 339 ++++ cmake/BuildOptions.cmake | 1 + configure.ac | 13 + src/jtag/drivers/CMakeLists.txt | 4 + src/jtag/drivers/Makefile.am | 3 + src/jtag/drivers/ch347.c | 1837 ++++++++++++++++++ src/jtag/interface.h | 2 +- src/jtag/interfaces.c | 3 + tcl/interface/easydevkits-wch.cfg | 4 + tcl/interface/ftdi/easydevkits-ftdi.cfg | 24 + 11 files changed, 2288 insertions(+), 1 deletion(-) create mode 100755 .github/workflows/OpenOCD EasyDevKits CI.yml create mode 100755 README.md mode change 100644 => 100755 cmake/BuildOptions.cmake mode change 100644 => 100755 configure.ac mode change 100644 => 100755 src/jtag/drivers/CMakeLists.txt mode change 100644 => 100755 src/jtag/drivers/Makefile.am create mode 100755 src/jtag/drivers/ch347.c mode change 100644 => 100755 src/jtag/interface.h mode change 100644 => 100755 src/jtag/interfaces.c create mode 100755 tcl/interface/easydevkits-wch.cfg create mode 100755 tcl/interface/ftdi/easydevkits-ftdi.cfg diff --git a/.github/workflows/OpenOCD EasyDevKits CI.yml b/.github/workflows/OpenOCD EasyDevKits CI.yml new file mode 100755 index 0000000000..9205c38043 --- /dev/null +++ b/.github/workflows/OpenOCD EasyDevKits CI.yml @@ -0,0 +1,59 @@ +name: OpenOCD EasyDevKits CI + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + build-linux: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Install dependencies + run: sudo apt-get -y install libusb-1.0 + - name: Bootstrap + run: ./bootstrap + - name: Configure + run: ./configure + - name: Make + run: make + - name: Create package + run: make DESTDIR=/tmp install + - uses: actions/upload-artifact@v3 + with: + name: openocd-easydevkits-linux + path: /tmp/usr/local + + build-windows: + + runs-on: windows-latest + + defaults: + run: + shell: msys2 {0} + + steps: + - uses: actions/checkout@v3 + - uses: msys2/setup-msys2@v2 + with: + msystem: MINGW32 + update: true + #for MINGW64 but not working - install: base-devel mingw-w64-x86_64-toolchain git libtool pkg-config autoconf automake texinfo mingw-w64-x86_64-libusb + install: base-devel mingw-w64-i686-gcc mingw-w64-i686-toolchain git libtool pkg-config autoconf automake texinfo mingw-w64-i686-libusb + + - name: Bootstrap + run: ./bootstrap + - name: Configure + run: ./configure + - name: Make + run: make + - name: Create package + run: make DESTDIR=/tmp install + - uses: actions/upload-artifact@v3 + with: + name: openocd-easydevkits-windows + path: D:\a\_temp\msys64\tmp\mingw32 diff --git a/README.md b/README.md new file mode 100755 index 0000000000..2a3adac74c --- /dev/null +++ b/README.md @@ -0,0 +1,339 @@ +[![OpenOCD EasyDevKits CI](https://github.com/EasyDevKits/openocd-easydevkits/actions/workflows/OpenOCD%20EasyDevKits%20CI.yml/badge.svg)](https://github.com/EasyDevKits/openocd-easydevkits/actions/workflows/OpenOCD%20EasyDevKits%20CI.yml) + +# Welcome to OpenOCD for EasyDevKits! + +**This repository is forked from [espressif/openocd-esp32](https://github.com/espressif/openocd-esp32) and contains modifications for working with [EasyDevKits](https://www.easydevkits.com/)** + +OpenOCD provides on-chip programming and debugging support with a +layered architecture of JTAG interface and TAP support including: + +- (X)SVF playback to facilitate automated boundary scan and FPGA/CPLD + programming; +- debug target support (e.g. ARM, MIPS): single-stepping, + breakpoints/watchpoints, gprof profiling, etc; +- flash chip drivers (e.g. CFI, NAND, internal flash); +- embedded TCL interpreter for easy scripting. + +Several network interfaces are available for interacting with OpenOCD: +telnet, TCL, and GDB. The GDB server enables OpenOCD to function as a +"remote target" for source-level debugging of embedded systems using +the GNU GDB program (and the others who talk GDB protocol, e.g. IDA +Pro). + +This README file contains an overview of the following topics: + +- quickstart instructions, +- how to find and build more OpenOCD documentation, +- list of the supported hardware, +- the installation and build process, +- packaging tips. + + +# Quickstart for the impatient + +If you have a popular board then just start OpenOCD with its config, +e.g.: + + ```openocd -f board/stm32f4discovery.cfg``` + +If you are connecting a particular adapter with some specific target, +you need to source both the jtag interface and the target configs, +e.g.: + + ```openocd -f interface/ftdi/jtagkey2.cfg -c "transport select jtag" -f target/ti_calypso.cfg``` + + ```openocd -f interface/stlink.cfg -c "transport select hla_swd" -f target/stm32l0.cfg``` + +After OpenOCD startup, connect GDB with + + (gdb) target extended-remote localhost:3333 + + +# OpenOCD Documentation + +In addition to the in-tree documentation, the latest manuals may be +viewed online at the following URLs: + + OpenOCD User's Guide: + http://openocd.org/doc/html/index.html + + OpenOCD Developer's Manual: + http://openocd.org/doc/doxygen/html/index.html + +These reflect the latest development versions, so the following section +introduces how to build the complete documentation from the package. + +For more information, refer to these documents or contact the developers +by subscribing to the OpenOCD developer mailing list: + + openocd-devel@lists.sourceforge.net + +# Building the OpenOCD Documentation + +By default the OpenOCD build process prepares documentation in the +"Info format" and installs it the standard way, so that "info openocd" +can access it. + +Additionally, the OpenOCD User's Guide can be produced in the +following different formats: + + **If PDFVIEWER is set, this creates and views the PDF User Guide.** + + ```make pdf && ${PDFVIEWER} doc/openocd.pdf``` + + **If HTMLVIEWER is set, this creates and views the HTML User Guide.** + + ```make html && ${HTMLVIEWER} doc/openocd.html/index.html``` + +The OpenOCD Developer Manual contains information about the internal +architecture and other details about the code: + + **NB! make sure doxygen is installed, type doxygen --version** + + ```make doxygen && ${HTMLVIEWER} doxygen/index.html``` + + +# Supported hardware + +## JTAG adapters + +AM335x, ARM-JTAG-EW, ARM-USB-OCD, ARM-USB-TINY, AT91RM9200, axm0432, BCM2835, +Bus Blaster, Buspirate, Cadence DPI, Cadence vdebug, Chameleon, CMSIS-DAP, +Cortino, Cypress KitProg, DENX, Digilent JTAG-SMT2, DLC 5, DLP-USB1232H, +**EasyDevKits**, embedded projects, Espressif USB JTAG Programmer, +eStick, FlashLINK, FlossJTAG, Flyswatter, Flyswatter2, +FTDI FT232R, Gateworks, Hoegl, ICDI, ICEBear, J-Link, JTAG VPI, JTAGkey, +JTAGkey2, JTAG-lock-pick, KT-Link, Linux GPIOD, Lisa/L, LPC1768-Stick, +Mellanox rshim, MiniModule, NGX, Nuvoton Nu-Link, Nu-Link2, NXHX, NXP IMX GPIO, +OOCDLink, Opendous, OpenJTAG, Openmoko, OpenRD, OSBDM, Presto, Redbee, +Remote Bitbang, RLink, SheevaPlug devkit, Stellaris evkits, +ST-LINK (SWO tracing supported), STM32-PerformanceStick, STR9-comStick, +sysfsgpio, TI XDS110, TUMPA, Turtelizer, ULINK, USB-A9260, USB-Blaster, +USB-JTAG, USBprog, VPACLink, VSLLink, Wiggler, XDS100v2, Xilinx XVC/PCIe, +Xverve. + +## Debug targets + +ARM: AArch64, ARM11, ARM7, ARM9, Cortex-A/R (v7-A/R), Cortex-M (ARMv{6/7/8}-M), +FA526, Feroceon/Dragonite, XScale. +ARCv2, AVR32, DSP563xx, DSP5680xx, EnSilica eSi-RISC, EJTAG (MIPS32, MIPS64), +ESP32, ESP32-S2, ESP32-S3, Intel Quark, LS102x-SAP, RISC-V, ST STM8, +Xtensa. + +## Flash drivers + +ADUC702x, AT91SAM, AT91SAM9 (NAND), ATH79, ATmega128RFA1, Atmel SAM, AVR, CFI, +DSP5680xx, EFM32, EM357, eSi-RISC, eSi-TSMC, EZR32HG, FM3, FM4, Freedom E SPI, +i.MX31, Kinetis, LPC8xx/LPC1xxx/LPC2xxx/LPC541xx, LPC2900, LPC3180, LPC32xx, +LPCSPIFI, Marvell QSPI, MAX32, Milandr, MXC, NIIET, nRF51, nRF52 , NuMicro, +NUC910, Orion/Kirkwood, PIC32mx, PSoC4/5LP/6, Renesas RPC HF and SH QSPI, +S3C24xx, S3C6400, SiM3x, SiFive Freedom E, Stellaris, ST BlueNRG, STM32, +STM32 QUAD/OCTO-SPI for Flash/FRAM/EEPROM, STMSMI, STR7x, STR9x, SWM050, +TI CC13xx, TI CC26xx, TI CC32xx, TI MSP432, Winner Micro w600, Xilinx XCF, +XMC1xxx, XMC4xxx. + + +# Installing OpenOCD + +## A Note to OpenOCD Users + +If you would rather be working "with" OpenOCD rather than "on" it, your +operating system or JTAG interface supplier may provide binaries for +you in a convenient-enough package. + +Such packages may be more stable than git mainline, where +bleeding-edge development takes place. These "Packagers" produce +binary releases of OpenOCD after the developers produces new "release" +versions of the source code. Previous versions of OpenOCD cannot be +used to diagnose problems with the current release, so users are +encouraged to keep in contact with their distribution package +maintainers or interface vendors to ensure suitable upgrades appear +regularly. + +Users of these binary versions of OpenOCD must contact their Packager to +ask for support or newer versions of the binaries; the OpenOCD +developers do not support packages directly. + +## A Note to OpenOCD Packagers + +You are a PACKAGER of OpenOCD if you: + +- Sell dongles and include pre-built binaries; +- Supply tools or IDEs (a development solution integrating OpenOCD); +- Build packages (e.g. RPM or DEB files for a GNU/Linux distribution). + +As a PACKAGER, you will experience first reports of most issues. +When you fix those problems for your users, your solution may help +prevent hundreds (if not thousands) of other questions from other users. + +If something does not work for you, please work to inform the OpenOCD +developers know how to improve the system or documentation to avoid +future problems, and follow-up to help us ensure the issue will be fully +resolved in our future releases. + +That said, the OpenOCD developers would also like you to follow a few +suggestions: + +- Send patches, including config files, upstream, participate in the + discussions; +- Enable all the options OpenOCD supports, even those unrelated to your + particular hardware; +- Use "ftdi" interface adapter driver for the FTDI-based devices. + + +# Building OpenOCD + +The INSTALL file contains generic instructions for running 'configure' +and compiling the OpenOCD source code. That file is provided by +default for all GNU autotools packages. If you are not familiar with +the GNU autotools, then you should read those instructions first. + +The remainder of this document tries to provide some instructions for +those looking for a quick-install. + +## OpenOCD Dependencies + +GCC or Clang is currently required to build OpenOCD. The developers +have begun to enforce strict code warnings (-Wall, -Werror, -Wextra, +and more) and use C99-specific features: inline functions, named +initializers, mixing declarations with code, and other tricks. While +it may be possible to use other compilers, they must be somewhat +modern and could require extending support to conditionally remove +GCC-specific extensions. + +You'll also need: + +- make +- libtool +- pkg-config >= 0.23 or pkgconf + +OpenOCD uses jimtcl library; build from git can retrieve jimtcl as git +submodule. + +Additionally, for building from git: + +- autoconf >= 2.69 +- automake >= 1.14 +- texinfo >= 5.0 + +Optional USB-based adapter drivers need libusb-1.0. + +Optional USB-Blaster, ASIX Presto and OpenJTAG interface adapter +drivers need: + - libftdi: http://www.intra2net.com/en/developer/libftdi/index.php + +Optional CMSIS-DAP adapter driver needs HIDAPI library. + +Optional linuxgpiod adapter driver needs libgpiod library. + +Optional J-Link adapter driver needs libjaylink library. + +Optional ARM disassembly needs capstone library. + +Optional development script checkpatch needs: + +- perl +- python +- python-ply + +## Permissions delegation + +Running OpenOCD with root/administrative permissions is strongly +discouraged for security reasons. + +For USB devices on GNU/Linux you should use the contrib/60-openocd.rules +file. It probably belongs somewhere in /etc/udev/rules.d, but +consult your operating system documentation to be sure. Do not forget +to add yourself to the "plugdev" group. + +For parallel port adapters on GNU/Linux and FreeBSD please change your +"ppdev" (parport* or ppi*) device node permissions accordingly. + +For parport adapters on Windows you need to run install_giveio.bat +(it's also possible to use "ioperm" with Cygwin instead) to give +ordinary users permissions for accessing the "LPT" registers directly. + +## Compiling OpenOCD + +To build OpenOCD, use the following sequence of commands: + + ```./bootstrap (when building from the git repository)``` + + ```./configure [options]``` + + ```make``` + + ```sudo make install``` + +The 'configure' step generates the Makefiles required to build +OpenOCD, usually with one or more options provided to it. The first +'make' step will build OpenOCD and place the final executable in +'./src/'. The final (optional) step, ``make install'', places all of +the files in the required location. + +To see the list of all the supported options, run + ```./configure --help``` + +## Cross-compiling Options + +Cross-compiling is supported the standard autotools way, you just need +to specify the cross-compiling target triplet in the --host option, +e.g. for cross-building for Windows 32-bit with MinGW on Debian: + + ```./configure --host=i686-w64-mingw32 [options]``` + +To make pkg-config work nicely for cross-compiling, you might need an +additional wrapper script as described at + + https://autotools.io/pkgconfig/cross-compiling.html + +This is needed to tell pkg-config where to look for the target +libraries that OpenOCD depends on. Alternatively, you can specify +*_CFLAGS and *_LIBS environment variables directly, see "./configure +--help" for the details. + +For a more or less complete script that does all this for you, see + + contrib/cross-build.sh + +## Parallel Port Dongles + +If you want to access the parallel port using the PPDEV interface you +have to specify both --enable-parport AND --enable-parport-ppdev, since +the later option is an option to the parport driver. + +The same is true for the --enable-parport-giveio option, you have to +use both the --enable-parport AND the --enable-parport-giveio option +if you want to use giveio instead of ioperm parallel port access +method. + + +## Obtaining OpenOCD From GIT + +You can download the current GIT version with a GIT client of your +choice from the main repository: + + git://git.code.sf.net/p/openocd/code + +You may prefer to use a mirror: + + http://repo.or.cz/r/openocd.git + git://repo.or.cz/openocd.git + +Using the GIT command line client, you might use the following command +to set up a local copy of the current repository (make sure there is no +directory called "openocd" in the current directory): + + ```git clone git://git.code.sf.net/p/openocd/code openocd``` + +Then you can update that at your convenience using + + ```git pull``` + +There is also a gitweb interface, which you can use either to browse +the repository or to download arbitrary snapshots using HTTP: + + http://repo.or.cz/w/openocd.git + +Snapshots are compressed tarballs of the source tree, about 1.3 MBytes +each at this writing. diff --git a/cmake/BuildOptions.cmake b/cmake/BuildOptions.cmake old mode 100644 new mode 100755 index 835fd7720a..5761cad6e6 --- a/cmake/BuildOptions.cmake +++ b/cmake/BuildOptions.cmake @@ -39,6 +39,7 @@ option(BUILD_SANITIZERS "Build support with the sanitizer flags" OFF) # USB1 Adapters #TODO check default values option(BUILD_FTDI "MPSSE mode of FTDI based devices" ON) +option(BUILD_CH347 "Mode 3 of the CH347 devices" ON) option(BUILD_HLADAPTER_STLINK "ST-Link Programmer" ON) option(BUILD_HLADAPTER_ICDI "TI ICDI JTAG Programmer" ON) option(BUILD_ULINK "Keil ULINK JTAG Programmer" ON) diff --git a/configure.ac b/configure.ac old mode 100644 new mode 100755 index 839a7f85ed..87e26408af --- a/configure.ac +++ b/configure.ac @@ -116,6 +116,7 @@ m4_define([ADAPTER_OPT], [m4_translit(ADAPTER_ARG($1), [_], [-])]) m4_define([USB1_ADAPTERS], [[[ftdi], [MPSSE mode of FTDI based devices], [FTDI]], + [[ch347], [Mode 3 of the CH347 devices], [CH347]], [[stlink], [ST-Link Programmer], [HLADAPTER_STLINK]], [[ti_icdi], [TI ICDI JTAG Programmer], [HLADAPTER_ICDI]], [[ulink], [Keil ULINK JTAG Programmer], [ULINK]], @@ -393,6 +394,10 @@ AC_ARG_ENABLE([remote-bitbang], AS_HELP_STRING([--enable-remote-bitbang], [Enable building support for the Remote Bitbang jtag driver]), [build_remote_bitbang=$enableval], [build_remote_bitbang=no]) +AC_ARG_ENABLE([ch347], + AS_HELP_STRING([--enable-ch347], [Enable building support for CH347]), + [build_ch347=$enableval], [build_ch347=no]) + AS_CASE(["${host_cpu}"], [i?86|x86*], [], [ @@ -643,6 +648,12 @@ AS_IF([test "x$build_gcov" = "xyes"], [ AC_DEFINE([BUILD_GCOV], [0], [0 if you don't want OpenOCD source code coverage support.]) ]) +AS_IF([test "x$build_ch347" = "xyes"], [ + AC_DEFINE([BUILD_CH347], [1], [1 if you want CH347.]) +], [ + AC_DEFINE([BUILD_CH347], [0], [0 if you don't want CH347.]) +]) + PKG_CHECK_MODULES([LIBUSB1], [libusb-1.0], [ use_libusb1=yes AC_DEFINE([HAVE_LIBUSB1], [1], [Define if you have libusb-1.x]) @@ -804,6 +815,8 @@ AM_CONDITIONAL([BUILD_ESP_COMPRESSION], [test "x$build_esp_compression" = "xyes" AM_CONDITIONAL([BUILD_GCOV], [test "x$build_gcov" = "xyes"]) +AM_CONDITIONAL([BUILD_CH347], [test "x$build_ch347" = "xyes"]) + # Look for environ alternatives. Possibility #1: is environ in unistd.h or stdlib.h? AC_MSG_CHECKING([for environ in unistd.h and stdlib.h]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ diff --git a/src/jtag/drivers/CMakeLists.txt b/src/jtag/drivers/CMakeLists.txt old mode 100644 new mode 100755 index c2f9ce840b..240fdb5a5c --- a/src/jtag/drivers/CMakeLists.txt +++ b/src/jtag/drivers/CMakeLists.txt @@ -232,6 +232,10 @@ if(IS_ESPIDF) target_link_libraries(ocdjtagdrivers PRIVATE idf::driver) endif() +if(BUILD_CH347) + target_sources(ocdjtagdrivers PRIVATE ch347.c) +endif() + target_sources(ocdjtagdrivers PRIVATE bitbang.h bitq.h diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am old mode 100644 new mode 100755 index e012c90dda..767e347975 --- a/src/jtag/drivers/Makefile.am +++ b/src/jtag/drivers/Makefile.am @@ -204,6 +204,9 @@ endif if BUILD_ESP_REMOTE DRIVERFILES += %D%/jtag_esp_remote.c endif +if CH347 +DRIVERFILES += %D%/ch347.c +endif DRIVERHEADERS = \ %D%/bitbang.h \ diff --git a/src/jtag/drivers/ch347.c b/src/jtag/drivers/ch347.c new file mode 100755 index 0000000000..704a878692 --- /dev/null +++ b/src/jtag/drivers/ch347.c @@ -0,0 +1,1837 @@ +/*************************************************************************** + * Driver for CH347-JTAG interface V1.1 * + * * + * Copyright (C) 2022 by oidcat. * + * Author: oidcatiot@163.com * + * * + * CH347 is a high-speed USB bus converter chip that provides UART, I2C * + * and SPI synchronous serial ports and JTAG interface through USB bus. * + * * + * The Jtag interface by CH347 can supports transmission frequency * + * configuration up to 60MHz. * + * * + * The USB2.0 to JTAG scheme based on CH347 can be used to build * + * customized USB high-speed JTAG debugger and other products. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * _____________ * + * | |____JTAG/SWD (TDO,TDI,TMS,TCK,TRST) * + * USB__| CH347T | * + * |_____________|____UART(TXD1,RXD1,RTS1,CTS1,DTR1) * + * ______|______ * + * | | * + * | 8 MHz XTAL | * + * |_____________| * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if IS_CYGWIN == 1 +#include "windows.h" +#undef LOG_ERROR +#endif + +/* project specific includes */ +#include +#include +#include +#include +#include +#include +#include +#include "libusb_helper.h" + +/* system includes */ +#include +#include +#include +#include +#include + +#define JTAGIO_STA_OUT_TDI (0x10) +#define JTAGIO_STA_OUT_TMS (0x02) +#define JTAGIO_STA_OUT_TCK (0x01) +#define JTAGIO_STA_OUT_TRST (0x20) +#define TDI_H JTAGIO_STA_OUT_TDI +#define TDI_L 0 +#define TMS_H JTAGIO_STA_OUT_TMS +#define TMS_L 0 +#define TCK_H JTAGIO_STA_OUT_TCK +#define TCK_L 0 +#define TRST_H JTAGIO_STA_OUT_TRST +#define TRST_L 0 + +#define KHZ(n) ((n)*UINT64_C(1000)) +#define MHZ(n) ((n)*UINT64_C(1000000)) +#define GHZ(n) ((n)*UINT64_C(1000000000)) + +#define HW_TDO_BUF_SIZE 4096 +#define SF_PACKET_BUF_SIZE 51200 /* Command packet length */ +#define UCMDPKT_DATA_MAX_BYTES_USBHS 507 /* The data length contained in each + command packet during USB + high-speed operation */ +#define USBC_PACKET_USBHS 512 /* Maximum data length per packet at + USB high speed */ +#define USBC_PACKET_USBHS_SINGLE 510 /* usb high speed max + package length */ +#define CH347_CMD_HEADER 3 /* Protocol header length */ + +#define CH347_CMD_HEADER 3 /* 协议包头长度 */ +/* Protocol transmission format: CMD (1 byte)+Length (2 bytes)+Data */ +#define CH347_CMD_INFO_RD 0xCA /* Parameter acquisition, used to + obtain firmware version, + JTAG interface related parameters, + etc */ +#define CH347_CMD_JTAG_INIT 0xD0 /* JTAG Interface Initialization + Command */ +#define CH347_CMD_JTAG_BIT_OP 0xD1 /* JTAG interface pin bit control + command */ +#define CH347_CMD_JTAG_BIT_OP_RD 0xD2 /* JTAG interface pin bit control and + read commands */ +#define CH347_CMD_JTAG_DATA_SHIFT 0xD3 /* JTAG interface data shift + command */ +#define CH347_CMD_JTAG_DATA_SHIFT_RD 0xD4 /* JTAG interface data shift and read + command */ +/* SWD */ +#define CH347_CMD_SWD_INIT 0xE5 /* SWD Interface Initialization Command */ +#define CH347_CMD_SWD 0xE8 +#define CH347_CMD_SWD_REG_W 0xA0 /* SWD Interface write reg */ +#define CH347_CMD_SWD_SEQ_W 0xA1 /* SWD Interface write spec seq */ +#define CH347_CMD_SWD_REG_R 0xA2 /* SWD Interface read reg */ +#define CH347_MAX_SEND_CMD 0X20 /* max send cmd number */ +#define CH347_MAX_SEND_BUF 0X200 +#define CH347_MAX_RECV_BUF 0X200 +#define BUILD_UINT16(loByte, hiByte) \ + ((uint16_t)(((loByte)&0x00FF) + (((hiByte)&0x00FF) << 8))) +#pragma pack(1) + +typedef unsigned char UCHAR; + +typedef enum pack { + STANDARD_PACK = 0, + LARGER_PACK = 1, +} PACK_SIZE; + +typedef struct _CH347_info /* Record the CH347 pin status */ +{ + int TMS; + int TDI; + int TCK; + int TRST; + + int buffer_idx; + uint8_t buffer[SF_PACKET_BUF_SIZE]; + + int len_idx; + int len_value; + uint8_t lastCmd; + + uint8_t read_buffer[SF_PACKET_BUF_SIZE]; + uint32_t read_idx; + uint32_t read_count; + struct bit_copy_queue read_queue; + PACK_SIZE pack_size; +} _CH347_Info; + +int DevIsOpened; /* Whether the device is turned on */ +bool UsbHighDev = true; +unsigned long USBC_PACKET; + +typedef struct _CH347_SWD_IO { + uint8_t usbcmd; /* 0xA0、0xA1、0xA2 */ + uint8_t cmd; + uint32_t *dst; + uint32_t value; + struct list_head list_entry; +} CH347_SWD_IO, *PCH347_SWD_IO; + +typedef struct _CH347_SWD_CONTEXT { + uint8_t send_buf[CH347_MAX_SEND_BUF]; + uint8_t recv_buf[CH347_MAX_RECV_BUF]; + uint32_t send_len; + uint32_t recv_len; + uint32_t need_recv_len; + int queued_retval; + uint8_t sent_cmd_count; + struct list_head send_cmd_head; + struct list_head free_cmd_head; + uint8_t *ch347_cmd_buf; +} CH347_SWD_CONTEXT; +static CH347_SWD_CONTEXT ch347_swd_context; +static bool swd_mode; +#pragma pack() + +#ifdef _WIN32 +#include + +typedef int(__stdcall * pCH347OpenDevice)(unsigned long iIndex); + +typedef int(__stdcall * pCH347CloseDevice)(unsigned long iIndex); + +typedef unsigned long(__stdcall * pCH347SetTimeout)( + unsigned long iIndex, /* Specify equipment serial number */ + unsigned long iWriteTimeout, /* Specifies the timeout period for USB + write out data blocks, in milliseconds + mS, and 0xFFFFFFFF specifies no timeout + (default) */ + unsigned long iReadTimeout); /* Specifies the timeout period for USB + reading data blocks, in milliseconds mS, + and 0xFFFFFFFF specifies no timeout + (default) */ + +typedef unsigned long(__stdcall * pCH347WriteData)( + unsigned long iIndex, /* Specify equipment serial number */ + void *oBuffer, /* Point to a buffer large enough to hold + the descriptor */ + unsigned long *ioLength); /* Pointing to the length unit, the input + is the length to be read, and the + return is the actual read length */ + +typedef unsigned long(__stdcall * pCH347ReadData)( + unsigned long iIndex, /* Specify equipment serial number */ + void *oBuffer, /* Point to a buffer large enough to + hold the descriptor */ + unsigned long *ioLength); /* Pointing to the length unit, the input + is the length to be read, and the + return is the actual read length */ + +typedef unsigned long(__stdcall * pCH347Jtag_INIT)( + unsigned long iIndex, /* Specify equipment serial number */ + unsigned char iClockRate); /* Pointing to the length unit, the input + is the length to be read, and the + return is the actual read length */ +HMODULE uhModule; +BOOL ugOpen; +unsigned long ugIndex; +pCH347OpenDevice CH347OpenDevice; +pCH347CloseDevice CH347CloseDevice; +pCH347SetTimeout CH347SetTimeout; +pCH347ReadData CH347ReadData; +pCH347WriteData CH347WriteData; +/* pCH347Jtag_INIT CH347Jtag_INIT; */ +#elif defined(__linux__) + +#include + +#define CH347_EPOUT 0x06u +#define CH347_EPIN 0x86u + +bool ugOpen; +unsigned long ugIndex; +struct libusb_device_handle *ch347_handle; + +static const uint16_t ch347_vids[] = {0x1a86, 0}; +static const uint16_t ch347_pids[] = {0x55dd, 0}; + +static uint32_t CH347OpenDevice(uint64_t iIndex) +{ + if (jtag_libusb_open(ch347_vids, ch347_pids, + &ch347_handle, NULL) != ERROR_OK) { + return false; + } else { + return true; + } +} + +static bool CH347WriteData(uint64_t iIndex, uint8_t *data, uint64_t *length) +{ + int ret, tmp = 0; + ret = jtag_libusb_bulk_write(ch347_handle, + CH347_EPOUT, + (char *)data, + *length, + 100, &tmp); + *length = tmp; + + if (!ret) + return true; + else + return false; +} + +static bool CH347ReadData(uint64_t iIndex, uint8_t *data, uint64_t *length) +{ + int ret, tmp = 0; + + int size = *length; + ret = jtag_libusb_bulk_read(ch347_handle, + CH347_EPIN, + (char *)data, + size, + 100, &tmp); + + *length = tmp; + if (!ret) + return true; + else + return false; +} + +static bool CH347CloseDevice(uint64_t iIndex) +{ + jtag_libusb_close(ch347_handle); + return true; +} + +#endif + +_CH347_Info ch347; + +static int ch347_swd_run_queue(void); +/* swd init func */ +static bool CH347SWD_INIT(uint64_t iIndex, uint8_t iClockRate) +{ + uint8_t cmdBuf[128] = ""; + unsigned long i = 0; + cmdBuf[i++] = CH347_CMD_SWD_INIT; + cmdBuf[i++] = 8; /* Data length is 6 */ + cmdBuf[i++] = 0; + cmdBuf[i++] = 0x40; + cmdBuf[i++] = 0x42; + + cmdBuf[i++] = 0x0f; /* Reserved Bytes */ + cmdBuf[i++] = 0x00; /* Reserved Bytes */ + cmdBuf[i++] = iClockRate; /* JTAG clock speed */ + i += 3; /* Reserved Bytes */ + + unsigned long mLength = i; + if (!CH347WriteData(iIndex, cmdBuf, &mLength) || (mLength != i)) + return false; + + mLength = 4; + memset(cmdBuf, 0, sizeof(cmdBuf)); + + if (!CH347ReadData(iIndex, cmdBuf, &mLength) || (mLength != 4)) + return false; + + return true; +} + +/** + * HexToString - Hex Conversion String Function + * @param buf Point to a buffer to place the Hex data to be converted + * @param size Pointing to the length unit where data needs to be converted + * + * @return Returns a converted string + */ +static char *HexToString(uint8_t *buf, uint32_t size) +{ + uint32_t i; + if (buf == NULL) + return "NULL"; + + char *str = calloc(size * 2 + 1, 1); + + for (i = 0; i < size; i++) + sprintf(str + 2 * i, "%02x ", buf[i]); + return str; +} + +/** + * CH347_Write - CH347 Write + * @param oBuffer Point to a buffer to place the data to be written out + * @param ioLength Pointing to the length unit, the input is the length to be + * written out, and the return is the actual written length + * + * @return Write success returns 1, failure returns 0 + */ +static int CH347_Write(void *oBuffer, unsigned long *ioLength) +{ + int ret = -1; + unsigned long wlength = *ioLength, WI; + if (*ioLength >= HW_TDO_BUF_SIZE) + wlength = HW_TDO_BUF_SIZE; + WI = 0; + while (1) { + ret = CH347WriteData(ugIndex, (uint8_t *)oBuffer + WI, + &wlength); + if (!ret) { + *ioLength = 0; + return false; + } + LOG_DEBUG_IO("(size=%lu, buf=[%s]) -> %" PRIu32, wlength, + HexToString((uint8_t *)oBuffer, wlength), + (uint32_t)wlength); + WI += wlength; + if (WI >= *ioLength) + break; + if ((*ioLength - WI) > HW_TDO_BUF_SIZE) + wlength = HW_TDO_BUF_SIZE; + else + wlength = *ioLength - WI; + } + + *ioLength = WI; + return true; +} + +/** + * CH347_Read - CH347 Read + * @param oBuffer Point to a buffer to place the data to be read in + * @param ioLength Pointing to the length unit, the input is the length to + * be read, and the return is the actual read length + * + * @return Write success returns 1, failure returns 0 + */ +static int CH347_Read(void *oBuffer, unsigned long *ioLength) +{ + unsigned long rlength = *ioLength, WI; + /* The maximum allowable reading for a single read is 4096B of data. + If it exceeds the allowable reading limit, it will be calculated as + 4096B */ + if (rlength > HW_TDO_BUF_SIZE) + rlength = HW_TDO_BUF_SIZE; + WI = 0; + + while (1) { + if (!CH347ReadData(ugIndex, (uint8_t *)oBuffer + WI, + &rlength)) { + LOG_ERROR("CH347_Read read data failure."); + return false; + } + + WI += rlength; + if (WI >= *ioLength) + break; + if ((*ioLength - WI) > HW_TDO_BUF_SIZE) + rlength = HW_TDO_BUF_SIZE; + else + rlength = *ioLength - WI; + } + LOG_DEBUG_IO("(size=%lu, buf=[%s]) -> %" PRIu32, WI, + HexToString((uint8_t *)oBuffer, WI), (uint32_t)WI); + *ioLength = WI; + return true; +} + +static void CH347_Read_Scan(UCHAR *pBuffer, uint32_t length) +{ + unsigned long read_size = 0; + unsigned long RxLen = 0; + unsigned long index = 0; + unsigned long read_buf_index = 0; + unsigned char *read_buf = NULL; + int dataLen = 0, i = 0; /*, this_bits = 0; */ + + read_size = length; + RxLen = read_size; + index = 0; + read_buf_index = 0; + read_buf = calloc(sizeof(unsigned char), read_size); + if (!CH347_Read(read_buf, &RxLen)) { + LOG_ERROR("CH347_Read read data failure."); + return; + } + while (index < read_size) { /* deal with the CH347_CMD_JTAG_BIT_OP_RD or CH347_CMD_JTAG_DATA_SHIFT_RD */ + if (read_buf[index] == CH347_CMD_JTAG_DATA_SHIFT_RD) { + dataLen = read_buf[++index] & 0xFF; + dataLen += (read_buf[++index] & 0xFF) << 8; + memcpy(pBuffer + read_buf_index, &read_buf[index + 1], + dataLen); + read_buf_index += dataLen; + index += dataLen + 1; + } else if (read_buf[index] == CH347_CMD_JTAG_BIT_OP_RD) { + dataLen = read_buf[++index] & 0xFF; + dataLen += (read_buf[++index] & 0xFF) << 8; + + for (i = 0; i < dataLen; i++) { + if (read_buf[index + 1 + i] & 1) + *(pBuffer + read_buf_index) |= (1 << i); + else + *(pBuffer + read_buf_index) &= ~(1 << i); + } + read_buf_index += 1; + index += dataLen + 1; + } else { + LOG_ERROR("readbuf read_commend error"); + *(pBuffer + read_buf_index) = read_buf[index]; + read_buf_index++; + index++; + } + } + if (read_buf) { + free(read_buf); + read_buf = NULL; + } +} + +static void CH347_Flush_Buffer(void) +{ + unsigned long retlen = ch347.buffer_idx; + int nb = ch347.buffer_idx, ret = ERROR_OK; + + while (ret == ERROR_OK && nb > 0) { + ret = CH347_Write(ch347.buffer, &retlen); + nb -= retlen; + } + memset(&ch347.buffer, 0, sizeof(ch347.buffer)); + ch347.buffer_idx = 0; + ch347.lastCmd = 0; + ch347.len_idx = 0; + ch347.len_value = 0; + + if (ch347.read_count == 0) + return; + if (ch347.pack_size == LARGER_PACK) { + CH347_Read_Scan(&ch347.read_buffer[0], ch347.read_count); + bit_copy_execute(&ch347.read_queue); + memset(ch347.read_buffer, 0, SF_PACKET_BUF_SIZE); + ch347.read_count = 0; + ch347.read_idx = 0; + } +} + +static void CH347_In_Buffer(uint8_t byte) +{ + if ((SF_PACKET_BUF_SIZE - ch347.buffer_idx) < 1) + CH347_Flush_Buffer(); + ch347.buffer[ch347.buffer_idx] = byte; + ch347.buffer_idx++; + if ((SF_PACKET_BUF_SIZE - ch347.buffer_idx) == 0) + CH347_Flush_Buffer(); +} + +static void CH347_In_Buffer_bytes(uint8_t *bytes, unsigned long bytes_length) +{ + if ((ch347.buffer_idx + bytes_length) > SF_PACKET_BUF_SIZE) + CH347_Flush_Buffer(); + memcpy(&ch347.buffer[ch347.buffer_idx], bytes, bytes_length); + ch347.buffer_idx += bytes_length; + if ((SF_PACKET_BUF_SIZE - ch347.buffer_idx) < 1) + CH347_Flush_Buffer(); +} + +static void combinePackets(uint8_t cmd, int cur_idx, unsigned long int len) +{ + if (cmd != ch347.lastCmd) { + ch347.buffer[cur_idx] = cmd; + ch347.buffer[cur_idx + 1] = + (uint8_t)(((len - CH347_CMD_HEADER) >> 0) & 0xFF); + ch347.buffer[cur_idx + 2] = + (uint8_t)(((len - CH347_CMD_HEADER) >> 8) & 0xFF); + + /* update the ch347 struct */ + ch347.lastCmd = cmd; + ch347.len_idx = cur_idx + 1; + ch347.len_value = (len - CH347_CMD_HEADER); + } else { + /* update the ch347 struct cmd data leng */ + ch347.len_value += (len - CH347_CMD_HEADER); + + /* update the cmd packet valid leng */ + ch347.buffer[ch347.len_idx] = (uint8_t)((ch347.len_value >> 0) \ + & 0xFF); + ch347.buffer[ch347.len_idx + 1] = (uint8_t)( + (ch347.len_value >> 8) & 0xFF); + + /* update the buffer data leng */ + memcpy(&ch347.buffer[cur_idx], + &ch347.buffer[cur_idx + CH347_CMD_HEADER], + (len - CH347_CMD_HEADER)); + + /* update the ch347 buffer index */ + ch347.buffer_idx -= CH347_CMD_HEADER; + } +} +/** + * CH347_ClockTms - Function function used to change the TMS value at the + * rising edge of TCK to switch its Tap state + * @param BitBangPkt Protocol package + * @param tms TMS value to be changed + * @param BI Protocol packet length + * + * @return Return protocol packet length + */ +static unsigned long CH347_ClockTms(int tms, unsigned long BI) +{ + uint8_t data = 0; + unsigned char cmd = 0; + + if (tms == 1) + cmd = TMS_H; + else + cmd = TMS_L; + + BI += 2; + + data = cmd | TDI_L | TCK_L | TRST_H; + CH347_In_Buffer(data); + data = cmd | TDI_L | TCK_H | TRST_H; + CH347_In_Buffer(data); + ch347.TMS = cmd; + ch347.TDI = TDI_L; + ch347.TCK = TCK_H; + ch347.TRST = TRST_H; + + return BI; +} + +/** + * CH347_IdleClock - Function function to ensure that the clock is in a low state + * @param BitBangPkt Protocol package + * @param BI Protocol packet length + * + * @return Return protocol packet length + */ +static unsigned long CH347_IdleClock(unsigned long BI) +{ + unsigned char byte = 0; + byte |= ch347.TMS ? TMS_H : TMS_L; + byte |= ch347.TDI ? TDI_H : TDI_L; + byte |= ch347.TRST ? TRST_H : TRST_L; + BI++; + CH347_In_Buffer(byte); + + return BI; +} + +/** + * CH347_TmsChange - Function function that performs state switching by changing the value of TMS + * @param tmsValue The TMS values that need to be switched form one byte of data in the switching order + * @param step The number of bit values that need to be read from the tmsValue value + * @param skip Count from the skip bit of tmsValue to step + * + */ +static void CH347_TmsChange(const unsigned char *tmsValue, int step, int skip) +{ + int i; + int index = ch347.buffer_idx; + unsigned long BI, retlen, cmdLen; + + BI = CH347_CMD_HEADER; + retlen = CH347_CMD_HEADER; + LOG_DEBUG_IO("(TMS Value: %02x..., step = %d, skip = %d)", tmsValue[0], + step, skip); + + for (i = 0; i < 3; i++) + CH347_In_Buffer(0); + + for (i = skip; i < step; i++) { + retlen = CH347_ClockTms((tmsValue[i / 8] >> (i % 8)) & 0x01, BI); + BI = retlen; + } + cmdLen = CH347_IdleClock(BI); + + combinePackets(CH347_CMD_JTAG_BIT_OP, index, cmdLen); +} + +/** + * CH347_TMS - By ch347_ execute_ Queue call + * @param cmd Upper layer transfer command parameters + * + */ +static void CH347_TMS(struct tms_command *cmd) +{ + LOG_DEBUG_IO("(step: %d)", cmd->num_bits); + CH347_TmsChange(cmd->bits, cmd->num_bits, 0); +} + +/** + * CH347_Reset - CH347 Reset Tap Status Function + * @brief If there are more than six consecutive TCKs and TMS is high, the state + * machine can be set to a Test-Logic-Reset state + * + */ +static int ch347_reset(int trst, int srst) +{ + LOG_DEBUG_IO("reset trst: %i srst %i", trst, srst); +#if 1 + unsigned char BitBang[512] = "", BII, i; + unsigned long TxLen; + + BII = CH347_CMD_HEADER; + for (i = 0; i < 7; i++) { + BitBang[BII++] = TMS_H | TDI_L | TCK_L; + BitBang[BII++] = TMS_H | TDI_L | TCK_H; + } + BitBang[BII++] = TMS_H | TDI_L | TCK_L; + + ch347.TCK = TCK_L; + ch347.TDI = TDI_L; + ch347.TMS = 0; + + BitBang[0] = CH347_CMD_JTAG_BIT_OP; + BitBang[1] = BII - CH347_CMD_HEADER; + BitBang[2] = 0; + + TxLen = BII; + + if (!CH347_Write(BitBang, &TxLen) && (TxLen != BII)) { + LOG_ERROR("JTAG_Init send usb data failure."); + return false; + } +#else + if (!swd_mode && trst == 0) { + + unsigned long int BI = 0; + + CH347_In_Buffer(CH347_CMD_JTAG_BIT_OP); + CH347_In_Buffer(0x01); + CH347_In_Buffer(0); + + ch347.TRST = 0; + CH347_IdleClock(BI); + + CH347_Flush_Buffer(); + + Sleep(50); + + CH347_In_Buffer(CH347_CMD_JTAG_BIT_OP); + CH347_In_Buffer(0x01); + CH347_In_Buffer(0); + + ch347.TRST = 1; + CH347_IdleClock(BI); + + CH347_Flush_Buffer(); + return ERROR_OK; + } +#endif + return ERROR_OK; +} + +/** + * CH347_MovePath - Obtain the current Tap status and switch to the status TMS + * value passed down by cmd + * @param cmd Upper layer transfer command parameters + * + */ +static void CH347_MovePath(struct pathmove_command *cmd) +{ + int i; + int index = ch347.buffer_idx; + unsigned long BI, retlen = 0, cmdLen; + + BI = CH347_CMD_HEADER; + + for (i = 0; i < 3; i++) + CH347_In_Buffer(0); + LOG_DEBUG_IO("(num_states=%d, last_state=%d)", + cmd->num_states, cmd->path[cmd->num_states - 1]); + + for (i = 0; i < cmd->num_states; i++) { + if (tap_state_transition(tap_get_state(), false) == + cmd->path[i]) + retlen = CH347_ClockTms(0, BI); + BI = retlen; + if (tap_state_transition(tap_get_state(), true) == cmd->path[i]) + retlen = CH347_ClockTms(1, BI); + BI = retlen; + tap_set_state(cmd->path[i]); + } + + cmdLen = CH347_IdleClock(BI); + + combinePackets(CH347_CMD_JTAG_BIT_OP, index, cmdLen); +} + +/** + * CH347_MoveState - Toggle the Tap state to the Target state stat + * @param stat Pre switch target path + * @param skip Number of digits to skip + * + */ +static void CH347_MoveState(tap_state_t state, int skip) +{ + uint8_t tms_scan; + int tms_len; + + LOG_DEBUG_IO("(from %s to %s)", tap_state_name(tap_get_state()), + tap_state_name(state)); + if (tap_get_state() == state) + return; + tms_scan = tap_get_tms_path(tap_get_state(), state); + tms_len = tap_get_tms_path_len(tap_get_state(), state); + CH347_TmsChange(&tms_scan, tms_len, skip); + tap_set_state(state); +} + +/** + * CH347_WriteRead - CH347 Batch read/write function + * @param bits Read and write data this time + * @param nb_bits Incoming data length + * @param scan The transmission method of incoming data to determine whether + * to perform data reading + */ +static void CH347_WriteRead(struct scan_command *cmd, uint8_t *bits, + int nb_bits, enum scan_type scan) +{ + int nb8 = nb_bits / 8; + int nb1 = nb_bits % 8; + int i, num_bits = 0; + bool IsRead = false; /*, isLastByte = false */ + uint8_t TMS_Bit = 0, TDI_Bit = 0, CMD_Bit; + static uint8_t byte0[SF_PACKET_BUF_SIZE]; + uint8_t *readData = calloc(SF_PACKET_BUF_SIZE, 1); + unsigned long readLen = 0; + unsigned long BI = 0, DI, DII, PktDataLen, DLen = 0, tempIndex, + totalReadLength = 0, tempLength = 0; + if (ch347.pack_size == LARGER_PACK) { + if ((ch347.read_count >= (USBC_PACKET_USBHS_SINGLE * 1))) + CH347_Flush_Buffer(); + } else { + CH347_Flush_Buffer(); + } + + if (nb8 > 0 && nb1 == 0) { + nb8--; + nb1 = 8; + } + + IsRead = (scan == SCAN_IN || scan == SCAN_IO); + DI = BI = 0; + while (DI < (unsigned long)nb8) { + if ((nb8 - DI) > UCMDPKT_DATA_MAX_BYTES_USBHS) + PktDataLen = UCMDPKT_DATA_MAX_BYTES_USBHS; + else + PktDataLen = nb8 - DI; + + DII = PktDataLen; + + if (IsRead) + CH347_In_Buffer(CH347_CMD_JTAG_DATA_SHIFT_RD); + else + CH347_In_Buffer(CH347_CMD_JTAG_DATA_SHIFT); + + /* packet data don't deal D3 & D4 */ + if ((CH347_CMD_JTAG_DATA_SHIFT_RD != ch347.lastCmd) | + (CH347_CMD_JTAG_DATA_SHIFT != ch347.lastCmd)) { + /* update the ch347 struct */ + ch347.lastCmd = 0; + ch347.len_idx = 0; + ch347.len_value = 0; + } + + CH347_In_Buffer((uint8_t)(PktDataLen >> 0) & 0xFF); + CH347_In_Buffer((uint8_t)(PktDataLen >> 8) & 0xFF); + + if (bits) + CH347_In_Buffer_bytes(&bits[DI], PktDataLen); + else + CH347_In_Buffer_bytes(byte0, PktDataLen); + DI += DII; + + tempLength += (DII + CH347_CMD_HEADER); + } + + totalReadLength += tempLength; + + if (IsRead) { + ch347.read_count += tempLength; + readLen += tempLength; + } + + if (bits) { + CMD_Bit = IsRead ? CH347_CMD_JTAG_BIT_OP_RD : \ + CH347_CMD_JTAG_BIT_OP; + DLen = (nb1 * 2) + 1; + + if (CMD_Bit != ch347.lastCmd) { + CH347_In_Buffer(CMD_Bit); + CH347_In_Buffer((uint8_t)(DLen >> 0) & 0xFF); + CH347_In_Buffer((uint8_t)(DLen >> 8) & 0xFF); + ch347.lastCmd = CMD_Bit; + ch347.len_idx = ch347.buffer_idx - 2; + ch347.len_value = DLen; + } else { + /* update the ch347 struct cmd data leng */ + ch347.len_value += DLen; + /* update the cmd packet valid leng */ + ch347.buffer[ch347.len_idx] = + (uint8_t)(ch347.len_value >> 0) & 0xFF; + ch347.buffer[ch347.len_idx + 1] = + (uint8_t)(ch347.len_value >> 8) & 0xFF; + } + + TMS_Bit = TMS_L; + for (i = 0; i < nb1; i++) { + if ((bits[nb8] >> i) & 0x01) + TDI_Bit = TDI_H; + else + TDI_Bit = TDI_L; + + if ((i + 1) == nb1) + TMS_Bit = TMS_H; + + CH347_In_Buffer(TMS_Bit | TDI_Bit | TCK_L | TRST_H); + CH347_In_Buffer(TMS_Bit | TDI_Bit | TCK_H | TRST_H); + } + CH347_In_Buffer(TMS_Bit | TDI_Bit | TCK_L | TRST_H); + } + + ch347.TMS = TMS_Bit; + ch347.TDI = TDI_Bit; + ch347.TCK = TCK_L; + + if (IsRead) { + tempLength = ((DLen / 2) + CH347_CMD_HEADER); + totalReadLength += tempLength; + ch347.read_count += tempLength; + readLen += tempLength; + DI = BI = 0; + } + int offset = 0, bit_count = 0; + if (IsRead && totalReadLength > 0) { + if (ch347.pack_size == STANDARD_PACK && bits && cmd) { + CH347_Flush_Buffer(); + CH347_Read_Scan(readData, readLen); + } + + for (i = 0; i < cmd->num_fields; i++) { + /* if neither in_value nor in_handler + * are specified we don't have to examine this field + */ + LOG_DEBUG("fields[%i].in_value[%i], offset: %d", + i, cmd->fields[i].num_bits, offset); + if (cmd->fields[i].in_value) { + num_bits = cmd->fields[i].num_bits; + + if (ch347.pack_size == LARGER_PACK) { + bit_count += num_bits; + if (cmd->fields[i].in_value) + bit_copy_queued( + &ch347.read_queue, + cmd->fields[i].in_value, + 0, + &ch347.read_buffer[ch347.read_idx], + offset, num_bits); + + if (num_bits > 7) + ch347.read_idx += + DIV_ROUND_UP(bit_count, + 8); + offset += num_bits; + } else { + uint8_t *captured = buf_set_buf( + readData, bit_count, + malloc(DIV_ROUND_UP(num_bits, + 8)), 0, + num_bits); + + if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) { + char *char_buf = + buf_to_hex_str( + captured, + (num_bits > + DEBUG_JTAG_IOZ) + ? DEBUG_JTAG_IOZ + : num_bits); + free(char_buf); + } + if (cmd->fields[i].in_value) + buf_cpy(captured, + cmd->fields[i].in_value, + num_bits); + free(captured); + } + bit_count += cmd->fields[i].num_bits; + } + } + } + + tempIndex = ch347.buffer_idx; + for (i = 0; i < CH347_CMD_HEADER; i++) + CH347_In_Buffer(0); + BI = CH347_CMD_HEADER; + BI = CH347_IdleClock(BI); + + combinePackets(CH347_CMD_JTAG_BIT_OP, tempIndex, BI); + if (readData) { + free(readData); + readData = NULL; + } +} + +static void CH347_RunTest(int cycles, tap_state_t state) +{ + LOG_DEBUG_IO("%s(cycles=%i, end_state=%d)", __func__, cycles, state); + if (tap_get_state() != TAP_IDLE) + CH347_MoveState(TAP_IDLE, 0); + + uint8_t tmsValue = 0; + CH347_TmsChange(&tmsValue, 7, 1); + + CH347_WriteRead(NULL, NULL, cycles, SCAN_OUT); + CH347_MoveState(state, 0); +} + +static void CH347_TableClocks(int cycles) +{ + LOG_DEBUG_IO("%s(cycles=%i)", __func__, cycles); + CH347_WriteRead(NULL, NULL, cycles, SCAN_OUT); +} + +/** + * CH347_Scan - Switch to SHIFT-DR or SHIFT-IR status for scanning + * @param cmd Upper layer transfer command parameters + * + * @return Success returns ERROR_OK + */ +static int CH347_Scan(struct scan_command *cmd) +{ + int scan_bits; + uint8_t *buf = NULL; + enum scan_type type; + int ret = ERROR_OK; + static const char *const type2str[] = { + "", "SCAN_IN", "SCAN_OUT", "SCAN_IO" + }; + char *log_buf = NULL; + + type = jtag_scan_type(cmd); + scan_bits = jtag_build_buffer(cmd, &buf); + + if (cmd->ir_scan) + CH347_MoveState(TAP_IRSHIFT, 0); + else + CH347_MoveState(TAP_DRSHIFT, 0); + + log_buf = HexToString(buf, DIV_ROUND_UP(scan_bits, 8)); + LOG_DEBUG_IO("Scan"); + LOG_DEBUG_IO("%s(scan=%s, type=%s, bits=%d, buf=[%s], end_state=%d)", + __func__, + cmd->ir_scan ? "IRSCAN" : "DRSCAN", + type2str[type], + scan_bits, log_buf, cmd->end_state); + + free(log_buf); + + CH347_WriteRead(cmd, buf, scan_bits, type); + + free(buf); + + CH347_MoveState(cmd->end_state, 1); + + return ret; +} + +static void CH347_Sleep(int us) +{ + LOG_DEBUG_IO("%s(us=%d)", __func__, us); + jtag_sleep(us); +} + +static int ch347_execute_queue(void) +{ + struct jtag_command *cmd; + int ret = ERROR_OK; + + for (cmd = jtag_command_queue; ret == ERROR_OK && cmd; + cmd = cmd->next) { + switch (cmd->type) { + case JTAG_RESET: + LOG_DEBUG_IO("JTAG_RESET : %d %d.\n", + cmd->cmd.reset->trst, + cmd->cmd.reset->srst); + ch347_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); + break; + case JTAG_RUNTEST: + CH347_RunTest(cmd->cmd.runtest->num_cycles, + cmd->cmd.runtest->end_state); + break; + case JTAG_STABLECLOCKS: + CH347_TableClocks(cmd->cmd.stableclocks->num_cycles); + break; + case JTAG_TLR_RESET: + CH347_MoveState(cmd->cmd.statemove->end_state, 0); + break; + case JTAG_PATHMOVE: + CH347_MovePath(cmd->cmd.pathmove); + break; + case JTAG_TMS: + CH347_TMS(cmd->cmd.tms); + break; + case JTAG_SLEEP: + CH347_Sleep(cmd->cmd.sleep->us); + break; + case JTAG_SCAN: + ret = CH347_Scan(cmd->cmd.scan); + break; + default: + LOG_ERROR("BUG: unknown JTAG command type 0x%X", + cmd->type); + ret = ERROR_FAIL; + break; + } + } + + CH347_Flush_Buffer(); + return ret; +} + +/** + * ch347_init - CH347 Initialization function + * + * Todo: + * Initialize dynamic library functions + * Open Device + * @return Success returns 0, failure returns ERROR_FAIL + */ +static int ch347_init(void) +{ +#ifdef _WIN32 + if (uhModule == 0) { + uhModule = LoadLibrary("CH347DLL.DLL"); + if (uhModule) { + CH347OpenDevice = (pCH347OpenDevice)GetProcAddress( + uhModule, "CH347OpenDevice"); + CH347CloseDevice = (pCH347CloseDevice)GetProcAddress( + uhModule, "CH347CloseDevice"); + CH347ReadData = (pCH347ReadData)GetProcAddress( + uhModule, "CH347ReadData"); + CH347WriteData = (pCH347WriteData)GetProcAddress( + uhModule, "CH347WriteData"); + CH347SetTimeout = (pCH347SetTimeout)GetProcAddress( + uhModule, "CH347SetTimeout"); + if (CH347OpenDevice == NULL || CH347CloseDevice == NULL + || CH347SetTimeout == NULL || CH347ReadData == NULL + || CH347WriteData == NULL) { + LOG_ERROR("Jtag_init error "); + return ERROR_FAIL; + } + } + } + DevIsOpened = CH347OpenDevice(ugIndex); +#elif defined(__linux__) + DevIsOpened = CH347OpenDevice(ugIndex); + ugIndex = DevIsOpened; +#endif + if (DevIsOpened == -1) { + LOG_ERROR("CH347 Open Error."); + return ERROR_FAIL; + } else { + LOG_INFO("CH347 Open Succ."); + } + + if (!swd_mode) { + USBC_PACKET = USBC_PACKET_USBHS; + /* ch347 init */ + ch347.TCK = 0; + ch347.TMS = 0; + ch347.TDI = 0; + ch347.TRST = TRST_H; + ch347.buffer_idx = 0; + + memset(&ch347.buffer, 0, SF_PACKET_BUF_SIZE); + ch347.len_idx = 0; + ch347.len_value = 0; + ch347.lastCmd = 0; + + memset(&ch347.read_buffer, 0, SF_PACKET_BUF_SIZE); + ch347.read_count = 0; + ch347.read_idx = 0; + + bit_copy_queue_init(&ch347.read_queue); + + /* CH347SetTimeout(ugIndex, 500, 500); */ + + tap_set_state(TAP_RESET); + } else { /* swd init */ + CH347SWD_INIT(ugIndex, 1); + } + return 0; +} + +/** + * ch347_quit - CH347 Device Release Function + * + * Todo: + * Reset JTAG pin signal + * Close + * @return always returns 0 + */ +static int ch347_quit(void) +{ + unsigned long retlen = 4; + uint8_t byte[4] = {CH347_CMD_JTAG_BIT_OP, 0x01, 0x00, ch347.TRST}; + if (!swd_mode) { + CH347_Write(byte, &retlen); + bit_copy_discard(&ch347.read_queue); + } + if (DevIsOpened) { + CH347CloseDevice(ugIndex); + LOG_INFO("Close the CH347."); + DevIsOpened = false; + } + return 0; +} + +static bool Check_Speed(uint64_t iIndex, uint8_t iClockRate) +{ + unsigned long int i = 0, j; + bool retVal; + uint8_t cmdBuf[32] = ""; + cmdBuf[i++] = CH347_CMD_JTAG_INIT; + cmdBuf[i++] = 6; + cmdBuf[i++] = 0; + + cmdBuf[i++] = 0; + cmdBuf[i++] = iClockRate; + + for (j = 0; j < 4; j++) + cmdBuf[i++] = ch347.TCK | ch347.TDI | ch347.TMS | ch347.TRST; + + unsigned long int mLength = i; + if (!CH347WriteData(iIndex, cmdBuf, &mLength) || (mLength != i)) + return false; + + mLength = 4; + memset(cmdBuf, 0, sizeof(cmdBuf)); + + if (!CH347ReadData(iIndex, cmdBuf, &mLength) || (mLength != 4)) + return false; + + retVal = ((cmdBuf[0] == CH347_CMD_JTAG_INIT) && \ + (cmdBuf[CH347_CMD_HEADER] == 0)); + return retVal; +} + +static bool CH347Jtag_INIT(uint64_t iIndex, uint8_t iClockRate) +{ + ch347.pack_size = (Check_Speed(iIndex, 0x09) == true) ? \ + STANDARD_PACK : LARGER_PACK; + if (ch347.pack_size == STANDARD_PACK) { + if (iClockRate - 2 < 0) + return Check_Speed(iIndex, 0); + else + return Check_Speed(iIndex, iClockRate - 2); + } + + return Check_Speed(iIndex, iClockRate); +} + +/** + * ch347_speed - CH347 TCK frequency setting + * @param speed Frequency size set + * @return Success returns ERROR_OK,failed returns FALSE + */ +static int ch347_speed(int speed) +{ + unsigned long i = 0; + uint8_t clockRate; + int retval = -1; + int speed_clock[8] = { + KHZ(468.75), KHZ(937.5), MHZ(1.875), + MHZ(3.75), MHZ(7.5), MHZ(15), MHZ(30), MHZ(60) + }; + + if (!swd_mode) { + for (i = 0; i < (sizeof(speed_clock) / sizeof(int)); i++) { + if ((speed >= speed_clock[i]) && + (speed <= speed_clock[i + 1])) { + clockRate = i + 1; + retval = CH347Jtag_INIT(ugIndex, clockRate); + if (!retval) { + LOG_ERROR("Couldn't set CH347 TCK speed"); + return retval; + } else { + break; + } + } else if (speed < speed_clock[0]) { + retval = CH347Jtag_INIT(ugIndex, 0); + if (!retval) { + LOG_ERROR("Couldn't set CH347 TCK speed"); + return retval; + } else { + break; + } + } + } + } + return ERROR_OK; +} + +static int ch347_speed_div(int speed, int *khz) +{ + *khz = speed / 1000; + return ERROR_OK; +} + +static int ch347_khz(int khz, int *jtag_speed) +{ + if (khz == 0) { + LOG_ERROR("Couldn't support the adapter speed"); + return ERROR_FAIL; + } + *jtag_speed = khz * 1000; + return ERROR_OK; +} + +static int ch347_trst_out(unsigned char status) +{ + unsigned long int BI = 0; + unsigned char byte = 0; + unsigned char cmdPacket[4] = ""; + cmdPacket[BI++] = CH347_CMD_JTAG_BIT_OP; + cmdPacket[BI++] = 0x01; + cmdPacket[BI++] = 0; + byte = ch347.TCK | ch347.TDI | ch347.TMS | (ch347.TRST = + (status ? TRST_H : TRST_L)); + cmdPacket[BI++] = byte; + + if (!CH347_Write(cmdPacket, &BI)) { + LOG_ERROR("TRST set failure."); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +COMMAND_HANDLER(ch347_handle_vid_pid_command) +{ + /* TODO */ + return ERROR_OK; +} + +COMMAND_HANDLER(ch347_trst) +{ + ch347_trst_out(TRST_L); + jtag_sleep(atoi(CMD_ARGV[0]) * 1000); + ch347_trst_out(TRST_H); + return ERROR_OK; +} + +static const struct command_registration ch347_subcommand_handlers[] = { + { + .name = "vid_pid", + .handler = &ch347_handle_vid_pid_command, + .mode = COMMAND_CONFIG, + .help = "", + .usage = "", + }, + { + .name = "jtag_ntrst_delay", + .handler = &ch347_trst, + .mode = COMMAND_ANY, + .help = "set the trst of the CH347 device that is used as JTAG", + .usage = "[milliseconds]", + }, + + COMMAND_REGISTRATION_DONE}; + +static const struct command_registration ch347_command_handlers[] = { + { + .name = "ch347", + .mode = COMMAND_ANY, + .help = "perform ch347 management", + .chain = ch347_subcommand_handlers, + .usage = "", + }, + COMMAND_REGISTRATION_DONE}; + +static int ch347_swd_init(void) +{ + PCH347_SWD_IO pswd_io; + LOG_INFO("CH347 SWD mode enabled"); + swd_mode = true; + memset(&ch347_swd_context, 0, sizeof(ch347_swd_context)); + + INIT_LIST_HEAD(&ch347_swd_context.send_cmd_head); + INIT_LIST_HEAD(&ch347_swd_context.free_cmd_head); + + ch347_swd_context.queued_retval = ERROR_OK; + /* 0XE8 + 2byte len + N byte cmds */ + ch347_swd_context.send_len = CH347_CMD_HEADER; + /* 0XE8 + 2byte len + N byte ack + data */ + ch347_swd_context.need_recv_len = CH347_CMD_HEADER; + ch347_swd_context.ch347_cmd_buf = malloc(128 * sizeof(CH347_SWD_IO)); + if (ch347_swd_context.ch347_cmd_buf) { + pswd_io = (PCH347_SWD_IO)ch347_swd_context.ch347_cmd_buf; + for (int i = 0; i < 128; i++, pswd_io++) { + INIT_LIST_HEAD(&pswd_io->list_entry); + list_add_tail(&pswd_io->list_entry, + &ch347_swd_context.free_cmd_head); + } + } + return ch347_swd_context.ch347_cmd_buf ? ERROR_OK : ERROR_FAIL; +} + +static PCH347_SWD_IO ch347_get_one_swd_io(void) +{ + PCH347_SWD_IO pswd_io; + if (list_empty(&ch347_swd_context.free_cmd_head)) { + return NULL; + } else { + pswd_io = list_first_entry(&ch347_swd_context.free_cmd_head, + CH347_SWD_IO, list_entry); + list_del_init(&pswd_io->list_entry); + pswd_io->cmd = 0; + pswd_io->usbcmd = CH347_CMD_SWD_SEQ_W; + pswd_io->dst = NULL; + return pswd_io; + } +} + +static void ch347_swd_queue_flush(void) +{ + unsigned long mLength = ch347_swd_context.send_len; + ch347_swd_context.send_buf[0] = (uint8_t)CH347_CMD_SWD; + ch347_swd_context.send_buf[1] = (uint8_t)(ch347_swd_context.send_len - + CH347_CMD_HEADER); + ch347_swd_context.send_buf[2] = (uint8_t)((ch347_swd_context.send_len - + CH347_CMD_HEADER) >> 8); + if (!CH347WriteData(ugIndex, ch347_swd_context.send_buf, &mLength) || + (mLength != ch347_swd_context.send_len)) { + ch347_swd_context.queued_retval = ERROR_FAIL; + LOG_DEBUG("CH347WriteData error "); + return; + } + ch347_swd_context.recv_len = 0; + do { + mLength = CH347_MAX_RECV_BUF - ch347_swd_context.recv_len; + if (!CH347ReadData(ugIndex, + &ch347_swd_context.recv_buf[ch347_swd_context.recv_len], + &mLength)) { + ch347_swd_context.queued_retval = ERROR_FAIL; + LOG_DEBUG("CH347ReadData error "); + return; + } + ch347_swd_context.recv_len += mLength; + } while (ch347_swd_context.recv_len < ch347_swd_context.need_recv_len); + + if (ch347_swd_context.need_recv_len > ch347_swd_context.recv_len) { + LOG_ERROR("ch347_swd_queue_flush write/read failed %d %d %d", + __LINE__, + ch347_swd_context.recv_len, + ch347_swd_context.need_recv_len); + } +} +static void ch347_wrtie_swd_reg(uint8_t cmd, const uint8_t *out, uint8_t parity) +{ + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = + CH347_CMD_SWD_REG_W; + /* 8bit + 32bit +1bit */ + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = 0x29; + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = 0x00; + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = cmd; + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = out[0]; + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = out[1]; + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = out[2]; + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = out[3]; + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = parity; + /* 0xA0 + 1 byte(3bit ACK) */ + ch347_swd_context.need_recv_len += (1 + 1); +} + +static void ch347_wrtie_spec_seq(const uint8_t *out, uint8_t out_len) +{ + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = + CH347_CMD_SWD_SEQ_W; + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = out_len; + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = 0x00; + for (uint8_t i = 0; i < DIV_ROUND_UP(out_len, 8); i++) { + if (out) { + ch347_swd_context.send_buf[ch347_swd_context.send_len++] + = out[i]; + } else { + ch347_swd_context.send_buf[ch347_swd_context.send_len++] + = 0x00; + } + } + ch347_swd_context.need_recv_len += 1; /* 0xA1 */ +} + +static void ch347_read_swd_reg(uint8_t cmd) +{ + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = + CH347_CMD_SWD_REG_R; + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = 0x22; + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = 0x00; + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = cmd; + /* 0xA2 + 1 byte(3bit ACK) + 4 byte(data) + + 1 byte(1bit parity+1bit trn) */ + ch347_swd_context.need_recv_len += 1 + 1 + 4 + 1; +} + +static int ch347_swd_switch_out(enum swd_special_seq seq, const uint8_t *out, + unsigned out_len) +{ + PCH347_SWD_IO pswd_io; + if ((ch347_swd_context.send_len + + (1 + 2 + DIV_ROUND_UP(out_len, 8))) > CH347_MAX_SEND_BUF) { + return ERROR_FAIL; + } + if ((ch347_swd_context.need_recv_len + 2) > CH347_MAX_RECV_BUF) + return ERROR_FAIL; + + pswd_io = ch347_get_one_swd_io(); + if (pswd_io) { + ch347_wrtie_spec_seq(out, out_len); + list_add_tail(&pswd_io->list_entry, + &ch347_swd_context.send_cmd_head); + return ERROR_OK; + } else { + return ERROR_FAIL; + } +} + +/* check read/write REG can fill in remaining buff */ +static bool ch347_chk_buf_size(uint8_t cmd, uint32_t ap_delay_clk) +{ + bool bflush; + uint32_t send_len, recv_len, len; + bflush = false; + send_len = ch347_swd_context.send_len; + recv_len = ch347_swd_context.need_recv_len; + do { + + if (cmd & SWD_CMD_RNW) { + len = 1 + 1 + 1 + 1; /* 0xA2 + len + rev + cmd */ + if (send_len + len > CH347_MAX_SEND_BUF) + break; + send_len += len; + len = 1 + 1 + 4 + 1; + /* 0xA2 + 1byte(3bit ack) + 4byte(data) + + 1byte(1bit parity+1bit trn) */ + if (recv_len + len > CH347_MAX_RECV_BUF) + break; + recv_len += len; + } else { /* write reg */ + len = 1 + 1 + 1 + 1 + 4 + 1; + /* 0xA0 + len + rev + cmd +data + parity */ + if (send_len + len > CH347_MAX_SEND_BUF) + break; + send_len += len; + len = 1 + 1; /* 0xA0 + 1byte(3bit ack) */ + if (recv_len + len > CH347_MAX_RECV_BUF) + break; + recv_len += len; + } + if (cmd & SWD_CMD_APNDP) { + len = 1 + 1 + 1 + DIV_ROUND_UP(ap_delay_clk, 8); + /* 0xA1 + Len + rev + n byte(delay) */ + if (send_len + len > CH347_MAX_SEND_BUF) + break; + len = 1; /* 0xA1 */ + if ((recv_len + len) > CH347_MAX_RECV_BUF) + break; + } + /* swd packet requests */ + bflush = true; + } while (false); + + return bflush; +} + +static void ch347_swd_send_idle(uint32_t ap_delay_clk) +{ + PCH347_SWD_IO pswd_io; + + pswd_io = ch347_get_one_swd_io(); + if (!pswd_io) { + ch347_swd_run_queue(); + pswd_io = ch347_get_one_swd_io(); + if (!pswd_io) { + LOG_DEBUG("ch347_swd_queue_cmd error "); + ch347_swd_context.queued_retval = ERROR_FAIL; + return; + } + } + ch347_wrtie_spec_seq(NULL, ap_delay_clk); + + list_add_tail(&pswd_io->list_entry, &ch347_swd_context.send_cmd_head); +} + +static void ch347_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, + uint32_t ap_delay_clk) +{ + PCH347_SWD_IO pswd_io; + if (ap_delay_clk > 255) + printf("ch347_swd_queue_cmd ap_delay_clk = %d\r\n", + ap_delay_clk); + + if (ch347_swd_context.sent_cmd_count >= CH347_MAX_SEND_CMD) + ch347_swd_run_queue(); + + if (!ch347_chk_buf_size(cmd, ap_delay_clk)) + ch347_swd_run_queue(); + + pswd_io = ch347_get_one_swd_io(); + if (!pswd_io) { + ch347_swd_run_queue(); + pswd_io = ch347_get_one_swd_io(); + if (!pswd_io) { + LOG_DEBUG("ch347_swd_queue_cmd error "); + ch347_swd_context.queued_retval = ERROR_FAIL; + return; + } + } + + pswd_io->cmd = cmd | SWD_CMD_START | SWD_CMD_PARK; + + if (pswd_io->cmd & SWD_CMD_RNW) { + pswd_io->usbcmd = CH347_CMD_SWD_REG_R; + pswd_io->dst = dst; + ch347_read_swd_reg(pswd_io->cmd); + } else { + pswd_io->usbcmd = CH347_CMD_SWD_REG_W; + pswd_io->value = data; + ch347_wrtie_swd_reg(pswd_io->cmd, (uint8_t *)&data, + parity_u32(data)); + } + + ch347_swd_context.sent_cmd_count++; + list_add_tail(&pswd_io->list_entry, &ch347_swd_context.send_cmd_head); + /* Insert idle cycles after AP accesses to avoid WAIT */ + if (cmd & SWD_CMD_APNDP) { + if (ap_delay_clk == 0) + printf("ap_delay_clk == 0"); + ch347_swd_send_idle(ap_delay_clk); + } +} + +static int ch347_swd_switch_seq(enum swd_special_seq seq) +{ + printf("ch347_swd_switch_seq %d \r\n", seq); + switch (seq) { + case LINE_RESET: + LOG_DEBUG("SWD line reset"); + return ch347_swd_switch_out(seq, swd_seq_line_reset, + swd_seq_line_reset_len); + case JTAG_TO_SWD: + LOG_DEBUG("JTAG-to-SWD"); + return ch347_swd_switch_out(seq, swd_seq_jtag_to_swd, + swd_seq_jtag_to_swd_len); + case JTAG_TO_DORMANT: + LOG_DEBUG("JTAG-to-DORMANT"); + return ch347_swd_switch_out(seq, swd_seq_jtag_to_dormant, + swd_seq_jtag_to_dormant_len); + case SWD_TO_JTAG: + LOG_DEBUG("SWD-to-JTAG"); + return ch347_swd_switch_out(seq, swd_seq_swd_to_jtag, + swd_seq_swd_to_jtag_len); + case SWD_TO_DORMANT: + LOG_DEBUG("SWD-to-DORMANT"); + return ch347_swd_switch_out(seq, swd_seq_swd_to_dormant, + swd_seq_swd_to_dormant_len); + case DORMANT_TO_SWD: + LOG_DEBUG("DORMANT-to-SWD"); + return ch347_swd_switch_out(seq, swd_seq_dormant_to_swd, + swd_seq_dormant_to_swd_len); + case DORMANT_TO_JTAG: + LOG_DEBUG("DORMANT-to-JTAG"); + return ch347_swd_switch_out(seq, swd_seq_dormant_to_jtag, + swd_seq_dormant_to_jtag_len); + default: + LOG_ERROR("Sequence %d not supported", seq); + return ERROR_FAIL; + } +} + +static void ch347_swd_read_reg(uint8_t cmd, uint32_t *value, + uint32_t ap_delay_clk) +{ + assert(cmd & SWD_CMD_RNW); + ch347_swd_queue_cmd(cmd, value, 0, ap_delay_clk); +} + +static void ch347_swd_write_reg(uint8_t cmd, uint32_t value, + uint32_t ap_delay_clk) +{ + assert(!(cmd & SWD_CMD_RNW)); + ch347_swd_queue_cmd(cmd, NULL, value, ap_delay_clk); +} + +static int ch347_swd_run_queue(void) +{ + LOG_DEBUG_IO("Executing %u queued transactions", + ch347_swd_context.sent_cmd_count); + int retval, parity; + struct list_head *tmp, *pos; + uint8_t *recv_buf; + uint32_t recv_len, cmds_len, data; + PCH347_SWD_IO pswd_io; + if (ch347_swd_context.queued_retval != ERROR_OK) { + LOG_DEBUG_IO("Skipping due to previous errors: %d", + ch347_swd_context.queued_retval); + goto skip; + } + + /* A transaction must be followed by another transaction or at least 8 + idle cycles to ensure that data is clocked through the AP. */ + if ((ch347_swd_context.send_len + (1 + 2 + 1)) > CH347_MAX_SEND_BUF) + goto skip_idle; + + if ((ch347_swd_context.need_recv_len + 1) > CH347_MAX_RECV_BUF) + goto skip_idle; + + ch347_swd_send_idle(8); + +skip_idle: + + ch347_swd_queue_flush(); + + if (ch347_swd_context.queued_retval != ERROR_OK) { + LOG_ERROR("CH347 usb write/read failed %d", __LINE__); + goto skip; + } + recv_buf = ch347_swd_context.recv_buf; + recv_len = 0; + if (recv_buf[recv_len++] != CH347_CMD_SWD) { /* 0XE8 */ + ch347_swd_context.queued_retval = ERROR_FAIL; + LOG_ERROR("CH347 usb write/read failed %d", __LINE__); + goto skip; + } + + cmds_len = BUILD_UINT16(recv_buf[recv_len], recv_buf[recv_len + 1]); + recv_len += 2; /* cmds_len */ + if ((cmds_len + CH347_CMD_HEADER) > ch347_swd_context.recv_len) { + ch347_swd_context.queued_retval = ERROR_FAIL; + LOG_ERROR("CH347 usb write/read failed %d", __LINE__); + goto skip; + } + + list_for_each_safe(pos, tmp, &ch347_swd_context.send_cmd_head) { + pswd_io = list_entry(pos, CH347_SWD_IO, list_entry); + if (pswd_io->usbcmd == CH347_CMD_SWD_SEQ_W) { + if (recv_buf[recv_len++] != CH347_CMD_SWD_SEQ_W) { + ch347_swd_context.queued_retval = ERROR_FAIL; + LOG_ERROR("CH347 usb write/read failed %d", + __LINE__); + goto skip; + } + } else { /* read/write Reg */ + int ack; + bool check_ack; + /* read Reg */ + if (recv_buf[recv_len] == CH347_CMD_SWD_REG_R) { + recv_len++; + ack = buf_get_u32(&recv_buf[recv_len++], 0, 3); + /* Devices do not reply to DP_TARGETSEL write + cmd, ignore received ack */ + check_ack = swd_cmd_returns_ack(pswd_io->cmd); + if (ack != SWD_ACK_OK && check_ack) { + ch347_swd_context.queued_retval = + swd_ack_to_error_code(ack); + LOG_ERROR("ack != SWD_ACK_OK %d", + __LINE__); + goto skip; + } + if (pswd_io->cmd & SWD_CMD_RNW) { + data = buf_get_u32(&recv_buf[recv_len], + 0, 32); + parity = buf_get_u32( + &recv_buf[recv_len], 32, 1); + if (parity != parity_u32(data)) { + LOG_ERROR("SWD Read data parity mismatch %d", + __LINE__); + ch347_swd_context.queued_retval = ERROR_FAIL; + goto skip; + } + + LOG_DEBUG_IO("%s%s %s %s reg %X = %08X\n" PRIx32, + check_ack ? "" : "ack ignored ", + ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : \ + ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", + pswd_io->cmd & SWD_CMD_APNDP ? "AP" : "DP", + pswd_io->cmd & SWD_CMD_RNW ? "read" : "write", + (pswd_io->cmd & SWD_CMD_A32) >> 1, + data); + + if (pswd_io->dst) + *pswd_io->dst = data; + } else { + ch347_swd_context.queued_retval = + ERROR_FAIL; + LOG_ERROR("CH347 usb write/read failed %d", __LINE__); + goto skip; + } + recv_len += 5; + } else if (recv_buf[recv_len] == CH347_CMD_SWD_REG_W) { + recv_len++; + ack = buf_get_u32(&recv_buf[recv_len++], 0, 3); + /* Devices do not reply to DP_TARGETSEL write + cmd, ignore received ack */ + check_ack = swd_cmd_returns_ack(pswd_io->cmd); + if (ack != SWD_ACK_OK && check_ack) { + ch347_swd_context.queued_retval = + swd_ack_to_error_code(ack); + LOG_ERROR("SWD Read data parity mismatch%d", __LINE__); + goto skip; + } + LOG_DEBUG_IO("%s%s %s %s reg %X = %08X\n" PRIx32, + check_ack ? "" : "ack ignored ", + ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : \ + ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", + pswd_io->cmd & SWD_CMD_APNDP ? "AP" : "DP", + pswd_io->cmd & SWD_CMD_RNW ? "read" : "write", + (pswd_io->cmd & SWD_CMD_A32) >> 1, + pswd_io->value); + } else { + ch347_swd_context.queued_retval = ERROR_FAIL; + LOG_ERROR("CH347 usb write/read failed %d recv_len = %d", + __LINE__, recv_len); + goto skip; + } + } + list_del_init(&pswd_io->list_entry); + list_add_tail(&pswd_io->list_entry, + &ch347_swd_context.free_cmd_head); + } + +skip: + if (!list_empty(&ch347_swd_context.send_cmd_head)) { + list_for_each_safe(pos, tmp, &ch347_swd_context.send_cmd_head) + { + pswd_io = list_entry(pos, CH347_SWD_IO, list_entry); + list_del_init(&pswd_io->list_entry); + list_add_tail(&pswd_io->list_entry, + &ch347_swd_context.free_cmd_head); + } + } + /* 0xE8 + 2byte len */ + ch347_swd_context.send_len = CH347_CMD_HEADER; + /* 0xE8 + 2byte len */ + ch347_swd_context.need_recv_len = CH347_CMD_HEADER; + ch347_swd_context.recv_len = 0; + ch347_swd_context.sent_cmd_count = 0; + retval = ch347_swd_context.queued_retval; + ch347_swd_context.queued_retval = ERROR_OK; + + return retval; +} + +static const struct swd_driver ch347_swd = { + .init = ch347_swd_init, + .switch_seq = ch347_swd_switch_seq, + .read_reg = ch347_swd_read_reg, + .write_reg = ch347_swd_write_reg, + .run = ch347_swd_run_queue, +}; + +static const char *const ch347_transports[] = {"jtag", "swd", NULL}; + +static struct jtag_interface ch347_interface = { + .supported = DEBUG_CAP_TMS_SEQ, + .execute_queue = ch347_execute_queue, +}; + +struct adapter_driver ch347_adapter_driver = { + .name = "ch347", + .transports = ch347_transports, + .commands = ch347_command_handlers, + + .init = ch347_init, + .quit = ch347_quit, + .reset = ch347_reset, + .speed = ch347_speed, + .khz = ch347_khz, + .speed_div = ch347_speed_div, + + .jtag_ops = &ch347_interface, + .swd_ops = &ch347_swd, +}; diff --git a/src/jtag/interface.h b/src/jtag/interface.h old mode 100644 new mode 100755 index 69c09483e2..c27bc136cf --- a/src/jtag/interface.h +++ b/src/jtag/interface.h @@ -402,5 +402,5 @@ extern struct adapter_driver xds110_adapter_driver; extern struct adapter_driver xlnx_pcie_xvc_adapter_driver; extern struct adapter_driver esp_remote_adapter_driver; extern struct adapter_driver esp_gpio_adapter_driver; - +extern struct adapter_driver ch347_adapter_driver; #endif /* OPENOCD_JTAG_INTERFACE_H */ diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c old mode 100644 new mode 100755 index 94472c4b79..27b554894a --- a/src/jtag/interfaces.c +++ b/src/jtag/interfaces.c @@ -155,6 +155,9 @@ struct adapter_driver *adapter_drivers[] = { #endif #if BUILD_ESP_GPIO &esp_gpio_adapter_driver, +#endif +#if BUILD_CH347 == 1 + &ch347_adapter_driver, #endif NULL, }; diff --git a/tcl/interface/easydevkits-wch.cfg b/tcl/interface/easydevkits-wch.cfg new file mode 100755 index 0000000000..f399687ee3 --- /dev/null +++ b/tcl/interface/easydevkits-wch.cfg @@ -0,0 +1,4 @@ +adapter driver ch347 +ch347 vid_pid 0x1a86 0x55dd + +adapter speed 10000 diff --git a/tcl/interface/ftdi/easydevkits-ftdi.cfg b/tcl/interface/ftdi/easydevkits-ftdi.cfg new file mode 100755 index 0000000000..7001d8f8ed --- /dev/null +++ b/tcl/interface/ftdi/easydevkits-ftdi.cfg @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Driver for the FT2232H JTAG chip on the EasyDevKits JTAG Adapter +# + +adapter driver ftdi +ftdi device_desc "EasyDevKit" +ftdi vid_pid 0x0403 0x6010 + +# interface 0 is JTAG; interface 1 is the uart +ftdi channel 0 + +# TCK, TDI, TDO, TMS: ADBUS0-3 +# LED: ADBUS4 +ftdi layout_init 0x0008 0x001b +ftdi layout_signal LED -data 0x0010 + +# The speed of the JTAG interface, in kHz. If you get DSR/DIR errors (and they +# do not relate to OpenOCD trying to read from a memory range without physical +# memory being present there), you can try lowering this. +# +# On EasyDevKits, this can go as high as 20MHz if CPU frequency is 80MHz, +# or 26MHz if CPU frequency is 160MHz or 240MHz. +adapter speed 20000 From b3930db4e501536a6dcfd5f6cda13f7996b0f3b2 Mon Sep 17 00:00:00 2001 From: EasyDevKits Date: Sun, 1 Oct 2023 00:01:52 +0200 Subject: [PATCH 02/22] Configuration of CH347 vid/pid, device description, activity LED added jtag_libusb_open enhanced for checking the device description --- src/jtag/drivers/angie.c | 2 +- src/jtag/drivers/arm-jtag-ew.c | 2 +- src/jtag/drivers/ch347.c | 58 +++++++++++++++++-- src/jtag/drivers/esp_usb_jtag.c | 2 +- src/jtag/drivers/ft232r.c | 2 +- src/jtag/drivers/jtag_esp_remote.c | 2 +- src/jtag/drivers/kitprog.c | 2 +- src/jtag/drivers/libusb_helper.c | 13 ++++- src/jtag/drivers/libusb_helper.h | 2 +- src/jtag/drivers/opendous.c | 2 +- src/jtag/drivers/openjtag.c | 2 +- src/jtag/drivers/osbdm.c | 2 +- src/jtag/drivers/rlink.c | 2 +- src/jtag/drivers/stlink_usb.c | 2 +- src/jtag/drivers/ti_icdi_usb.c | 2 +- .../usb_blaster/ublast2_access_libusb.c | 6 +- src/jtag/drivers/usbprog.c | 2 +- tcl/interface/easydevkits-wch.cfg | 6 +- 18 files changed, 85 insertions(+), 26 deletions(-) diff --git a/src/jtag/drivers/angie.c b/src/jtag/drivers/angie.c index 35811fb80c..e439db6e55 100644 --- a/src/jtag/drivers/angie.c +++ b/src/jtag/drivers/angie.c @@ -255,7 +255,7 @@ static int angie_usb_open(struct angie *device) const uint16_t vids[] = {ANGIE_VID, ANGIE_VID, 0}; const uint16_t pids[] = {ANGIE_PID, ANGIE_PID_2, 0}; - int ret = jtag_libusb_open(vids, pids, &usb_device_handle, NULL); + int ret = jtag_libusb_open(vids, pids, NULL, &usb_device_handle, NULL); if (ret != ERROR_OK) return ret; diff --git a/src/jtag/drivers/arm-jtag-ew.c b/src/jtag/drivers/arm-jtag-ew.c index a372720849..eada67f45c 100644 --- a/src/jtag/drivers/arm-jtag-ew.c +++ b/src/jtag/drivers/arm-jtag-ew.c @@ -677,7 +677,7 @@ static struct armjtagew *armjtagew_usb_open(void) const uint16_t pids[] = { USB_PID, 0 }; struct libusb_device_handle *dev; - if (jtag_libusb_open(vids, pids, &dev, NULL) != ERROR_OK) + if (jtag_libusb_open(vids, pids, NULL, &dev, NULL) != ERROR_OK) return NULL; struct armjtagew *result = malloc(sizeof(struct armjtagew)); diff --git a/src/jtag/drivers/ch347.c b/src/jtag/drivers/ch347.c index 704a878692..7756e276f7 100755 --- a/src/jtag/drivers/ch347.c +++ b/src/jtag/drivers/ch347.c @@ -234,12 +234,14 @@ bool ugOpen; unsigned long ugIndex; struct libusb_device_handle *ch347_handle; -static const uint16_t ch347_vids[] = {0x1a86, 0}; -static const uint16_t ch347_pids[] = {0x55dd, 0}; +static uint16_t ch347_vids[] = {0x1a86, 0}; +static uint16_t ch347_pids[] = {0x55dd, 0}; +static char *ch347_device_desc = NULL; +static uint8_t ch347_activity_led_gpio_pin = 0xFF; static uint32_t CH347OpenDevice(uint64_t iIndex) { - if (jtag_libusb_open(ch347_vids, ch347_pids, + if (jtag_libusb_open(ch347_vids, ch347_pids, ch347_device_desc, &ch347_handle, NULL) != ERROR_OK) { return false; } else { @@ -1293,7 +1295,14 @@ static int ch347_trst_out(unsigned char status) COMMAND_HANDLER(ch347_handle_vid_pid_command) { - /* TODO */ + if (CMD_ARGC != 2) { + LOG_WARNING("incomplete ch347 vid_pid configuration directive"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], ch347_vids[0]); + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], ch347_pids[0]); + return ERROR_OK; } @@ -1305,13 +1314,36 @@ COMMAND_HANDLER(ch347_trst) return ERROR_OK; } +COMMAND_HANDLER(ch347_handle_device_desc_command) +{ + if (CMD_ARGC == 1) { + if (ch347_device_desc != NULL) + free(ch347_device_desc); + ch347_device_desc = strdup(CMD_ARGV[0]); + } else { + LOG_ERROR("expected exactly one argument to ch347 device_desc "); + } + + return ERROR_OK; +} + +COMMAND_HANDLER(ch347_handle_activity_led_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], ch347_activity_led_gpio_pin); + + return ERROR_OK; +} + static const struct command_registration ch347_subcommand_handlers[] = { { .name = "vid_pid", .handler = &ch347_handle_vid_pid_command, .mode = COMMAND_CONFIG, - .help = "", - .usage = "", + .help = "the vendor ID and product ID of the CH347 device", + .usage = "(vid pid)*", }, { .name = "jtag_ntrst_delay", @@ -1320,6 +1352,20 @@ static const struct command_registration ch347_subcommand_handlers[] = { .help = "set the trst of the CH347 device that is used as JTAG", .usage = "[milliseconds]", }, + { + .name = "device_desc", + .handler = &ch347_handle_device_desc_command, + .mode = COMMAND_CONFIG, + .help = "set the USB device description of the CH347 device", + .usage = "description_string", + }, + { + .name = "activity_led", + .handler = &ch347_handle_activity_led_command, + .mode = COMMAND_CONFIG, + .help = "if set this CH347 GPIO pin is the JTAG activity LED; e.g. 4", + .usage = "", + }, COMMAND_REGISTRATION_DONE}; diff --git a/src/jtag/drivers/esp_usb_jtag.c b/src/jtag/drivers/esp_usb_jtag.c index 662bbf16d5..1e352b8255 100644 --- a/src/jtag/drivers/esp_usb_jtag.c +++ b/src/jtag/drivers/esp_usb_jtag.c @@ -641,7 +641,7 @@ static int esp_usb_jtag_init(void) bitq_interface->in_rdy = esp_usb_jtag_in_rdy; bitq_interface->in = esp_usb_jtag_in; - int r = jtag_libusb_open(vids, pids, &priv->usb_device, NULL); + int r = jtag_libusb_open(vids, pids, NULL, &priv->usb_device, NULL); if (r != ERROR_OK) { LOG_ERROR("esp_usb_jtag: could not find or open device!"); goto out; diff --git a/src/jtag/drivers/ft232r.c b/src/jtag/drivers/ft232r.c index c2ec78ad88..2d9d9ef34d 100644 --- a/src/jtag/drivers/ft232r.c +++ b/src/jtag/drivers/ft232r.c @@ -246,7 +246,7 @@ static int ft232r_init(void) { uint16_t avids[] = {ft232r_vid, 0}; uint16_t apids[] = {ft232r_pid, 0}; - if (jtag_libusb_open(avids, apids, &adapter, NULL)) { + if (jtag_libusb_open(avids, apids, NULL, &adapter, NULL)) { const char *ft232r_serial_desc = adapter_get_required_serial(); LOG_ERROR("ft232r not found: vid=%04x, pid=%04x, serial=%s\n", ft232r_vid, ft232r_pid, (!ft232r_serial_desc) ? "[any]" : ft232r_serial_desc); diff --git a/src/jtag/drivers/jtag_esp_remote.c b/src/jtag/drivers/jtag_esp_remote.c index d7f74b988f..9626321b17 100644 --- a/src/jtag/drivers/jtag_esp_remote.c +++ b/src/jtag/drivers/jtag_esp_remote.c @@ -631,7 +631,7 @@ static int jtag_esp_remote_init_usb(void) { const uint16_t vids[] = { usb_vid, 0 }; /* must be null terminated */ const uint16_t pids[] = { usb_pid, 0 }; /* must be null terminated */ - int r = jtag_libusb_open(vids, pids, &usb_device, NULL); + int r = jtag_libusb_open(vids, pids, NULL, &usb_device, NULL); if (r != ERROR_OK) { if (r == ERROR_FAIL) return ERROR_JTAG_INVALID_INTERFACE; /*we likely can't find the USB diff --git a/src/jtag/drivers/kitprog.c b/src/jtag/drivers/kitprog.c index b953218b85..e126a9c22b 100644 --- a/src/jtag/drivers/kitprog.c +++ b/src/jtag/drivers/kitprog.c @@ -275,7 +275,7 @@ static int kitprog_usb_open(void) const uint16_t vids[] = { VID, 0 }; const uint16_t pids[] = { PID, 0 }; - if (jtag_libusb_open(vids, pids, &kitprog_handle->usb_handle, NULL) != ERROR_OK) { + if (jtag_libusb_open(vids, pids, NULL, &kitprog_handle->usb_handle, NULL) != ERROR_OK) { LOG_ERROR("Failed to open or find the device"); return ERROR_FAIL; } diff --git a/src/jtag/drivers/libusb_helper.c b/src/jtag/drivers/libusb_helper.c index cc5984e34f..7bf40331ea 100644 --- a/src/jtag/drivers/libusb_helper.c +++ b/src/jtag/drivers/libusb_helper.c @@ -145,13 +145,14 @@ static bool jtag_libusb_match_serial(struct libusb_device_handle *device, return match; } -int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], +int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], const char *product, struct libusb_device_handle **out, adapter_get_alternate_serial_fn adapter_get_alternate_serial) { int cnt, idx, err_code; int retval = ERROR_FAIL; bool serial_mismatch = false; + bool product_mismatch = false; struct libusb_device_handle *libusb_handle = NULL; const char *serial = adapter_get_required_serial(); @@ -188,10 +189,17 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], continue; } + if (product && !string_descriptor_equal(libusb_handle, dev_desc.iProduct, product)) { + product_mismatch = true; + libusb_close(libusb_handle); + continue; + } + /* Success. */ *out = libusb_handle; retval = ERROR_OK; serial_mismatch = false; + product_mismatch = false; break; } if (cnt >= 0) @@ -200,6 +208,9 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], if (serial_mismatch) LOG_INFO("No device matches the serial string"); + if (product_mismatch) + LOG_INFO("No device matches the product string"); + if (retval != ERROR_OK) libusb_exit(jtag_libusb_context); diff --git a/src/jtag/drivers/libusb_helper.h b/src/jtag/drivers/libusb_helper.h index cb7ce32276..2edfb49128 100644 --- a/src/jtag/drivers/libusb_helper.h +++ b/src/jtag/drivers/libusb_helper.h @@ -32,7 +32,7 @@ typedef char * (*adapter_get_alternate_serial_fn)(struct libusb_device_handle *d bool jtag_libusb_match_ids(struct libusb_device_descriptor *dev_desc, const uint16_t vids[], const uint16_t pids[]); -int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], +int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], const char *product, struct libusb_device_handle **out, adapter_get_alternate_serial_fn adapter_get_alternate_serial); void jtag_libusb_close(struct libusb_device_handle *dev); diff --git a/src/jtag/drivers/opendous.c b/src/jtag/drivers/opendous.c index 2e1d648147..4d9fd998a7 100644 --- a/src/jtag/drivers/opendous.c +++ b/src/jtag/drivers/opendous.c @@ -695,7 +695,7 @@ struct opendous_jtag *opendous_usb_open(void) struct opendous_jtag *result; struct libusb_device_handle *devh; - if (jtag_libusb_open(opendous_probe->VID, opendous_probe->PID, &devh, NULL) != ERROR_OK) + if (jtag_libusb_open(opendous_probe->VID, opendous_probe->PID, NULL, &devh, NULL) != ERROR_OK) return NULL; jtag_libusb_set_configuration(devh, 0); diff --git a/src/jtag/drivers/openjtag.c b/src/jtag/drivers/openjtag.c index fe3a8ff7f9..dca27b0a64 100644 --- a/src/jtag/drivers/openjtag.c +++ b/src/jtag/drivers/openjtag.c @@ -438,7 +438,7 @@ static int openjtag_init_cy7c65215(void) int ret; usbh = NULL; - ret = jtag_libusb_open(cy7c65215_vids, cy7c65215_pids, &usbh, NULL); + ret = jtag_libusb_open(cy7c65215_vids, cy7c65215_pids, NULL, &usbh, NULL); if (ret != ERROR_OK) { LOG_ERROR("unable to open cy7c65215 device"); goto err; diff --git a/src/jtag/drivers/osbdm.c b/src/jtag/drivers/osbdm.c index d8fe7135e7..84f2fd66a0 100644 --- a/src/jtag/drivers/osbdm.c +++ b/src/jtag/drivers/osbdm.c @@ -363,7 +363,7 @@ static int osbdm_flush(struct osbdm *osbdm, struct queue *queue) static int osbdm_open(struct osbdm *osbdm) { (void)memset(osbdm, 0, sizeof(*osbdm)); - if (jtag_libusb_open(osbdm_vid, osbdm_pid, &osbdm->devh, NULL) != ERROR_OK) + if (jtag_libusb_open(osbdm_vid, osbdm_pid, NULL, &osbdm->devh, NULL) != ERROR_OK) return ERROR_FAIL; if (libusb_claim_interface(osbdm->devh, 0) != ERROR_OK) diff --git a/src/jtag/drivers/rlink.c b/src/jtag/drivers/rlink.c index 65f7494bd9..a28e76e013 100644 --- a/src/jtag/drivers/rlink.c +++ b/src/jtag/drivers/rlink.c @@ -1448,7 +1448,7 @@ static int rlink_init(void) const uint16_t vids[] = { USB_IDVENDOR, 0 }; const uint16_t pids[] = { USB_IDPRODUCT, 0 }; - if (jtag_libusb_open(vids, pids, &hdev, NULL) != ERROR_OK) + if (jtag_libusb_open(vids, pids, NULL, &hdev, NULL) != ERROR_OK) return ERROR_FAIL; struct libusb_device_descriptor descriptor; diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index 2c5b63dd6e..8111113d68 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -3406,7 +3406,7 @@ static int stlink_usb_usb_open(void *handle, struct hl_interface_param_s *param) in order to become operational. */ do { - if (jtag_libusb_open(param->vid, param->pid, + if (jtag_libusb_open(param->vid, param->pid, NULL, &h->usb_backend_priv.fd, stlink_usb_get_alternate_serial) != ERROR_OK) { LOG_ERROR("open failed"); return ERROR_FAIL; diff --git a/src/jtag/drivers/ti_icdi_usb.c b/src/jtag/drivers/ti_icdi_usb.c index 3e36218738..4260e2d39d 100644 --- a/src/jtag/drivers/ti_icdi_usb.c +++ b/src/jtag/drivers/ti_icdi_usb.c @@ -675,7 +675,7 @@ static int icdi_usb_open(struct hl_interface_param_s *param, void **fd) /* TI (Stellaris) ICDI provides its serial number in the USB descriptor; no need to provide a callback here. */ - jtag_libusb_open(param->vid, param->pid, &h->usb_dev, NULL); + jtag_libusb_open(param->vid, param->pid, NULL, &h->usb_dev, NULL); if (!h->usb_dev) { LOG_ERROR("open failed"); diff --git a/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c b/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c index f5e0026a7b..de0d2d8472 100644 --- a/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c +++ b/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c @@ -202,7 +202,7 @@ static int ublast2_libusb_init(struct ublast_lowlevel *low) bool renumeration = false; int ret; - if (jtag_libusb_open(vids, pids, &temp, NULL) == ERROR_OK) { + if (jtag_libusb_open(vids, pids, NULL, &temp, NULL) == ERROR_OK) { LOG_INFO("Altera USB-Blaster II (uninitialized) found"); LOG_INFO("Loading firmware..."); ret = load_usb_blaster_firmware(temp, low); @@ -216,13 +216,13 @@ static int ublast2_libusb_init(struct ublast_lowlevel *low) const uint16_t pids_renum[] = { low->ublast_pid, 0 }; if (renumeration == false) { - if (jtag_libusb_open(vids_renum, pids_renum, &low->libusb_dev, NULL) != ERROR_OK) { + if (jtag_libusb_open(vids_renum, pids_renum, NULL, &low->libusb_dev, NULL) != ERROR_OK) { LOG_ERROR("Altera USB-Blaster II not found"); return ERROR_FAIL; } } else { int retry = 10; - while (jtag_libusb_open(vids_renum, pids_renum, &low->libusb_dev, NULL) != ERROR_OK && retry--) { + while (jtag_libusb_open(vids_renum, pids_renum, NULL, &low->libusb_dev, NULL) != ERROR_OK && retry--) { usleep(1000000); LOG_INFO("Waiting for reenumerate..."); } diff --git a/src/jtag/drivers/usbprog.c b/src/jtag/drivers/usbprog.c index 5d41656b4f..aa655ed7e6 100644 --- a/src/jtag/drivers/usbprog.c +++ b/src/jtag/drivers/usbprog.c @@ -341,7 +341,7 @@ struct usbprog_jtag *usbprog_jtag_open(void) const uint16_t pids[] = { PID, 0 }; struct libusb_device_handle *dev; - if (jtag_libusb_open(vids, pids, &dev, NULL) != ERROR_OK) + if (jtag_libusb_open(vids, pids, NULL, &dev, NULL) != ERROR_OK) return NULL; struct usbprog_jtag *tmp = malloc(sizeof(struct usbprog_jtag)); diff --git a/tcl/interface/easydevkits-wch.cfg b/tcl/interface/easydevkits-wch.cfg index f399687ee3..fc8afa67f8 100755 --- a/tcl/interface/easydevkits-wch.cfg +++ b/tcl/interface/easydevkits-wch.cfg @@ -1,4 +1,6 @@ adapter driver ch347 -ch347 vid_pid 0x1a86 0x55dd +ch347 device_desc "EasyDevKit" +ch347 vid_pid 0x1a86 0x55dd +ch347 activity_led 4 -adapter speed 10000 +adapter speed 10000 \ No newline at end of file From 0916a2932a35582ee85e27509e328c303a523b67 Mon Sep 17 00:00:00 2001 From: EasyDevKits Date: Sun, 1 Oct 2023 01:36:33 +0200 Subject: [PATCH 03/22] Preparation for driving an activity LED The LED output can alsob e acrive low --- src/jtag/drivers/ch347.c | 36 +++++++++++++++++++++++++++---- tcl/interface/easydevkits-wch.cfg | 16 ++++++++++++-- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/src/jtag/drivers/ch347.c b/src/jtag/drivers/ch347.c index 7756e276f7..134a9027d1 100755 --- a/src/jtag/drivers/ch347.c +++ b/src/jtag/drivers/ch347.c @@ -74,6 +74,8 @@ #define TCK_L 0 #define TRST_H JTAGIO_STA_OUT_TRST #define TRST_L 0 +#define LED_ON 1 +#define LED_OFF 0 #define KHZ(n) ((n)*UINT64_C(1000)) #define MHZ(n) ((n)*UINT64_C(1000000)) @@ -90,7 +92,6 @@ package length */ #define CH347_CMD_HEADER 3 /* Protocol header length */ -#define CH347_CMD_HEADER 3 /* 协议包头长度 */ /* Protocol transmission format: CMD (1 byte)+Length (2 bytes)+Data */ #define CH347_CMD_INFO_RD 0xCA /* Parameter acquisition, used to obtain firmware version, @@ -132,6 +133,8 @@ typedef struct _CH347_info /* Record the CH347 pin status */ int TDI; int TCK; int TRST; + + int activity_led; int buffer_idx; uint8_t buffer[SF_PACKET_BUF_SIZE]; @@ -238,6 +241,7 @@ static uint16_t ch347_vids[] = {0x1a86, 0}; static uint16_t ch347_pids[] = {0x55dd, 0}; static char *ch347_device_desc = NULL; static uint8_t ch347_activity_led_gpio_pin = 0xFF; +static bool ch347_activity_led_active_high = false; static uint32_t CH347OpenDevice(uint64_t iIndex) { @@ -343,6 +347,15 @@ static char *HexToString(uint8_t *buf, uint32_t size) return str; } +static void CH347_SetActivityLed(int ledState) +{ + if (ch347_activity_led_gpio_pin != 0xff) + { + ch347.activity_led = ch347_activity_led_active_high == true ? ledState : 1 - ledState; + // TODO: output LED here + } +} + /** * CH347_Write - CH347 Write * @param oBuffer Point to a buffer to place the data to be written out @@ -651,6 +664,8 @@ static void CH347_TMS(struct tms_command *cmd) static int ch347_reset(int trst, int srst) { LOG_DEBUG_IO("reset trst: %i srst %i", trst, srst); + CH347_SetActivityLed(LED_OFF); + #if 1 unsigned char BitBang[512] = "", BII, i; unsigned long TxLen; @@ -1032,6 +1047,8 @@ static int ch347_execute_queue(void) struct jtag_command *cmd; int ret = ERROR_OK; + CH347_SetActivityLed(LED_ON); + for (cmd = jtag_command_queue; ret == ERROR_OK && cmd; cmd = cmd->next) { switch (cmd->type) { @@ -1072,6 +1089,7 @@ static int ch347_execute_queue(void) } CH347_Flush_Buffer(); + CH347_SetActivityLed(LED_OFF); return ret; } @@ -1158,6 +1176,9 @@ static int ch347_init(void) */ static int ch347_quit(void) { + // on close set the LED on, because the state without JTAG is on + CH347_SetActivityLed(LED_ON); + unsigned long retlen = 4; uint8_t byte[4] = {CH347_CMD_JTAG_BIT_OP, 0x01, 0x00, ch347.TRST}; if (!swd_mode) { @@ -1332,7 +1353,14 @@ COMMAND_HANDLER(ch347_handle_activity_led_command) if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], ch347_activity_led_gpio_pin); + if (CMD_ARGV[0][0] == 'n') { + COMMAND_PARSE_NUMBER(u8, ++CMD_ARGV[0], ch347_activity_led_gpio_pin); + ch347_activity_led_active_high = false; + CMD_ARGV[0]--; + } else { + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], ch347_activity_led_gpio_pin); + ch347_activity_led_active_high = true; + } return ERROR_OK; } @@ -1363,8 +1391,8 @@ static const struct command_registration ch347_subcommand_handlers[] = { .name = "activity_led", .handler = &ch347_handle_activity_led_command, .mode = COMMAND_CONFIG, - .help = "if set this CH347 GPIO pin is the JTAG activity LED; e.g. 4", - .usage = "", + .help = "if set this CH347 GPIO pin is the JTAG activity LED; start with n for active low output", + .usage = "n4 or 4", }, COMMAND_REGISTRATION_DONE}; diff --git a/tcl/interface/easydevkits-wch.cfg b/tcl/interface/easydevkits-wch.cfg index fc8afa67f8..3200e4a7c8 100755 --- a/tcl/interface/easydevkits-wch.cfg +++ b/tcl/interface/easydevkits-wch.cfg @@ -1,6 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Driver for the CH347 JTAG chip on the EasyDevKits JTAG Adapter +# + adapter driver ch347 ch347 device_desc "EasyDevKit" ch347 vid_pid 0x1a86 0x55dd -ch347 activity_led 4 +# the activity LED is low active at GPIO4 (n4) +ch347 activity_led n4 -adapter speed 10000 \ No newline at end of file +# The speed of the JTAG interface, in kHz. If you get DSR/DIR errors (and they +# do not relate to OpenOCD trying to read from a memory range without physical +# memory being present there), you can try lowering this. +# +# On EasyDevKits, this can go as high as 20MHz if CPU frequency is 80MHz, +# or 26MHz if CPU frequency is 160MHz or 240MHz. +adapter speed 20000 \ No newline at end of file From b8f19c09dc96a0cfab4fc47903e3167de3072e17 Mon Sep 17 00:00:00 2001 From: EasyDevKits Date: Sun, 1 Oct 2023 01:42:51 +0200 Subject: [PATCH 04/22] Unused actions removed --- .github/workflows/issue_comment.yml | 19 ------------------- .github/workflows/new_issues.yml | 19 ------------------- .github/workflows/new_prs.yml | 25 ------------------------- 3 files changed, 63 deletions(-) delete mode 100644 .github/workflows/issue_comment.yml delete mode 100644 .github/workflows/new_issues.yml delete mode 100644 .github/workflows/new_prs.yml diff --git a/.github/workflows/issue_comment.yml b/.github/workflows/issue_comment.yml deleted file mode 100644 index 9ca538fc22..0000000000 --- a/.github/workflows/issue_comment.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: Sync issue comments to JIRA - -# This workflow will be triggered when new issue comment is created (including PR comments) -on: issue_comment - -jobs: - sync_issue_comments_to_jira: - name: Sync Issue Comments to Jira - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@master - - name: Sync issue comments to JIRA - uses: espressif/github-actions/sync_issues_to_jira@master - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - JIRA_PASS: ${{ secrets.JIRA_PASS }} - JIRA_PROJECT: OCD - JIRA_URL: ${{ secrets.JIRA_URL }} - JIRA_USER: ${{ secrets.JIRA_USER }} diff --git a/.github/workflows/new_issues.yml b/.github/workflows/new_issues.yml deleted file mode 100644 index efa672cc18..0000000000 --- a/.github/workflows/new_issues.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: Sync issues to Jira - -# This workflow will be triggered when a new issue is opened -on: issues - -jobs: - sync_issues_to_jira: - name: Sync issues to Jira - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@master - - name: Sync GitHub issues to Jira project - uses: espressif/github-actions/sync_issues_to_jira@master - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - JIRA_PASS: ${{ secrets.JIRA_PASS }} - JIRA_PROJECT: OCD - JIRA_URL: ${{ secrets.JIRA_URL }} - JIRA_USER: ${{ secrets.JIRA_USER }} diff --git a/.github/workflows/new_prs.yml b/.github/workflows/new_prs.yml deleted file mode 100644 index 3cb5a4b230..0000000000 --- a/.github/workflows/new_prs.yml +++ /dev/null @@ -1,25 +0,0 @@ - -name: Sync remain PRs to Jira - -# This workflow will be triggered every hour, to sync remaining PRs (i.e. PRs with zero comment) to Jira project -# Note that, PRs can also get synced when new PR comment is created -on: - schedule: - - cron: "0 * * * *" - -jobs: - sync_prs_to_jira: - name: Sync PRs to Jira - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@master - - name: Sync PRs to Jira project - uses: espressif/github-actions/sync_issues_to_jira@master - with: - cron_job: true - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - JIRA_PASS: ${{ secrets.JIRA_PASS }} - JIRA_PROJECT: OCD - JIRA_URL: ${{ secrets.JIRA_URL }} - JIRA_USER: ${{ secrets.JIRA_USER }} From a83ec2538c0a6dfb3d385c1ed1b2b12ab65c49cc Mon Sep 17 00:00:00 2001 From: EasyDevKits Date: Sun, 1 Oct 2023 01:47:29 +0200 Subject: [PATCH 05/22] Compilation error fixed for windows --- src/jtag/drivers/ch347.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jtag/drivers/ch347.c b/src/jtag/drivers/ch347.c index 134a9027d1..fc61ddbd29 100755 --- a/src/jtag/drivers/ch347.c +++ b/src/jtag/drivers/ch347.c @@ -153,6 +153,8 @@ typedef struct _CH347_info /* Record the CH347 pin status */ int DevIsOpened; /* Whether the device is turned on */ bool UsbHighDev = true; unsigned long USBC_PACKET; +static uint8_t ch347_activity_led_gpio_pin = 0xFF; +static bool ch347_activity_led_active_high = false; typedef struct _CH347_SWD_IO { uint8_t usbcmd; /* 0xA0、0xA1、0xA2 */ @@ -240,8 +242,6 @@ struct libusb_device_handle *ch347_handle; static uint16_t ch347_vids[] = {0x1a86, 0}; static uint16_t ch347_pids[] = {0x55dd, 0}; static char *ch347_device_desc = NULL; -static uint8_t ch347_activity_led_gpio_pin = 0xFF; -static bool ch347_activity_led_active_high = false; static uint32_t CH347OpenDevice(uint64_t iIndex) { From 3fe37fc33a4a65f2b6ffea992ecfd9c156b4a35d Mon Sep 17 00:00:00 2001 From: EasyDevKits Date: Sun, 1 Oct 2023 01:50:08 +0200 Subject: [PATCH 06/22] Variables moved to fix the windows build --- src/jtag/drivers/ch347.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/jtag/drivers/ch347.c b/src/jtag/drivers/ch347.c index fc61ddbd29..7fbf899726 100755 --- a/src/jtag/drivers/ch347.c +++ b/src/jtag/drivers/ch347.c @@ -153,6 +153,10 @@ typedef struct _CH347_info /* Record the CH347 pin status */ int DevIsOpened; /* Whether the device is turned on */ bool UsbHighDev = true; unsigned long USBC_PACKET; + +static uint16_t ch347_vids[] = {0x1a86, 0}; +static uint16_t ch347_pids[] = {0x55dd, 0}; +static char *ch347_device_desc = NULL; static uint8_t ch347_activity_led_gpio_pin = 0xFF; static bool ch347_activity_led_active_high = false; @@ -239,10 +243,6 @@ bool ugOpen; unsigned long ugIndex; struct libusb_device_handle *ch347_handle; -static uint16_t ch347_vids[] = {0x1a86, 0}; -static uint16_t ch347_pids[] = {0x55dd, 0}; -static char *ch347_device_desc = NULL; - static uint32_t CH347OpenDevice(uint64_t iIndex) { if (jtag_libusb_open(ch347_vids, ch347_pids, ch347_device_desc, From 59c6a113f77bf4668c68300a8879aaaa1d162910 Mon Sep 17 00:00:00 2001 From: EasyDevKits Date: Sun, 1 Oct 2023 22:55:53 +0200 Subject: [PATCH 07/22] GPIO output added for the activity LED --- src/jtag/drivers/ch347.c | 66 ++++++++++++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 13 deletions(-) diff --git a/src/jtag/drivers/ch347.c b/src/jtag/drivers/ch347.c index 7fbf899726..9fb540064e 100755 --- a/src/jtag/drivers/ch347.c +++ b/src/jtag/drivers/ch347.c @@ -76,6 +76,8 @@ #define TRST_L 0 #define LED_ON 1 #define LED_OFF 0 +#define GPIO_CNT 8 /* the CH347 has 8 GPIO's */ +#define USEABLE_GPIOS 0x10 /* mask which GPIO's are available in mode 3 of CH347 - needs more investigation: to ba save only GPIO4 (Pin15 / ACT) is possible */ #define KHZ(n) ((n)*UINT64_C(1000)) #define MHZ(n) ((n)*UINT64_C(1000000)) @@ -91,12 +93,15 @@ #define USBC_PACKET_USBHS_SINGLE 510 /* usb high speed max package length */ #define CH347_CMD_HEADER 3 /* Protocol header length */ +#define CH347_GPIO_CMD_LENGTH (CH347_CMD_HEADER + GPIO_CNT) /* fixed length of the GPIO control command*/ /* Protocol transmission format: CMD (1 byte)+Length (2 bytes)+Data */ #define CH347_CMD_INFO_RD 0xCA /* Parameter acquisition, used to obtain firmware version, JTAG interface related parameters, etc */ +#define CH347_CMD_GPIO 0xCC /* GPIO Command */ + #define CH347_CMD_JTAG_INIT 0xD0 /* JTAG Interface Initialization Command */ #define CH347_CMD_JTAG_BIT_OP 0xD1 /* JTAG interface pin bit control @@ -134,8 +139,6 @@ typedef struct _CH347_info /* Record the CH347 pin status */ int TCK; int TRST; - int activity_led; - int buffer_idx; uint8_t buffer[SF_PACKET_BUF_SIZE]; @@ -347,15 +350,6 @@ static char *HexToString(uint8_t *buf, uint32_t size) return str; } -static void CH347_SetActivityLed(int ledState) -{ - if (ch347_activity_led_gpio_pin != 0xff) - { - ch347.activity_led = ch347_activity_led_active_high == true ? ledState : 1 - ledState; - // TODO: output LED here - } -} - /** * CH347_Write - CH347 Write * @param oBuffer Point to a buffer to place the data to be written out @@ -655,6 +649,41 @@ static void CH347_TMS(struct tms_command *cmd) CH347_TmsChange(cmd->bits, cmd->num_bits, 0); } +static void CH347_GpioSet(int gpio, int data) +{ + // build a gpio control command + long unsigned int cmdLength = CH347_GPIO_CMD_LENGTH; + uint8_t gpioCmd[CH347_GPIO_CMD_LENGTH]; + memset(gpioCmd, 0, sizeof(gpioCmd)); + gpioCmd[0] = CH347_CMD_GPIO; + gpioCmd[1] = GPIO_CNT; + gpioCmd[2] = 0; + // always set bits 7 and 6 for GPIO enable and bits 5 and 4 for pin direction output + // bit 3 is the data bit + gpioCmd[CH347_CMD_HEADER + gpio] = data == 0 ? 0xF0 : 0xF8; + + if (!CH347_Write(gpioCmd, &cmdLength) && (cmdLength != CH347_GPIO_CMD_LENGTH)) { + LOG_ERROR("JTAG_Gpio send usb data failure."); + return; + } + else if (!CH347_Read(gpioCmd, &cmdLength) && (cmdLength != CH347_GPIO_CMD_LENGTH)) { + LOG_ERROR("JTAG_Gpio read usb data failure."); + return; + } + else if ((gpioCmd[CH347_CMD_HEADER + gpio] & 0x40) >> 6 != data) { + LOG_ERROR("JTAG_Gpio output not set."); + return; + } + return; +} + +static void CH347_SetActivityLed(int ledState) +{ + if (ch347_activity_led_gpio_pin != 0xff) { + CH347_GpioSet(ch347_activity_led_gpio_pin, ch347_activity_led_active_high ? ledState : 1 - ledState); + } +} + /** * CH347_Reset - CH347 Reset Tap Status Function * @brief If there are more than six consecutive TCKs and TMS is high, the state @@ -1353,14 +1382,25 @@ COMMAND_HANDLER(ch347_handle_activity_led_command) if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; + uint8_t gpio; if (CMD_ARGV[0][0] == 'n') { - COMMAND_PARSE_NUMBER(u8, ++CMD_ARGV[0], ch347_activity_led_gpio_pin); + COMMAND_PARSE_NUMBER(u8, ++CMD_ARGV[0], gpio); ch347_activity_led_active_high = false; CMD_ARGV[0]--; } else { - COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], ch347_activity_led_gpio_pin); + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], gpio); ch347_activity_led_active_high = true; } + + if (gpio >= GPIO_CNT) { + LOG_ERROR("activity_led out of range"); + } + else if (((1 << gpio) & USEABLE_GPIOS) == 0) { + LOG_ERROR("activity_led pin not in useable list"); + } + else { + ch347_activity_led_gpio_pin = gpio; + } return ERROR_OK; } From 2fe428861c4b1bd0aeb07802a59cc3d0f2b6caf0 Mon Sep 17 00:00:00 2001 From: EasyDevKits Date: Sun, 1 Oct 2023 23:24:14 +0200 Subject: [PATCH 08/22] GPIO3, 4, 5 and 6 can be used for the activity LED --- src/jtag/drivers/ch347.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/jtag/drivers/ch347.c b/src/jtag/drivers/ch347.c index 9fb540064e..3a4f5099d8 100755 --- a/src/jtag/drivers/ch347.c +++ b/src/jtag/drivers/ch347.c @@ -77,7 +77,10 @@ #define LED_ON 1 #define LED_OFF 0 #define GPIO_CNT 8 /* the CH347 has 8 GPIO's */ -#define USEABLE_GPIOS 0x10 /* mask which GPIO's are available in mode 3 of CH347 - needs more investigation: to ba save only GPIO4 (Pin15 / ACT) is possible */ +#define USEABLE_GPIOS 0x78 /* mask which GPIO's are available in mode 3 of CH347T + only GPIO3 (Pin11 / SCL), GPIO4 (Pin15 / ACT), + GPIO5 (Pin9 / TRST) and GPIO6 (Pin2 / CTS1) are possible + Tested only with CH347T not CH347F chip - pin numbers are for CH347T */ #define KHZ(n) ((n)*UINT64_C(1000)) #define MHZ(n) ((n)*UINT64_C(1000000)) From fe8ceaf6a58aafc49cf6ddc95c47187484f00410 Mon Sep 17 00:00:00 2001 From: EasyDevKits Date: Tue, 3 Oct 2023 22:43:30 +0200 Subject: [PATCH 09/22] Wait a bit longer in esp_xtensa_reset_reason_read --- src/target/espressif/esp_xtensa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/espressif/esp_xtensa.c b/src/target/espressif/esp_xtensa.c index 934435058c..d361112fa5 100644 --- a/src/target/espressif/esp_xtensa.c +++ b/src/target/espressif/esp_xtensa.c @@ -235,7 +235,7 @@ int esp_xtensa_reset_reason_read(struct target *target) /* Can not call `target_wait_state` here because it will re-enter `esp_xtensa_poll` in waiting loop. So * implement our own waiting cycle. `xtensa_poll` does not call target state event handlers, so GDB will * not notice target state change. */ - int64_t timeout = timeval_ms() + 100; + int64_t timeout = timeval_ms() + 200; while (target->state != TARGET_HALTED) { alive_sleep(10); ret = xtensa_poll(target); From 39d3b3f5d4a331b418a622d7756d82d6df85c0ff Mon Sep 17 00:00:00 2001 From: EasyDevKits Date: Tue, 3 Oct 2023 22:52:21 +0200 Subject: [PATCH 10/22] Thanks to coflery - Frand Ren https://github.com/coflery/openocd - Constants for usb timeouts added - Read the firmware version on open - ch347_reset: do nothing if trst/srst are unset (seen in ftdi driver) - CH347_MoveState: Don't skip the move to TAP_RESET --- src/jtag/drivers/ch347.c | 104 +++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 53 deletions(-) diff --git a/src/jtag/drivers/ch347.c b/src/jtag/drivers/ch347.c index 3a4f5099d8..b9d354ef72 100755 --- a/src/jtag/drivers/ch347.c +++ b/src/jtag/drivers/ch347.c @@ -82,6 +82,8 @@ GPIO5 (Pin9 / TRST) and GPIO6 (Pin2 / CTS1) are possible Tested only with CH347T not CH347F chip - pin numbers are for CH347T */ +#define VENDOR_VERSION 0x5F + #define KHZ(n) ((n)*UINT64_C(1000)) #define MHZ(n) ((n)*UINT64_C(1000000)) #define GHZ(n) ((n)*UINT64_C(1000000000)) @@ -244,19 +246,37 @@ pCH347WriteData CH347WriteData; #define CH347_EPOUT 0x06u #define CH347_EPIN 0x86u +#define CH347_MPHSI_INTERFACE 2 bool ugOpen; unsigned long ugIndex; struct libusb_device_handle *ch347_handle; +uint32_t usb_write_timeout = 500; +uint32_t usb_read_timeout = 500; static uint32_t CH347OpenDevice(uint64_t iIndex) { - if (jtag_libusb_open(ch347_vids, ch347_pids, ch347_device_desc, - &ch347_handle, NULL) != ERROR_OK) { + if (jtag_libusb_open(ch347_vids, ch347_pids, ch347_device_desc, &ch347_handle, NULL) != ERROR_OK) { + LOG_ERROR("ch347 not found: vid=%04x, pid=%04x", ch347_vids[0], ch347_pids[0]); + return false; + } + + if (libusb_claim_interface(ch347_handle, CH347_MPHSI_INTERFACE)) { + LOG_ERROR("ch347 unable to claim interface"); + return false; + } + + char firmwareVersion; + if (jtag_libusb_control_transfer(ch347_handle, + LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + VENDOR_VERSION, 0, 0, &firmwareVersion, sizeof(firmwareVersion), usb_write_timeout, NULL) != ERROR_OK) + { + LOG_ERROR("ch347 unable to get firmware version"); return false; - } else { - return true; } + + LOG_INFO("CH347 found (Firmware=0x%02X)", firmwareVersion); + return true; } static bool CH347WriteData(uint64_t iIndex, uint8_t *data, uint64_t *length) @@ -266,7 +286,7 @@ static bool CH347WriteData(uint64_t iIndex, uint8_t *data, uint64_t *length) CH347_EPOUT, (char *)data, *length, - 100, &tmp); + usb_write_timeout, &tmp); *length = tmp; if (!ret) @@ -284,7 +304,7 @@ static bool CH347ReadData(uint64_t iIndex, uint8_t *data, uint64_t *length) CH347_EPIN, (char *)data, size, - 100, &tmp); + usb_read_timeout, &tmp); *length = tmp; if (!ret) @@ -412,7 +432,7 @@ static int CH347_Read(void *oBuffer, unsigned long *ioLength) while (1) { if (!CH347ReadData(ugIndex, (uint8_t *)oBuffer + WI, &rlength)) { - LOG_ERROR("CH347_Read read data failure."); + LOG_ERROR("CH347 read fail"); return false; } @@ -445,7 +465,7 @@ static void CH347_Read_Scan(UCHAR *pBuffer, uint32_t length) read_buf_index = 0; read_buf = calloc(sizeof(unsigned char), read_size); if (!CH347_Read(read_buf, &RxLen)) { - LOG_ERROR("CH347_Read read data failure."); + LOG_ERROR("CH347 read fail"); return; } while (index < read_size) { /* deal with the CH347_CMD_JTAG_BIT_OP_RD or CH347_CMD_JTAG_DATA_SHIFT_RD */ @@ -469,7 +489,7 @@ static void CH347_Read_Scan(UCHAR *pBuffer, uint32_t length) read_buf_index += 1; index += dataLen + 1; } else { - LOG_ERROR("readbuf read_commend error"); + LOG_ERROR("CH347 read command fail"); *(pBuffer + read_buf_index) = read_buf[index]; read_buf_index++; index++; @@ -696,35 +716,14 @@ static void CH347_SetActivityLed(int ledState) static int ch347_reset(int trst, int srst) { LOG_DEBUG_IO("reset trst: %i srst %i", trst, srst); - CH347_SetActivityLed(LED_OFF); + // have seen in ftdi driver, that reset does only the reset via trst or srst pins. + // if both are unset the ftdi driver does nothing. => do also nothing if both are unset + if (!trst && !srst) + return ERROR_OK; -#if 1 - unsigned char BitBang[512] = "", BII, i; - unsigned long TxLen; - - BII = CH347_CMD_HEADER; - for (i = 0; i < 7; i++) { - BitBang[BII++] = TMS_H | TDI_L | TCK_L; - BitBang[BII++] = TMS_H | TDI_L | TCK_H; - } - BitBang[BII++] = TMS_H | TDI_L | TCK_L; - - ch347.TCK = TCK_L; - ch347.TDI = TDI_L; - ch347.TMS = 0; - - BitBang[0] = CH347_CMD_JTAG_BIT_OP; - BitBang[1] = BII - CH347_CMD_HEADER; - BitBang[2] = 0; - - TxLen = BII; - - if (!CH347_Write(BitBang, &TxLen) && (TxLen != BII)) { - LOG_ERROR("JTAG_Init send usb data failure."); - return false; - } -#else - if (!swd_mode && trst == 0) { + // untested! if not in swd mode and trst is defined we can give + // a 50µs pulse to the TRST pin via bit operations + if (!swd_mode && trst != 0) { unsigned long int BI = 0; @@ -737,7 +736,7 @@ static int ch347_reset(int trst, int srst) CH347_Flush_Buffer(); - Sleep(50); + usleep(50); CH347_In_Buffer(CH347_CMD_JTAG_BIT_OP); CH347_In_Buffer(0x01); @@ -749,7 +748,6 @@ static int ch347_reset(int trst, int srst) CH347_Flush_Buffer(); return ERROR_OK; } -#endif return ERROR_OK; } @@ -801,7 +799,8 @@ static void CH347_MoveState(tap_state_t state, int skip) LOG_DEBUG_IO("(from %s to %s)", tap_state_name(tap_get_state()), tap_state_name(state)); - if (tap_get_state() == state) + // don't do anything if we are already in the right state; but do execute always the TAP_RESET + if (tap_get_state() == state && state != TAP_RESET) return; tms_scan = tap_get_tms_path(tap_get_state(), state); tms_len = tap_get_tms_path_len(tap_get_state(), state); @@ -1080,7 +1079,7 @@ static int ch347_execute_queue(void) int ret = ERROR_OK; CH347_SetActivityLed(LED_ON); - + for (cmd = jtag_command_queue; ret == ERROR_OK && cmd; cmd = cmd->next) { switch (cmd->type) { @@ -1113,8 +1112,7 @@ static int ch347_execute_queue(void) ret = CH347_Scan(cmd->cmd.scan); break; default: - LOG_ERROR("BUG: unknown JTAG command type 0x%X", - cmd->type); + LOG_ERROR("BUG: unknown JTAG command type 0x%X", cmd->type); ret = ERROR_FAIL; break; } @@ -1162,15 +1160,14 @@ static int ch347_init(void) DevIsOpened = CH347OpenDevice(ugIndex); ugIndex = DevIsOpened; #endif - if (DevIsOpened == -1) { - LOG_ERROR("CH347 Open Error."); + if (DevIsOpened < 0) { + LOG_ERROR("CH347 open error"); return ERROR_FAIL; } else { - LOG_INFO("CH347 Open Succ."); + LOG_DEBUG_IO("CH347 open success"); } if (!swd_mode) { - USBC_PACKET = USBC_PACKET_USBHS; /* ch347 init */ ch347.TCK = 0; ch347.TMS = 0; @@ -1189,13 +1186,11 @@ static int ch347_init(void) bit_copy_queue_init(&ch347.read_queue); - /* CH347SetTimeout(ugIndex, 500, 500); */ - tap_set_state(TAP_RESET); } else { /* swd init */ - CH347SWD_INIT(ugIndex, 1); + CH347SWD_INIT(ugIndex, 0); } - return 0; + return ERROR_OK; } /** @@ -1219,7 +1214,7 @@ static int ch347_quit(void) } if (DevIsOpened) { CH347CloseDevice(ugIndex); - LOG_INFO("Close the CH347."); + LOG_DEBUG_IO("CH347 close"); DevIsOpened = false; } return 0; @@ -1349,7 +1344,7 @@ static int ch347_trst_out(unsigned char status) COMMAND_HANDLER(ch347_handle_vid_pid_command) { if (CMD_ARGC != 2) { - LOG_WARNING("incomplete ch347 vid_pid configuration directive"); + LOG_ERROR("incomplete ch347 vid_pid configuration directive"); return ERROR_COMMAND_SYNTAX_ERROR; } @@ -1375,6 +1370,7 @@ COMMAND_HANDLER(ch347_handle_device_desc_command) ch347_device_desc = strdup(CMD_ARGV[0]); } else { LOG_ERROR("expected exactly one argument to ch347 device_desc "); + return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; @@ -1397,9 +1393,11 @@ COMMAND_HANDLER(ch347_handle_activity_led_command) if (gpio >= GPIO_CNT) { LOG_ERROR("activity_led out of range"); + return ERROR_COMMAND_SYNTAX_ERROR; } else if (((1 << gpio) & USEABLE_GPIOS) == 0) { LOG_ERROR("activity_led pin not in useable list"); + return ERROR_COMMAND_SYNTAX_ERROR; } else { ch347_activity_led_gpio_pin = gpio; From d7113c2c0e0fe9148866ed179e088f7e711ab069 Mon Sep 17 00:00:00 2001 From: EasyDevKits Date: Wed, 4 Oct 2023 20:56:09 +0200 Subject: [PATCH 11/22] CH347: Chip version check added --- src/jtag/drivers/ch347.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/jtag/drivers/ch347.c b/src/jtag/drivers/ch347.c index b9d354ef72..35f576626f 100755 --- a/src/jtag/drivers/ch347.c +++ b/src/jtag/drivers/ch347.c @@ -261,6 +261,13 @@ static uint32_t CH347OpenDevice(uint64_t iIndex) return false; } + struct libusb_device_descriptor ch347_device_descriptor; + libusb_get_device_descriptor(libusb_get_device(ch347_handle), &ch347_device_descriptor); + if (ch347_device_descriptor.bcdDevice < 0x241) { + LOG_ERROR("ch347 old version of the chip, JTAG not working. Need at least version 2.41."); + return false; + } + if (libusb_claim_interface(ch347_handle, CH347_MPHSI_INTERFACE)) { LOG_ERROR("ch347 unable to claim interface"); return false; @@ -275,7 +282,10 @@ static uint32_t CH347OpenDevice(uint64_t iIndex) return false; } - LOG_INFO("CH347 found (Firmware=0x%02X)", firmwareVersion); + LOG_INFO("CH347 found (Chip version=%2X.%2X, Firmware=0x%02X)", + (ch347_device_descriptor.bcdDevice >> 8) & 0xFF, + ch347_device_descriptor.bcdDevice & 0xFF, + firmwareVersion); return true; } From 44d53e8cd9e1a178d30c714213acceefee01dbfc Mon Sep 17 00:00:00 2001 From: EasyDevKits Date: Sun, 8 Oct 2023 23:53:42 +0200 Subject: [PATCH 12/22] Various fixes for getting JTAG working with CH347 - Added CH347_WriteReadBitwise -read/write for older chip versions - Added CH347_ScanDataToFields and fixed a bug for fields without data - for scan fields without data (one bit field) for skipping targets the bits need also be counted --- src/jtag/drivers/ch347.c | 260 ++++++++++++++++++++++++++------------- 1 file changed, 172 insertions(+), 88 deletions(-) diff --git a/src/jtag/drivers/ch347.c b/src/jtag/drivers/ch347.c index 35f576626f..3dfe666d66 100755 --- a/src/jtag/drivers/ch347.c +++ b/src/jtag/drivers/ch347.c @@ -90,33 +90,22 @@ #define HW_TDO_BUF_SIZE 4096 #define SF_PACKET_BUF_SIZE 51200 /* Command packet length */ -#define UCMDPKT_DATA_MAX_BYTES_USBHS 507 /* The data length contained in each - command packet during USB - high-speed operation */ -#define USBC_PACKET_USBHS 512 /* Maximum data length per packet at - USB high speed */ -#define USBC_PACKET_USBHS_SINGLE 510 /* usb high speed max - package length */ +#define UCMDPKT_DATA_MAX_BYTES_USBHS 507 /* The data length contained in each command packet during USB high-speed operation */ +#define USBC_PACKET_USBHS 512 /* Maximum data length per packet at USB high speed */ +#define USBC_PACKET_USBHS_SINGLE 510 /* usb high speed max package length */ #define CH347_CMD_HEADER 3 /* Protocol header length */ +#define MAX_BITS_PER_BIT_OP 248 /* No more bits are allowed per CH347_CMD_JTAG_BIT_OP command; this should be dividable by 8 */ #define CH347_GPIO_CMD_LENGTH (CH347_CMD_HEADER + GPIO_CNT) /* fixed length of the GPIO control command*/ /* Protocol transmission format: CMD (1 byte)+Length (2 bytes)+Data */ -#define CH347_CMD_INFO_RD 0xCA /* Parameter acquisition, used to - obtain firmware version, - JTAG interface related parameters, - etc */ +#define CH347_CMD_INFO_RD 0xCA /* Parameter acquisition, used to obtain firmware version, JTAG interface related parameters, etc */ #define CH347_CMD_GPIO 0xCC /* GPIO Command */ -#define CH347_CMD_JTAG_INIT 0xD0 /* JTAG Interface Initialization - Command */ -#define CH347_CMD_JTAG_BIT_OP 0xD1 /* JTAG interface pin bit control - command */ -#define CH347_CMD_JTAG_BIT_OP_RD 0xD2 /* JTAG interface pin bit control and - read commands */ -#define CH347_CMD_JTAG_DATA_SHIFT 0xD3 /* JTAG interface data shift - command */ -#define CH347_CMD_JTAG_DATA_SHIFT_RD 0xD4 /* JTAG interface data shift and read - command */ +#define CH347_CMD_JTAG_INIT 0xD0 /* JTAG Interface initialization command */ +#define CH347_CMD_JTAG_BIT_OP 0xD1 /* JTAG interface pin bit control command */ +#define CH347_CMD_JTAG_BIT_OP_RD 0xD2 /* JTAG interface pin bit control and read commands */ +#define CH347_CMD_JTAG_DATA_SHIFT 0xD3 /* JTAG interface data shift command */ +#define CH347_CMD_JTAG_DATA_SHIFT_RD 0xD4 /* JTAG interface data shift and read command */ /* SWD */ #define CH347_CMD_SWD_INIT 0xE5 /* SWD Interface Initialization Command */ #define CH347_CMD_SWD 0xE8 @@ -156,6 +145,7 @@ typedef struct _CH347_info /* Record the CH347 pin status */ uint32_t read_count; struct bit_copy_queue read_queue; PACK_SIZE pack_size; + bool use_bitwise_write_read; } _CH347_Info; int DevIsOpened; /* Whether the device is turned on */ @@ -167,6 +157,7 @@ static uint16_t ch347_pids[] = {0x55dd, 0}; static char *ch347_device_desc = NULL; static uint8_t ch347_activity_led_gpio_pin = 0xFF; static bool ch347_activity_led_active_high = false; +_CH347_Info ch347; typedef struct _CH347_SWD_IO { uint8_t usbcmd; /* 0xA0、0xA1、0xA2 */ @@ -263,11 +254,7 @@ static uint32_t CH347OpenDevice(uint64_t iIndex) struct libusb_device_descriptor ch347_device_descriptor; libusb_get_device_descriptor(libusb_get_device(ch347_handle), &ch347_device_descriptor); - if (ch347_device_descriptor.bcdDevice < 0x241) { - LOG_ERROR("ch347 old version of the chip, JTAG not working. Need at least version 2.41."); - return false; - } - + if (libusb_claim_interface(ch347_handle, CH347_MPHSI_INTERFACE)) { LOG_ERROR("ch347 unable to claim interface"); return false; @@ -282,10 +269,18 @@ static uint32_t CH347OpenDevice(uint64_t iIndex) return false; } - LOG_INFO("CH347 found (Chip version=%2X.%2X, Firmware=0x%02X)", + LOG_INFO("CH347 found (Chip version=%X.%2X, Firmware=0x%02X)", (ch347_device_descriptor.bcdDevice >> 8) & 0xFF, ch347_device_descriptor.bcdDevice & 0xFF, - firmwareVersion); + firmwareVersion); + + if (ch347_device_descriptor.bcdDevice < 0x241) { + LOG_INFO("ch347 old version of the chip, JTAG only working in bitwise mode. For bytewise mode at least version 2.41 is neeed."); + ch347.use_bitwise_write_read = true; + } else + { + ch347.use_bitwise_write_read = false; + } return true; } @@ -331,8 +326,6 @@ static bool CH347CloseDevice(uint64_t iIndex) #endif -_CH347_Info ch347; - static int ch347_swd_run_queue(void); /* swd init func */ static bool CH347SWD_INIT(uint64_t iIndex, uint8_t iClockRate) @@ -468,6 +461,7 @@ static void CH347_Read_Scan(UCHAR *pBuffer, uint32_t length) unsigned long read_buf_index = 0; unsigned char *read_buf = NULL; int dataLen = 0, i = 0; /*, this_bits = 0; */ + int bitCounter = 0; read_size = length; RxLen = read_size; @@ -492,12 +486,16 @@ static void CH347_Read_Scan(UCHAR *pBuffer, uint32_t length) for (i = 0; i < dataLen; i++) { if (read_buf[index + 1 + i] & 1) - *(pBuffer + read_buf_index) |= (1 << i); + *(pBuffer + read_buf_index) |= (1 << i % 8); else - *(pBuffer + read_buf_index) &= ~(1 << i); + *(pBuffer + read_buf_index) &= ~(1 << i % 8); + bitCounter++; + if (bitCounter % 8 == 0) + read_buf_index++; } - read_buf_index += 1; index += dataLen + 1; + if (bitCounter % 8 != 0) + read_buf_index++; } else { LOG_ERROR("CH347 read command fail"); *(pBuffer + read_buf_index) = read_buf[index]; @@ -610,12 +608,12 @@ static unsigned long CH347_ClockTms(int tms, unsigned long BI) BI += 2; - data = cmd | TDI_L | TCK_L | TRST_H; + uint8_t tdiBit = ch347.TDI ? TDI_H : TDI_L; + data = cmd | tdiBit | TCK_L | TRST_H; CH347_In_Buffer(data); - data = cmd | TDI_L | TCK_H | TRST_H; + data = cmd | tdiBit | TCK_H | TRST_H; CH347_In_Buffer(data); ch347.TMS = cmd; - ch347.TDI = TDI_L; ch347.TCK = TCK_H; ch347.TRST = TRST_H; @@ -818,6 +816,137 @@ static void CH347_MoveState(tap_state_t state, int skip) tap_set_state(state); } +static void CH347_ScanDataToFields(struct scan_command *cmd, uint8_t *readData) +{ + int offset = 0; + int numBits = 0; + + for (int i = 0; i < cmd->num_fields; i++) { + /* if neither in_value nor in_handler + * are specified we don't have to examine this field + */ + LOG_DEBUG("fields[%i].in_value[%i], offset: %d", i, cmd->fields[i].num_bits, offset); + numBits = cmd->fields[i].num_bits; + if (cmd->fields[i].in_value) { + if (ch347.pack_size == LARGER_PACK) { + if (cmd->fields[i].in_value) + bit_copy_queued(&ch347.read_queue, cmd->fields[i].in_value, 0, &ch347.read_buffer[ch347.read_idx], offset, numBits); + + if (numBits > 7) + ch347.read_idx += DIV_ROUND_UP(offset, 8); + } else { + uint8_t *captured = buf_set_buf(readData, offset, malloc(DIV_ROUND_UP(numBits, 8)), 0, numBits); + + if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) { + char *char_buf = buf_to_hex_str(captured, (numBits > DEBUG_JTAG_IOZ) ? DEBUG_JTAG_IOZ : numBits); + free(char_buf); + } + if (cmd->fields[i].in_value) + buf_cpy(captured, cmd->fields[i].in_value, numBits); + free(captured); + } + } + offset += numBits; + } +} + +/** + * CH347_WriteReadBitwise - CH347 Batch read/write function + * That's the workaround function for write/read bit by bit because the + * bytewise functions D3/D4 are not working correctly + * @param bits Read and write data this time + * @param nb_bits Incoming data length + * @param scan The transmission method of incoming data to determine whether + * to perform data reading + */ +static void CH347_WriteReadBitwise(struct scan_command *cmd, uint8_t *bits, + int nb_bits, enum scan_type scan) +{ + int i = 0; + int chunkDataLength = 0; + int chunkBitCount = 0; + int chunkCount = 0; + uint8_t tmsBit = 0; + uint8_t tdiBit = 0; + + if (ch347.pack_size == LARGER_PACK) { + if ((ch347.read_count >= (USBC_PACKET_USBHS_SINGLE * 1))) + CH347_Flush_Buffer(); + } else { + CH347_Flush_Buffer(); + } + + bool isRead = (scan == SCAN_IN || scan == SCAN_IO); + + while (i < nb_bits) { + // we need two bytes for each bit (one for TCK_L and one for TCK_H) + if ((nb_bits - i) > MAX_BITS_PER_BIT_OP) { + chunkBitCount = MAX_BITS_PER_BIT_OP; + chunkDataLength = chunkBitCount * 2; + } else { + // an additional TCK_L after the last byte is needed because that's the last chunk + chunkDataLength = (nb_bits - i) * 2 + 1; + chunkBitCount = nb_bits - i; + } + + // build the cmd header + if (isRead) + CH347_In_Buffer(CH347_CMD_JTAG_BIT_OP_RD); + else + CH347_In_Buffer(CH347_CMD_JTAG_BIT_OP); + CH347_In_Buffer((uint8_t)chunkDataLength & 0xFF); + CH347_In_Buffer((uint8_t)(chunkDataLength >> 8) & 0xFF); + + tmsBit = TMS_L; + for (int j = 0; j < chunkBitCount; j++) { + tdiBit = ((bits[i / 8] >> i % 8) & 0x01) ? TDI_H : TDI_L; + // for the last bit set TMS high to exit the shift state + if ((i + 1) == nb_bits) + tmsBit = TMS_H; + + CH347_In_Buffer(tmsBit | tdiBit | TCK_L | TRST_H); + CH347_In_Buffer(tmsBit | tdiBit | TCK_H | TRST_H); + + i++; + } + // one TCK_L after the last bit + if (i == nb_bits) { + CH347_In_Buffer(tmsBit | tdiBit | TCK_L | TRST_H); + } + + chunkCount++; + } + + ch347.TMS = tmsBit; + ch347.TDI = tdiBit; + ch347.TCK = TCK_L; + + uint8_t *readData = NULL; + if (isRead) { + readData = calloc(SF_PACKET_BUF_SIZE, 1); + uint32_t readLen = nb_bits + chunkCount * CH347_CMD_HEADER; + ch347.read_count = readLen; + + if (ch347.pack_size == STANDARD_PACK && bits && cmd) { + CH347_Flush_Buffer(); + CH347_Read_Scan(readData, readLen); + } + + CH347_ScanDataToFields(cmd, readData); + } + + int tempIndex = ch347.buffer_idx; + for (i = 0; i < CH347_CMD_HEADER; i++) + CH347_In_Buffer(0); + unsigned long byteIndex = CH347_CMD_HEADER; + byteIndex = CH347_IdleClock(byteIndex); + combinePackets(CH347_CMD_JTAG_BIT_OP, tempIndex, byteIndex); + if (readData) { + free(readData); + readData = NULL; + } +} + /** * CH347_WriteRead - CH347 Batch read/write function * @param bits Read and write data this time @@ -828,9 +957,14 @@ static void CH347_MoveState(tap_state_t state, int skip) static void CH347_WriteRead(struct scan_command *cmd, uint8_t *bits, int nb_bits, enum scan_type scan) { + if (ch347.use_bitwise_write_read) { + CH347_WriteReadBitwise(cmd, bits, nb_bits, scan); + return; + } + int nb8 = nb_bits / 8; int nb1 = nb_bits % 8; - int i, num_bits = 0; + int i = 0; bool IsRead = false; /*, isLastByte = false */ uint8_t TMS_Bit = 0, TDI_Bit = 0, CMD_Bit; static uint8_t byte0[SF_PACKET_BUF_SIZE]; @@ -942,63 +1076,13 @@ static void CH347_WriteRead(struct scan_command *cmd, uint8_t *bits, readLen += tempLength; DI = BI = 0; } - int offset = 0, bit_count = 0; if (IsRead && totalReadLength > 0) { if (ch347.pack_size == STANDARD_PACK && bits && cmd) { CH347_Flush_Buffer(); CH347_Read_Scan(readData, readLen); } - for (i = 0; i < cmd->num_fields; i++) { - /* if neither in_value nor in_handler - * are specified we don't have to examine this field - */ - LOG_DEBUG("fields[%i].in_value[%i], offset: %d", - i, cmd->fields[i].num_bits, offset); - if (cmd->fields[i].in_value) { - num_bits = cmd->fields[i].num_bits; - - if (ch347.pack_size == LARGER_PACK) { - bit_count += num_bits; - if (cmd->fields[i].in_value) - bit_copy_queued( - &ch347.read_queue, - cmd->fields[i].in_value, - 0, - &ch347.read_buffer[ch347.read_idx], - offset, num_bits); - - if (num_bits > 7) - ch347.read_idx += - DIV_ROUND_UP(bit_count, - 8); - offset += num_bits; - } else { - uint8_t *captured = buf_set_buf( - readData, bit_count, - malloc(DIV_ROUND_UP(num_bits, - 8)), 0, - num_bits); - - if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) { - char *char_buf = - buf_to_hex_str( - captured, - (num_bits > - DEBUG_JTAG_IOZ) - ? DEBUG_JTAG_IOZ - : num_bits); - free(char_buf); - } - if (cmd->fields[i].in_value) - buf_cpy(captured, - cmd->fields[i].in_value, - num_bits); - free(captured); - } - bit_count += cmd->fields[i].num_bits; - } - } + CH347_ScanDataToFields(cmd, readData); } tempIndex = ch347.buffer_idx; From c5dd1ab040c62ab77397cc3c4c02da8384004b7a Mon Sep 17 00:00:00 2001 From: EasyDevKits <142944713+EasyDevKits@users.noreply.github.com> Date: Mon, 9 Oct 2023 00:49:01 +0200 Subject: [PATCH 13/22] Sync with latest espressif/openocd-esp32 (#1) * esp/ci: Makes OpenOCD tool name in lower case in IDF branch name * esp/ci: update openocd-ci-env and remove install packages --------- Co-authored-by: Alexey Gerenkov Co-authored-by: Erhan Kurubas --- .gitlab-ci.yml | 2 +- .gitlab/ci/build.yml | 2 -- .gitlab/ci/pre-check.yml | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 534f3dacd2..0b35413c3a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -369,7 +369,7 @@ update_idf_tools: allow_failure: true <<: *release_tag_filter variables: - TOOL_NAME: OpenOCD + TOOL_NAME: openocd TOOL_MEMBERS: openocd-esp32 TOOL_VERSION: ${CI_COMMIT_TAG} TOOL_SHA256_URL: https://github.com/espressif/openocd-esp32/releases/download/${CI_COMMIT_TAG}/openocd-esp32-${CI_COMMIT_TAG}-checksum.sha256 diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index 03361a316a..72752cd4d5 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -303,7 +303,6 @@ scan-build: - mkdir -p ${SCAN_BUILD_OUTPUT} - mv scan_build.${ARCHIVE_EXT} ${SCAN_BUILD_OUTPUT} - cp build-scanbuild/out/*/index.html scanbuild_reference.html - - apt-get update && apt-get install pip && pip install beautifulsoup4 - SCANBUILD_REF_FILE="tools/scanbuild_reference.txt" - SCANBUILD_OUT_FILE="scanbuild_report.txt" - python3 tools/scanbuild_parser.py -i scanbuild_reference.html -o $SCANBUILD_OUT_FILE @@ -326,7 +325,6 @@ sparse: script: - !reference [.add_gitlab_key, script] - !reference [.submodules_mirror_update, script] - - apt-get update && apt-get install sparse - ./bootstrap - mkdir build-sparse && pushd build-sparse - ../configure CC=cgcc CFLAGS="-Wsparse-all -Wno-declaration-after-statement -Wno-unknown-attribute -Wno-transparent-union -Wno-tautological-compare -Wno-vla -Wno-flexible-array-array -D__FLT_EVAL_METHOD__=0" diff --git a/.gitlab/ci/pre-check.yml b/.gitlab/ci/pre-check.yml index f595fb6104..1df89c494f 100644 --- a/.gitlab/ci/pre-check.yml +++ b/.gitlab/ci/pre-check.yml @@ -4,7 +4,6 @@ style_check: - build script: - tools/check-line-endings.sh $PWD - - apt-get update && apt-get install patchutils python3-ply python3-git -y - tools/checkpatch-esp.sh esp_config_check: From d012d48923395fc2d27083ee2722bc6b87186834 Mon Sep 17 00:00:00 2001 From: EasyDevKits Date: Mon, 9 Oct 2023 12:10:25 +0200 Subject: [PATCH 14/22] Dependency to CH347DLL.DLL removed. Changed some unsigned long to uint64_t to make the windows compiler happy. --- src/jtag/drivers/ch347.c | 94 ++++------------------------------------ 1 file changed, 8 insertions(+), 86 deletions(-) diff --git a/src/jtag/drivers/ch347.c b/src/jtag/drivers/ch347.c index 3dfe666d66..888f0187eb 100755 --- a/src/jtag/drivers/ch347.c +++ b/src/jtag/drivers/ch347.c @@ -183,58 +183,6 @@ static CH347_SWD_CONTEXT ch347_swd_context; static bool swd_mode; #pragma pack() -#ifdef _WIN32 -#include - -typedef int(__stdcall * pCH347OpenDevice)(unsigned long iIndex); - -typedef int(__stdcall * pCH347CloseDevice)(unsigned long iIndex); - -typedef unsigned long(__stdcall * pCH347SetTimeout)( - unsigned long iIndex, /* Specify equipment serial number */ - unsigned long iWriteTimeout, /* Specifies the timeout period for USB - write out data blocks, in milliseconds - mS, and 0xFFFFFFFF specifies no timeout - (default) */ - unsigned long iReadTimeout); /* Specifies the timeout period for USB - reading data blocks, in milliseconds mS, - and 0xFFFFFFFF specifies no timeout - (default) */ - -typedef unsigned long(__stdcall * pCH347WriteData)( - unsigned long iIndex, /* Specify equipment serial number */ - void *oBuffer, /* Point to a buffer large enough to hold - the descriptor */ - unsigned long *ioLength); /* Pointing to the length unit, the input - is the length to be read, and the - return is the actual read length */ - -typedef unsigned long(__stdcall * pCH347ReadData)( - unsigned long iIndex, /* Specify equipment serial number */ - void *oBuffer, /* Point to a buffer large enough to - hold the descriptor */ - unsigned long *ioLength); /* Pointing to the length unit, the input - is the length to be read, and the - return is the actual read length */ - -typedef unsigned long(__stdcall * pCH347Jtag_INIT)( - unsigned long iIndex, /* Specify equipment serial number */ - unsigned char iClockRate); /* Pointing to the length unit, the input - is the length to be read, and the - return is the actual read length */ -HMODULE uhModule; -BOOL ugOpen; -unsigned long ugIndex; -pCH347OpenDevice CH347OpenDevice; -pCH347CloseDevice CH347CloseDevice; -pCH347SetTimeout CH347SetTimeout; -pCH347ReadData CH347ReadData; -pCH347WriteData CH347WriteData; -/* pCH347Jtag_INIT CH347Jtag_INIT; */ -#elif defined(__linux__) - -#include - #define CH347_EPOUT 0x06u #define CH347_EPIN 0x86u #define CH347_MPHSI_INTERFACE 2 @@ -324,8 +272,6 @@ static bool CH347CloseDevice(uint64_t iIndex) return true; } -#endif - static int ch347_swd_run_queue(void); /* swd init func */ static bool CH347SWD_INIT(uint64_t iIndex, uint8_t iClockRate) @@ -343,7 +289,7 @@ static bool CH347SWD_INIT(uint64_t iIndex, uint8_t iClockRate) cmdBuf[i++] = iClockRate; /* JTAG clock speed */ i += 3; /* Reserved Bytes */ - unsigned long mLength = i; + uint64_t mLength = i; if (!CH347WriteData(iIndex, cmdBuf, &mLength) || (mLength != i)) return false; @@ -387,7 +333,7 @@ static char *HexToString(uint8_t *buf, uint32_t size) static int CH347_Write(void *oBuffer, unsigned long *ioLength) { int ret = -1; - unsigned long wlength = *ioLength, WI; + uint64_t wlength = *ioLength, WI; if (*ioLength >= HW_TDO_BUF_SIZE) wlength = HW_TDO_BUF_SIZE; WI = 0; @@ -398,7 +344,7 @@ static int CH347_Write(void *oBuffer, unsigned long *ioLength) *ioLength = 0; return false; } - LOG_DEBUG_IO("(size=%lu, buf=[%s]) -> %" PRIu32, wlength, + LOG_DEBUG_IO("(size=%" PRIu64 ", buf=[%s]) -> %" PRIu32, wlength, HexToString((uint8_t *)oBuffer, wlength), (uint32_t)wlength); WI += wlength; @@ -424,7 +370,7 @@ static int CH347_Write(void *oBuffer, unsigned long *ioLength) */ static int CH347_Read(void *oBuffer, unsigned long *ioLength) { - unsigned long rlength = *ioLength, WI; + uint64_t rlength = *ioLength, WI; /* The maximum allowable reading for a single read is 4096B of data. If it exceeds the allowable reading limit, it will be calculated as 4096B */ @@ -447,7 +393,7 @@ static int CH347_Read(void *oBuffer, unsigned long *ioLength) else rlength = *ioLength - WI; } - LOG_DEBUG_IO("(size=%lu, buf=[%s]) -> %" PRIu32, WI, + LOG_DEBUG_IO("(size=%" PRIu64 ", buf=[%s]) -> %" PRIu32, WI, HexToString((uint8_t *)oBuffer, WI), (uint32_t)WI); *ioLength = WI; return true; @@ -1227,33 +1173,9 @@ static int ch347_execute_queue(void) */ static int ch347_init(void) { -#ifdef _WIN32 - if (uhModule == 0) { - uhModule = LoadLibrary("CH347DLL.DLL"); - if (uhModule) { - CH347OpenDevice = (pCH347OpenDevice)GetProcAddress( - uhModule, "CH347OpenDevice"); - CH347CloseDevice = (pCH347CloseDevice)GetProcAddress( - uhModule, "CH347CloseDevice"); - CH347ReadData = (pCH347ReadData)GetProcAddress( - uhModule, "CH347ReadData"); - CH347WriteData = (pCH347WriteData)GetProcAddress( - uhModule, "CH347WriteData"); - CH347SetTimeout = (pCH347SetTimeout)GetProcAddress( - uhModule, "CH347SetTimeout"); - if (CH347OpenDevice == NULL || CH347CloseDevice == NULL - || CH347SetTimeout == NULL || CH347ReadData == NULL - || CH347WriteData == NULL) { - LOG_ERROR("Jtag_init error "); - return ERROR_FAIL; - } - } - } - DevIsOpened = CH347OpenDevice(ugIndex); -#elif defined(__linux__) DevIsOpened = CH347OpenDevice(ugIndex); ugIndex = DevIsOpened; -#endif + if (DevIsOpened < 0) { LOG_ERROR("CH347 open error"); return ERROR_FAIL; @@ -1329,7 +1251,7 @@ static bool Check_Speed(uint64_t iIndex, uint8_t iClockRate) for (j = 0; j < 4; j++) cmdBuf[i++] = ch347.TCK | ch347.TDI | ch347.TMS | ch347.TRST; - unsigned long int mLength = i; + uint64_t mLength = i; if (!CH347WriteData(iIndex, cmdBuf, &mLength) || (mLength != i)) return false; @@ -1587,7 +1509,7 @@ static PCH347_SWD_IO ch347_get_one_swd_io(void) static void ch347_swd_queue_flush(void) { - unsigned long mLength = ch347_swd_context.send_len; + uint64_t mLength = ch347_swd_context.send_len; ch347_swd_context.send_buf[0] = (uint8_t)CH347_CMD_SWD; ch347_swd_context.send_buf[1] = (uint8_t)(ch347_swd_context.send_len - CH347_CMD_HEADER); From 41d7da7949089b06ffee12e06f680b6509ad378d Mon Sep 17 00:00:00 2001 From: EasyDevKits Date: Mon, 9 Oct 2023 23:44:20 +0200 Subject: [PATCH 15/22] coding style adjusted mostly to existing code --- src/jtag/drivers/ch347.c | 1021 +++++++++++++++++++++----------------- 1 file changed, 567 insertions(+), 454 deletions(-) diff --git a/src/jtag/drivers/ch347.c b/src/jtag/drivers/ch347.c index 888f0187eb..bdb1650c2f 100755 --- a/src/jtag/drivers/ch347.c +++ b/src/jtag/drivers/ch347.c @@ -4,6 +4,8 @@ * Copyright (C) 2022 by oidcat. * * Author: oidcatiot@163.com * * * + * Enhancements by EasyDevKits - info@easydevkits.com * + * * * CH347 is a high-speed USB bus converter chip that provides UART, I2C * * and SPI synchronous serial ports and JTAG interface through USB bus. * * * @@ -62,61 +64,65 @@ #include #include -#define JTAGIO_STA_OUT_TDI (0x10) -#define JTAGIO_STA_OUT_TMS (0x02) -#define JTAGIO_STA_OUT_TCK (0x01) -#define JTAGIO_STA_OUT_TRST (0x20) -#define TDI_H JTAGIO_STA_OUT_TDI -#define TDI_L 0 -#define TMS_H JTAGIO_STA_OUT_TMS -#define TMS_L 0 -#define TCK_H JTAGIO_STA_OUT_TCK -#define TCK_L 0 -#define TRST_H JTAGIO_STA_OUT_TRST -#define TRST_L 0 -#define LED_ON 1 -#define LED_OFF 0 -#define GPIO_CNT 8 /* the CH347 has 8 GPIO's */ -#define USEABLE_GPIOS 0x78 /* mask which GPIO's are available in mode 3 of CH347T - only GPIO3 (Pin11 / SCL), GPIO4 (Pin15 / ACT), - GPIO5 (Pin9 / TRST) and GPIO6 (Pin2 / CTS1) are possible - Tested only with CH347T not CH347F chip - pin numbers are for CH347T */ - -#define VENDOR_VERSION 0x5F - -#define KHZ(n) ((n)*UINT64_C(1000)) -#define MHZ(n) ((n)*UINT64_C(1000000)) -#define GHZ(n) ((n)*UINT64_C(1000000000)) - -#define HW_TDO_BUF_SIZE 4096 -#define SF_PACKET_BUF_SIZE 51200 /* Command packet length */ -#define UCMDPKT_DATA_MAX_BYTES_USBHS 507 /* The data length contained in each command packet during USB high-speed operation */ -#define USBC_PACKET_USBHS 512 /* Maximum data length per packet at USB high speed */ -#define USBC_PACKET_USBHS_SINGLE 510 /* usb high speed max package length */ -#define CH347_CMD_HEADER 3 /* Protocol header length */ -#define MAX_BITS_PER_BIT_OP 248 /* No more bits are allowed per CH347_CMD_JTAG_BIT_OP command; this should be dividable by 8 */ -#define CH347_GPIO_CMD_LENGTH (CH347_CMD_HEADER + GPIO_CNT) /* fixed length of the GPIO control command*/ +#define JTAGIO_STA_OUT_TDI (0x10) +#define JTAGIO_STA_OUT_TMS (0x02) +#define JTAGIO_STA_OUT_TCK (0x01) +#define JTAGIO_STA_OUT_TRST (0x20) +#define TDI_H JTAGIO_STA_OUT_TDI +#define TDI_L 0 +#define TMS_H JTAGIO_STA_OUT_TMS +#define TMS_L 0 +#define TCK_H JTAGIO_STA_OUT_TCK +#define TCK_L 0 +#define TRST_H JTAGIO_STA_OUT_TRST +#define TRST_L 0 +#define LED_ON 1 +#define LED_OFF 0 +#define GPIO_CNT 8 /* the CH347 has 8 GPIO's */ +#define USEABLE_GPIOS 0x78 /* mask which GPIO's are available in mode 3 of CH347T + only GPIO3 (Pin11 / SCL), GPIO4 (Pin15 / ACT), + GPIO5 (Pin9 / TRST) and GPIO6 (Pin2 / CTS1) are possible + Tested only with CH347T not CH347F chip - pin numbers are for CH347T */ +#define VENDOR_VERSION 0x5F /* for getting the chip version */ + +#define KHZ(n) ((n)*UINT64_C(1000)) +#define MHZ(n) ((n)*UINT64_C(1000000)) +#define GHZ(n) ((n)*UINT64_C(1000000000)) + +#define HW_TDO_BUF_SIZE 4096 +#define SF_PACKET_BUF_SIZE 51200 /* Command packet length */ +#define UCMDPKT_DATA_MAX_BYTES_USBHS 507 /* The data length contained in each command packet during USB high-speed operation */ +#define USBC_PACKET_USBHS 512 /* Maximum data length per packet at USB high speed */ +#define USBC_PACKET_USBHS_SINGLE 510 /* usb high speed max package length */ +#define CH347_CMD_HEADER 3 /* Protocol header length */ +#define MAX_BITS_PER_BIT_OP 248 /* No more bits are allowed per CH347_CMD_JTAG_BIT_OP command; this should be dividable by 8 */ +#define CH347_GPIO_CMD_LENGTH ( CH347_CMD_HEADER + GPIO_CNT) /* fixed length of the GPIO control command*/ /* Protocol transmission format: CMD (1 byte)+Length (2 bytes)+Data */ -#define CH347_CMD_INFO_RD 0xCA /* Parameter acquisition, used to obtain firmware version, JTAG interface related parameters, etc */ -#define CH347_CMD_GPIO 0xCC /* GPIO Command */ - -#define CH347_CMD_JTAG_INIT 0xD0 /* JTAG Interface initialization command */ -#define CH347_CMD_JTAG_BIT_OP 0xD1 /* JTAG interface pin bit control command */ -#define CH347_CMD_JTAG_BIT_OP_RD 0xD2 /* JTAG interface pin bit control and read commands */ -#define CH347_CMD_JTAG_DATA_SHIFT 0xD3 /* JTAG interface data shift command */ -#define CH347_CMD_JTAG_DATA_SHIFT_RD 0xD4 /* JTAG interface data shift and read command */ -/* SWD */ -#define CH347_CMD_SWD_INIT 0xE5 /* SWD Interface Initialization Command */ -#define CH347_CMD_SWD 0xE8 -#define CH347_CMD_SWD_REG_W 0xA0 /* SWD Interface write reg */ -#define CH347_CMD_SWD_SEQ_W 0xA1 /* SWD Interface write spec seq */ -#define CH347_CMD_SWD_REG_R 0xA2 /* SWD Interface read reg */ -#define CH347_MAX_SEND_CMD 0X20 /* max send cmd number */ -#define CH347_MAX_SEND_BUF 0X200 -#define CH347_MAX_RECV_BUF 0X200 -#define BUILD_UINT16(loByte, hiByte) \ - ((uint16_t)(((loByte)&0x00FF) + (((hiByte)&0x00FF) << 8))) +#define CH347_CMD_INFO_RD 0xCA /* Parameter acquisition, used to obtain firmware version, JTAG interface related parameters, etc */ +#define CH347_CMD_GPIO 0xCC /* GPIO Command */ +#define CH347_CMD_JTAG_INIT 0xD0 /* JTAG Interface initialization command */ +#define CH347_CMD_JTAG_BIT_OP 0xD1 /* JTAG interface pin bit control command */ +#define CH347_CMD_JTAG_BIT_OP_RD 0xD2 /* JTAG interface pin bit control and read commands */ +#define CH347_CMD_JTAG_DATA_SHIFT 0xD3 /* JTAG interface data shift command */ +#define CH347_CMD_JTAG_DATA_SHIFT_RD 0xD4 /* JTAG interface data shift and read command */ +/* for SWD */ +#define CH347_CMD_SWD_INIT 0xE5 /* SWD Interface Initialization Command */ +#define CH347_CMD_SWD 0xE8 +#define CH347_CMD_SWD_REG_W 0xA0 /* SWD Interface write reg */ +#define CH347_CMD_SWD_SEQ_W 0xA1 /* SWD Interface write spec seq */ +#define CH347_CMD_SWD_REG_R 0xA2 /* SWD Interface read reg */ +#define CH347_MAX_SEND_CMD 0X20 /* max send cmd number */ +#define CH347_MAX_SEND_BUF 0X200 +#define CH347_MAX_RECV_BUF 0X200 +#define BUILD_UINT16(loByte, hiByte) ((uint16_t)(((loByte)&0x00FF) + (((hiByte)&0x00FF) << 8))) + +#define CH347_EPOUT 0x06u /* the usb endpoint number for writing */ +#define CH347_EPIN 0x86u /* the usb endpoint number for reading */ +#define CH347_MPHSI_INTERFACE 2 /* the JTAG interface is number 2 */ +#define USB_WRITE_TIMEOUT 500 +#define USB_READ_TIMEOUT 500 + #pragma pack(1) typedef unsigned char UCHAR; @@ -145,20 +151,9 @@ typedef struct _CH347_info /* Record the CH347 pin status */ uint32_t read_count; struct bit_copy_queue read_queue; PACK_SIZE pack_size; - bool use_bitwise_write_read; + void (*writeRead)(struct scan_command *cmd, uint8_t *bits, int nb_bits, enum scan_type scan); } _CH347_Info; -int DevIsOpened; /* Whether the device is turned on */ -bool UsbHighDev = true; -unsigned long USBC_PACKET; - -static uint16_t ch347_vids[] = {0x1a86, 0}; -static uint16_t ch347_pids[] = {0x55dd, 0}; -static char *ch347_device_desc = NULL; -static uint8_t ch347_activity_led_gpio_pin = 0xFF; -static bool ch347_activity_led_active_high = false; -_CH347_Info ch347; - typedef struct _CH347_SWD_IO { uint8_t usbcmd; /* 0xA0、0xA1、0xA2 */ uint8_t cmd; @@ -179,21 +174,30 @@ typedef struct _CH347_SWD_CONTEXT { struct list_head free_cmd_head; uint8_t *ch347_cmd_buf; } CH347_SWD_CONTEXT; -static CH347_SWD_CONTEXT ch347_swd_context; -static bool swd_mode; -#pragma pack() -#define CH347_EPOUT 0x06u -#define CH347_EPIN 0x86u -#define CH347_MPHSI_INTERFACE 2 +#pragma pack() -bool ugOpen; -unsigned long ugIndex; +static CH347_SWD_CONTEXT ch347_swd_context; +static bool swd_mode; +static bool dev_is_opened; /* Whether the device is turned on */ +static uint16_t ch347_vids[] = {0x1a86, 0}; +static uint16_t ch347_pids[] = {0x55dd, 0}; +static char *ch347_device_desc = NULL; +static uint8_t ch347_activity_led_gpio_pin = 0xFF; +static bool ch347_activity_led_active_high = false; +_CH347_Info ch347; struct libusb_device_handle *ch347_handle; -uint32_t usb_write_timeout = 500; -uint32_t usb_read_timeout = 500; -static uint32_t CH347OpenDevice(uint64_t iIndex) +// private functions +static void ch347_write_read(struct scan_command *cmd, uint8_t *bits, int nb_bits, enum scan_type scan); +static void ch347_write_read_bitwise(struct scan_command *cmd, uint8_t *bits, int nb_bits, enum scan_type scan); + +/** + * @brief opens the CH347 device via libusb driver + * + * @return true at success + */ +static bool ch347_open_device(void) { if (jtag_libusb_open(ch347_vids, ch347_pids, ch347_device_desc, &ch347_handle, NULL) != ERROR_OK) { LOG_ERROR("ch347 not found: vid=%04x, pid=%04x", ch347_vids[0], ch347_pids[0]); @@ -211,7 +215,7 @@ static uint32_t CH347OpenDevice(uint64_t iIndex) char firmwareVersion; if (jtag_libusb_control_transfer(ch347_handle, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, - VENDOR_VERSION, 0, 0, &firmwareVersion, sizeof(firmwareVersion), usb_write_timeout, NULL) != ERROR_OK) + VENDOR_VERSION, 0, 0, &firmwareVersion, sizeof(firmwareVersion), USB_WRITE_TIMEOUT, NULL) != ERROR_OK) { LOG_ERROR("ch347 unable to get firmware version"); return false; @@ -224,22 +228,25 @@ static uint32_t CH347OpenDevice(uint64_t iIndex) if (ch347_device_descriptor.bcdDevice < 0x241) { LOG_INFO("ch347 old version of the chip, JTAG only working in bitwise mode. For bytewise mode at least version 2.41 is neeed."); - ch347.use_bitwise_write_read = true; + ch347.writeRead = ch347_write_read_bitwise; } else { - ch347.use_bitwise_write_read = false; + ch347.writeRead = ch347_write_read; } return true; } -static bool CH347WriteData(uint64_t iIndex, uint8_t *data, uint64_t *length) +/** + * @brief writes data to the CH347 via libusb driver + * @param data Point to the data buffer + * @param length Data length in and out + * + * @return true at success + */ +static bool ch347_write_data(uint8_t *data, uint64_t *length) { int ret, tmp = 0; - ret = jtag_libusb_bulk_write(ch347_handle, - CH347_EPOUT, - (char *)data, - *length, - usb_write_timeout, &tmp); + ret = jtag_libusb_bulk_write(ch347_handle, CH347_EPOUT, (char *)data, *length, USB_WRITE_TIMEOUT, &tmp); *length = tmp; if (!ret) @@ -248,16 +255,19 @@ static bool CH347WriteData(uint64_t iIndex, uint8_t *data, uint64_t *length) return false; } -static bool CH347ReadData(uint64_t iIndex, uint8_t *data, uint64_t *length) +/** + * @brief reads data from the CH347 via libusb driver + * @param data Point to the data buffer + * @param length Data length in and out + * + * @return true at success + */ +static bool ch347_read_data(uint8_t *data, uint64_t *length) { int ret, tmp = 0; int size = *length; - ret = jtag_libusb_bulk_read(ch347_handle, - CH347_EPIN, - (char *)data, - size, - usb_read_timeout, &tmp); + ret = jtag_libusb_bulk_read(ch347_handle, CH347_EPIN, (char *)data, size, USB_READ_TIMEOUT, &tmp); *length = tmp; if (!ret) @@ -266,15 +276,24 @@ static bool CH347ReadData(uint64_t iIndex, uint8_t *data, uint64_t *length) return false; } -static bool CH347CloseDevice(uint64_t iIndex) +/** + * @brief closes the CH347 device via libusb driver + * + * @return true at success + */ +static bool ch347_close_device(void) { jtag_libusb_close(ch347_handle); return true; } -static int ch347_swd_run_queue(void); -/* swd init func */ -static bool CH347SWD_INIT(uint64_t iIndex, uint8_t iClockRate) +/** + * @brief swd init function + * @param iClockRate clock index for CH347_CMD_SWD_INIT (E5) + * + * @return true at success + */ +static bool ch347_swd_init_cmd(uint8_t iClockRate) { uint8_t cmdBuf[128] = ""; unsigned long i = 0; @@ -290,26 +309,26 @@ static bool CH347SWD_INIT(uint64_t iIndex, uint8_t iClockRate) i += 3; /* Reserved Bytes */ uint64_t mLength = i; - if (!CH347WriteData(iIndex, cmdBuf, &mLength) || (mLength != i)) + if (!ch347_write_data(cmdBuf, &mLength) || (mLength != i)) return false; mLength = 4; memset(cmdBuf, 0, sizeof(cmdBuf)); - if (!CH347ReadData(iIndex, cmdBuf, &mLength) || (mLength != 4)) + if (!ch347_read_data(cmdBuf, &mLength) || (mLength != 4)) return false; return true; } /** - * HexToString - Hex Conversion String Function + * @brief Hex Conversion String Function * @param buf Point to a buffer to place the Hex data to be converted * @param size Pointing to the length unit where data needs to be converted * * @return Returns a converted string */ -static char *HexToString(uint8_t *buf, uint32_t size) +static char *ch347_hex_to_string(uint8_t *buf, uint32_t size) { uint32_t i; if (buf == NULL) @@ -323,14 +342,14 @@ static char *HexToString(uint8_t *buf, uint32_t size) } /** - * CH347_Write - CH347 Write + * @brief CH347 Write * @param oBuffer Point to a buffer to place the data to be written out * @param ioLength Pointing to the length unit, the input is the length to be * written out, and the return is the actual written length * - * @return Write success returns 1, failure returns 0 + * @return Write success returns true, failure returns false */ -static int CH347_Write(void *oBuffer, unsigned long *ioLength) +static bool ch347_write(void *oBuffer, unsigned long *ioLength) { int ret = -1; uint64_t wlength = *ioLength, WI; @@ -338,14 +357,13 @@ static int CH347_Write(void *oBuffer, unsigned long *ioLength) wlength = HW_TDO_BUF_SIZE; WI = 0; while (1) { - ret = CH347WriteData(ugIndex, (uint8_t *)oBuffer + WI, - &wlength); + ret = ch347_write_data((uint8_t *)oBuffer + WI, &wlength); if (!ret) { *ioLength = 0; return false; } LOG_DEBUG_IO("(size=%" PRIu64 ", buf=[%s]) -> %" PRIu32, wlength, - HexToString((uint8_t *)oBuffer, wlength), + ch347_hex_to_string((uint8_t *)oBuffer, wlength), (uint32_t)wlength); WI += wlength; if (WI >= *ioLength) @@ -361,14 +379,14 @@ static int CH347_Write(void *oBuffer, unsigned long *ioLength) } /** - * CH347_Read - CH347 Read + * @brief CH347 Read * @param oBuffer Point to a buffer to place the data to be read in * @param ioLength Pointing to the length unit, the input is the length to * be read, and the return is the actual read length * - * @return Write success returns 1, failure returns 0 + * @return Write success returns true, failure returns false */ -static int CH347_Read(void *oBuffer, unsigned long *ioLength) +static bool ch347_read(void *oBuffer, unsigned long *ioLength) { uint64_t rlength = *ioLength, WI; /* The maximum allowable reading for a single read is 4096B of data. @@ -379,8 +397,7 @@ static int CH347_Read(void *oBuffer, unsigned long *ioLength) WI = 0; while (1) { - if (!CH347ReadData(ugIndex, (uint8_t *)oBuffer + WI, - &rlength)) { + if (!ch347_read_data((uint8_t *)oBuffer + WI, &rlength)) { LOG_ERROR("CH347 read fail"); return false; } @@ -394,12 +411,17 @@ static int CH347_Read(void *oBuffer, unsigned long *ioLength) rlength = *ioLength - WI; } LOG_DEBUG_IO("(size=%" PRIu64 ", buf=[%s]) -> %" PRIu32, WI, - HexToString((uint8_t *)oBuffer, WI), (uint32_t)WI); + ch347_hex_to_string((uint8_t *)oBuffer, WI), (uint32_t)WI); *ioLength = WI; return true; } -static void CH347_Read_Scan(UCHAR *pBuffer, uint32_t length) +/** + * @brief Reads data back from CH347 and decode it byte- and bitwise into the buffer + * @param pBuffer Point to a buffer to place the data to be read in + * @param length Data length in bytes that should be read via libusb + */ +static void ch347_read_scan(UCHAR *pBuffer, uint32_t length) { unsigned long read_size = 0; unsigned long RxLen = 0; @@ -414,7 +436,7 @@ static void CH347_Read_Scan(UCHAR *pBuffer, uint32_t length) index = 0; read_buf_index = 0; read_buf = calloc(sizeof(unsigned char), read_size); - if (!CH347_Read(read_buf, &RxLen)) { + if (!ch347_read(read_buf, &RxLen)) { LOG_ERROR("CH347 read fail"); return; } @@ -436,10 +458,12 @@ static void CH347_Read_Scan(UCHAR *pBuffer, uint32_t length) else *(pBuffer + read_buf_index) &= ~(1 << i % 8); bitCounter++; + // advance the buffer index every 8 bits if (bitCounter % 8 == 0) read_buf_index++; } index += dataLen + 1; + // after a read advance the buffer, because we put the bits from the next commands in the next buffer byte if (bitCounter % 8 != 0) read_buf_index++; } else { @@ -455,13 +479,17 @@ static void CH347_Read_Scan(UCHAR *pBuffer, uint32_t length) } } -static void CH347_Flush_Buffer(void) +/** + * @brief Sends the write buffer via libusb + * and if LARGER_PACK mode is active read also data back + */ +static void ch347_flush_buffer(void) { unsigned long retlen = ch347.buffer_idx; int nb = ch347.buffer_idx, ret = ERROR_OK; while (ret == ERROR_OK && nb > 0) { - ret = CH347_Write(ch347.buffer, &retlen); + ret = ch347_write(ch347.buffer, &retlen); nb -= retlen; } memset(&ch347.buffer, 0, sizeof(ch347.buffer)); @@ -473,7 +501,7 @@ static void CH347_Flush_Buffer(void) if (ch347.read_count == 0) return; if (ch347.pack_size == LARGER_PACK) { - CH347_Read_Scan(&ch347.read_buffer[0], ch347.read_count); + ch347_read_scan(&ch347.read_buffer[0], ch347.read_count); bit_copy_execute(&ch347.read_queue); memset(ch347.read_buffer, 0, SF_PACKET_BUF_SIZE); ch347.read_count = 0; @@ -481,27 +509,42 @@ static void CH347_Flush_Buffer(void) } } -static void CH347_In_Buffer(uint8_t byte) +/** + * @brief Puts a byte for writing into the output buffer + * @param byte the byte + */ +static void ch347_in_buffer(uint8_t byte) { if ((SF_PACKET_BUF_SIZE - ch347.buffer_idx) < 1) - CH347_Flush_Buffer(); + ch347_flush_buffer(); ch347.buffer[ch347.buffer_idx] = byte; ch347.buffer_idx++; if ((SF_PACKET_BUF_SIZE - ch347.buffer_idx) == 0) - CH347_Flush_Buffer(); + ch347_flush_buffer(); } -static void CH347_In_Buffer_bytes(uint8_t *bytes, unsigned long bytes_length) +/** + * @brief Puts multiple byte for writing into the output buffer + * @param bytes the bytes + * @param bytes_length number of bytes + */ +static void ch347_in_buffer_bytes(uint8_t *bytes, unsigned long bytes_length) { if ((ch347.buffer_idx + bytes_length) > SF_PACKET_BUF_SIZE) - CH347_Flush_Buffer(); + ch347_flush_buffer(); memcpy(&ch347.buffer[ch347.buffer_idx], bytes, bytes_length); ch347.buffer_idx += bytes_length; if ((SF_PACKET_BUF_SIZE - ch347.buffer_idx) < 1) - CH347_Flush_Buffer(); + ch347_flush_buffer(); } -static void combinePackets(uint8_t cmd, int cur_idx, unsigned long int len) +/** + * @brief If two packets for the same usb command are in the writing buffer, teh commands will be combined into one bigger command + * @param cmd + * @param cur_idx + * @param len + */ +static void ch347_combine_packets(uint8_t cmd, int cur_idx, unsigned long int len) { if (cmd != ch347.lastCmd) { ch347.buffer[cur_idx] = cmd; @@ -534,15 +577,14 @@ static void combinePackets(uint8_t cmd, int cur_idx, unsigned long int len) } } /** - * CH347_ClockTms - Function function used to change the TMS value at the + * @brief Function used to change the TMS value at the * rising edge of TCK to switch its Tap state - * @param BitBangPkt Protocol package * @param tms TMS value to be changed - * @param BI Protocol packet length + * @param bi Protocol packet length * * @return Return protocol packet length */ -static unsigned long CH347_ClockTms(int tms, unsigned long BI) +static unsigned long ch347_clock_tms(int tms, unsigned long bi) { uint8_t data = 0; unsigned char cmd = 0; @@ -552,47 +594,45 @@ static unsigned long CH347_ClockTms(int tms, unsigned long BI) else cmd = TMS_L; - BI += 2; + bi += 2; uint8_t tdiBit = ch347.TDI ? TDI_H : TDI_L; data = cmd | tdiBit | TCK_L | TRST_H; - CH347_In_Buffer(data); + ch347_in_buffer(data); data = cmd | tdiBit | TCK_H | TRST_H; - CH347_In_Buffer(data); + ch347_in_buffer(data); ch347.TMS = cmd; ch347.TCK = TCK_H; ch347.TRST = TRST_H; - return BI; + return bi; } /** - * CH347_IdleClock - Function function to ensure that the clock is in a low state - * @param BitBangPkt Protocol package - * @param BI Protocol packet length + * @brief Function to ensure that the clock is in a low state + * @param bi Protocol packet length * * @return Return protocol packet length */ -static unsigned long CH347_IdleClock(unsigned long BI) +static unsigned long ch347_idle_clock(unsigned long bi) { unsigned char byte = 0; byte |= ch347.TMS ? TMS_H : TMS_L; byte |= ch347.TDI ? TDI_H : TDI_L; byte |= ch347.TRST ? TRST_H : TRST_L; - BI++; - CH347_In_Buffer(byte); + bi++; + ch347_in_buffer(byte); - return BI; + return bi; } /** - * CH347_TmsChange - Function function that performs state switching by changing the value of TMS + * @brief Function that performs state switching by changing the value of TMS * @param tmsValue The TMS values that need to be switched form one byte of data in the switching order * @param step The number of bit values that need to be read from the tmsValue value * @param skip Count from the skip bit of tmsValue to step - * */ -static void CH347_TmsChange(const unsigned char *tmsValue, int step, int skip) +static void ch347_tms_change(const unsigned char *tmsValue, int step, int skip) { int i; int index = ch347.buffer_idx; @@ -604,29 +644,34 @@ static void CH347_TmsChange(const unsigned char *tmsValue, int step, int skip) step, skip); for (i = 0; i < 3; i++) - CH347_In_Buffer(0); + ch347_in_buffer(0); for (i = skip; i < step; i++) { - retlen = CH347_ClockTms((tmsValue[i / 8] >> (i % 8)) & 0x01, BI); + retlen = ch347_clock_tms((tmsValue[i / 8] >> (i % 8)) & 0x01, BI); BI = retlen; } - cmdLen = CH347_IdleClock(BI); + cmdLen = ch347_idle_clock(BI); - combinePackets(CH347_CMD_JTAG_BIT_OP, index, cmdLen); + ch347_combine_packets(CH347_CMD_JTAG_BIT_OP, index, cmdLen); } /** - * CH347_TMS - By ch347_ execute_ Queue call + * @brief By ch347_executeQueue call * @param cmd Upper layer transfer command parameters * */ -static void CH347_TMS(struct tms_command *cmd) +static void ch347_tms(struct tms_command *cmd) { LOG_DEBUG_IO("(step: %d)", cmd->num_bits); - CH347_TmsChange(cmd->bits, cmd->num_bits, 0); + ch347_tms_change(cmd->bits, cmd->num_bits, 0); } -static void CH347_GpioSet(int gpio, int data) +/** + * @brief Sets a GPIO bit + * @param gpio GPIO bit number 0-7 + * @param data true for high; false for low + */ +static void ch347_gpio_set(int gpio, bool data) { // build a gpio control command long unsigned int cmdLength = CH347_GPIO_CMD_LENGTH; @@ -639,11 +684,11 @@ static void CH347_GpioSet(int gpio, int data) // bit 3 is the data bit gpioCmd[CH347_CMD_HEADER + gpio] = data == 0 ? 0xF0 : 0xF8; - if (!CH347_Write(gpioCmd, &cmdLength) && (cmdLength != CH347_GPIO_CMD_LENGTH)) { + if (!ch347_write(gpioCmd, &cmdLength) && (cmdLength != CH347_GPIO_CMD_LENGTH)) { LOG_ERROR("JTAG_Gpio send usb data failure."); return; } - else if (!CH347_Read(gpioCmd, &cmdLength) && (cmdLength != CH347_GPIO_CMD_LENGTH)) { + else if (!ch347_read(gpioCmd, &cmdLength) && (cmdLength != CH347_GPIO_CMD_LENGTH)) { LOG_ERROR("JTAG_Gpio read usb data failure."); return; } @@ -654,18 +699,22 @@ static void CH347_GpioSet(int gpio, int data) return; } -static void CH347_SetActivityLed(int ledState) +/** + * @brief Turn the activity LED on or off + * @param ledState LED_ON or LED_OFF + */ +static void ch347_set_activity_led(int ledState) { - if (ch347_activity_led_gpio_pin != 0xff) { - CH347_GpioSet(ch347_activity_led_gpio_pin, ch347_activity_led_active_high ? ledState : 1 - ledState); - } + if (ch347_activity_led_gpio_pin != 0xff) + ch347_gpio_set(ch347_activity_led_gpio_pin, ch347_activity_led_active_high ? ledState : 1 - ledState); } /** - * CH347_Reset - CH347 Reset Tap Status Function - * @brief If there are more than six consecutive TCKs and TMS is high, the state - * machine can be set to a Test-Logic-Reset state - * + * @brief Reset for resetting with pins; not used for reset via TMS + * @param trst TRST pin + * @param srst SRST pin + * + * @return Always ERROR_OK */ static int ch347_reset(int trst, int srst) { @@ -679,74 +728,70 @@ static int ch347_reset(int trst, int srst) // a 50µs pulse to the TRST pin via bit operations if (!swd_mode && trst != 0) { - unsigned long int BI = 0; + unsigned long int bi = 0; - CH347_In_Buffer(CH347_CMD_JTAG_BIT_OP); - CH347_In_Buffer(0x01); - CH347_In_Buffer(0); + ch347_in_buffer(CH347_CMD_JTAG_BIT_OP); + ch347_in_buffer(0x01); + ch347_in_buffer(0); ch347.TRST = 0; - CH347_IdleClock(BI); + ch347_idle_clock(bi); - CH347_Flush_Buffer(); + ch347_flush_buffer(); usleep(50); - CH347_In_Buffer(CH347_CMD_JTAG_BIT_OP); - CH347_In_Buffer(0x01); - CH347_In_Buffer(0); + ch347_in_buffer(CH347_CMD_JTAG_BIT_OP); + ch347_in_buffer(0x01); + ch347_in_buffer(0); ch347.TRST = 1; - CH347_IdleClock(BI); + ch347_idle_clock(bi); - CH347_Flush_Buffer(); - return ERROR_OK; + ch347_flush_buffer(); } return ERROR_OK; } /** - * CH347_MovePath - Obtain the current Tap status and switch to the status TMS - * value passed down by cmd + * @brief Obtain the current Tap status and switch to the status TMS value passed down by cmd * @param cmd Upper layer transfer command parameters - * */ -static void CH347_MovePath(struct pathmove_command *cmd) +static void ch347_move_path(struct pathmove_command *cmd) { int i; int index = ch347.buffer_idx; - unsigned long BI, retlen = 0, cmdLen; + unsigned long bi, retlen = 0, cmdLen; - BI = CH347_CMD_HEADER; + bi = CH347_CMD_HEADER; for (i = 0; i < 3; i++) - CH347_In_Buffer(0); + ch347_in_buffer(0); LOG_DEBUG_IO("(num_states=%d, last_state=%d)", cmd->num_states, cmd->path[cmd->num_states - 1]); for (i = 0; i < cmd->num_states; i++) { if (tap_state_transition(tap_get_state(), false) == cmd->path[i]) - retlen = CH347_ClockTms(0, BI); - BI = retlen; + retlen = ch347_clock_tms(0, bi); + bi = retlen; if (tap_state_transition(tap_get_state(), true) == cmd->path[i]) - retlen = CH347_ClockTms(1, BI); - BI = retlen; + retlen = ch347_clock_tms(1, bi); + bi = retlen; tap_set_state(cmd->path[i]); } - cmdLen = CH347_IdleClock(BI); + cmdLen = ch347_idle_clock(bi); - combinePackets(CH347_CMD_JTAG_BIT_OP, index, cmdLen); + ch347_combine_packets(CH347_CMD_JTAG_BIT_OP, index, cmdLen); } /** - * CH347_MoveState - Toggle the Tap state to the Target state stat - * @param stat Pre switch target path + * @brief Toggle the Tap state to the Target state stat + * @param state Pre switch target path * @param skip Number of digits to skip - * */ -static void CH347_MoveState(tap_state_t state, int skip) +static void ch347_move_state(tap_state_t state, int skip) { uint8_t tms_scan; int tms_len; @@ -758,11 +803,16 @@ static void CH347_MoveState(tap_state_t state, int skip) return; tms_scan = tap_get_tms_path(tap_get_state(), state); tms_len = tap_get_tms_path_len(tap_get_state(), state); - CH347_TmsChange(&tms_scan, tms_len, skip); + ch347_tms_change(&tms_scan, tms_len, skip); tap_set_state(state); } -static void CH347_ScanDataToFields(struct scan_command *cmd, uint8_t *readData) +/** + * @brief Used to put the data from the byte buffer into the scan command + * @param cmd The scan command + * @param readData data that are read from usb + */ +static void ch347_scan_data_to_fields(struct scan_command *cmd, uint8_t *readData) { int offset = 0; int numBits = 0; @@ -797,16 +847,15 @@ static void CH347_ScanDataToFields(struct scan_command *cmd, uint8_t *readData) } /** - * CH347_WriteReadBitwise - CH347 Batch read/write function + * @brief CH347 Batch read/write function * That's the workaround function for write/read bit by bit because the - * bytewise functions D3/D4 are not working correctly - * @param bits Read and write data this time - * @param nb_bits Incoming data length - * @param scan The transmission method of incoming data to determine whether - * to perform data reading + * bytewise functions D3/D4 are not working correctly for all chip versions + * @param cmd The scan command + * @param bits Read and write data this time + * @param nb_bits Incoming data length + * @param scan The transmission method of incoming data to determine whether to perform data reading */ -static void CH347_WriteReadBitwise(struct scan_command *cmd, uint8_t *bits, - int nb_bits, enum scan_type scan) +static void ch347_write_read_bitwise(struct scan_command *cmd, uint8_t *bits, int nb_bits, enum scan_type scan) { int i = 0; int chunkDataLength = 0; @@ -817,9 +866,9 @@ static void CH347_WriteReadBitwise(struct scan_command *cmd, uint8_t *bits, if (ch347.pack_size == LARGER_PACK) { if ((ch347.read_count >= (USBC_PACKET_USBHS_SINGLE * 1))) - CH347_Flush_Buffer(); + ch347_flush_buffer(); } else { - CH347_Flush_Buffer(); + ch347_flush_buffer(); } bool isRead = (scan == SCAN_IN || scan == SCAN_IO); @@ -837,11 +886,11 @@ static void CH347_WriteReadBitwise(struct scan_command *cmd, uint8_t *bits, // build the cmd header if (isRead) - CH347_In_Buffer(CH347_CMD_JTAG_BIT_OP_RD); + ch347_in_buffer(CH347_CMD_JTAG_BIT_OP_RD); else - CH347_In_Buffer(CH347_CMD_JTAG_BIT_OP); - CH347_In_Buffer((uint8_t)chunkDataLength & 0xFF); - CH347_In_Buffer((uint8_t)(chunkDataLength >> 8) & 0xFF); + ch347_in_buffer(CH347_CMD_JTAG_BIT_OP); + ch347_in_buffer((uint8_t)chunkDataLength & 0xFF); + ch347_in_buffer((uint8_t)(chunkDataLength >> 8) & 0xFF); tmsBit = TMS_L; for (int j = 0; j < chunkBitCount; j++) { @@ -850,14 +899,14 @@ static void CH347_WriteReadBitwise(struct scan_command *cmd, uint8_t *bits, if ((i + 1) == nb_bits) tmsBit = TMS_H; - CH347_In_Buffer(tmsBit | tdiBit | TCK_L | TRST_H); - CH347_In_Buffer(tmsBit | tdiBit | TCK_H | TRST_H); + ch347_in_buffer(tmsBit | tdiBit | TCK_L | TRST_H); + ch347_in_buffer(tmsBit | tdiBit | TCK_H | TRST_H); i++; } // one TCK_L after the last bit if (i == nb_bits) { - CH347_In_Buffer(tmsBit | tdiBit | TCK_L | TRST_H); + ch347_in_buffer(tmsBit | tdiBit | TCK_L | TRST_H); } chunkCount++; @@ -874,19 +923,19 @@ static void CH347_WriteReadBitwise(struct scan_command *cmd, uint8_t *bits, ch347.read_count = readLen; if (ch347.pack_size == STANDARD_PACK && bits && cmd) { - CH347_Flush_Buffer(); - CH347_Read_Scan(readData, readLen); + ch347_flush_buffer(); + ch347_read_scan(readData, readLen); } - CH347_ScanDataToFields(cmd, readData); + ch347_scan_data_to_fields(cmd, readData); } int tempIndex = ch347.buffer_idx; for (i = 0; i < CH347_CMD_HEADER; i++) - CH347_In_Buffer(0); + ch347_in_buffer(0); unsigned long byteIndex = CH347_CMD_HEADER; - byteIndex = CH347_IdleClock(byteIndex); - combinePackets(CH347_CMD_JTAG_BIT_OP, tempIndex, byteIndex); + byteIndex = ch347_idle_clock(byteIndex); + ch347_combine_packets(CH347_CMD_JTAG_BIT_OP, tempIndex, byteIndex); if (readData) { free(readData); readData = NULL; @@ -894,35 +943,29 @@ static void CH347_WriteReadBitwise(struct scan_command *cmd, uint8_t *bits, } /** - * CH347_WriteRead - CH347 Batch read/write function - * @param bits Read and write data this time - * @param nb_bits Incoming data length - * @param scan The transmission method of incoming data to determine whether - * to perform data reading + * @brief CH347 Batch read/write function + * @param cmd The scan command + * @param bits Read and write data this time + * @param nb_bits Incoming data length + * @param scan The transmission method of incoming data to determine whether to perform data reading */ -static void CH347_WriteRead(struct scan_command *cmd, uint8_t *bits, - int nb_bits, enum scan_type scan) +static void ch347_write_read(struct scan_command *cmd, uint8_t *bits, int nb_bits, enum scan_type scan) { - if (ch347.use_bitwise_write_read) { - CH347_WriteReadBitwise(cmd, bits, nb_bits, scan); - return; - } - int nb8 = nb_bits / 8; int nb1 = nb_bits % 8; int i = 0; - bool IsRead = false; /*, isLastByte = false */ + bool isRead = false; uint8_t TMS_Bit = 0, TDI_Bit = 0, CMD_Bit; static uint8_t byte0[SF_PACKET_BUF_SIZE]; uint8_t *readData = calloc(SF_PACKET_BUF_SIZE, 1); unsigned long readLen = 0; - unsigned long BI = 0, DI, DII, PktDataLen, DLen = 0, tempIndex, + unsigned long bi = 0, di, dii, pktDataLen, dLen = 0, tempIndex, totalReadLength = 0, tempLength = 0; if (ch347.pack_size == LARGER_PACK) { if ((ch347.read_count >= (USBC_PACKET_USBHS_SINGLE * 1))) - CH347_Flush_Buffer(); + ch347_flush_buffer(); } else { - CH347_Flush_Buffer(); + ch347_flush_buffer(); } if (nb8 > 0 && nb1 == 0) { @@ -930,20 +973,20 @@ static void CH347_WriteRead(struct scan_command *cmd, uint8_t *bits, nb1 = 8; } - IsRead = (scan == SCAN_IN || scan == SCAN_IO); - DI = BI = 0; - while (DI < (unsigned long)nb8) { - if ((nb8 - DI) > UCMDPKT_DATA_MAX_BYTES_USBHS) - PktDataLen = UCMDPKT_DATA_MAX_BYTES_USBHS; + isRead = (scan == SCAN_IN || scan == SCAN_IO); + di = bi = 0; + while (di < (unsigned long)nb8) { + if ((nb8 - di) > UCMDPKT_DATA_MAX_BYTES_USBHS) + pktDataLen = UCMDPKT_DATA_MAX_BYTES_USBHS; else - PktDataLen = nb8 - DI; + pktDataLen = nb8 - di; - DII = PktDataLen; + dii = pktDataLen; - if (IsRead) - CH347_In_Buffer(CH347_CMD_JTAG_DATA_SHIFT_RD); + if (isRead) + ch347_in_buffer(CH347_CMD_JTAG_DATA_SHIFT_RD); else - CH347_In_Buffer(CH347_CMD_JTAG_DATA_SHIFT); + ch347_in_buffer(CH347_CMD_JTAG_DATA_SHIFT); /* packet data don't deal D3 & D4 */ if ((CH347_CMD_JTAG_DATA_SHIFT_RD != ch347.lastCmd) | @@ -954,40 +997,40 @@ static void CH347_WriteRead(struct scan_command *cmd, uint8_t *bits, ch347.len_value = 0; } - CH347_In_Buffer((uint8_t)(PktDataLen >> 0) & 0xFF); - CH347_In_Buffer((uint8_t)(PktDataLen >> 8) & 0xFF); + ch347_in_buffer((uint8_t)(pktDataLen >> 0) & 0xFF); + ch347_in_buffer((uint8_t)(pktDataLen >> 8) & 0xFF); if (bits) - CH347_In_Buffer_bytes(&bits[DI], PktDataLen); + ch347_in_buffer_bytes(&bits[di], pktDataLen); else - CH347_In_Buffer_bytes(byte0, PktDataLen); - DI += DII; + ch347_in_buffer_bytes(byte0, pktDataLen); + di += dii; - tempLength += (DII + CH347_CMD_HEADER); + tempLength += (dii + CH347_CMD_HEADER); } totalReadLength += tempLength; - if (IsRead) { + if (isRead) { ch347.read_count += tempLength; readLen += tempLength; } if (bits) { - CMD_Bit = IsRead ? CH347_CMD_JTAG_BIT_OP_RD : \ + CMD_Bit = isRead ? CH347_CMD_JTAG_BIT_OP_RD : \ CH347_CMD_JTAG_BIT_OP; - DLen = (nb1 * 2) + 1; + dLen = (nb1 * 2) + 1; if (CMD_Bit != ch347.lastCmd) { - CH347_In_Buffer(CMD_Bit); - CH347_In_Buffer((uint8_t)(DLen >> 0) & 0xFF); - CH347_In_Buffer((uint8_t)(DLen >> 8) & 0xFF); + ch347_in_buffer(CMD_Bit); + ch347_in_buffer((uint8_t)(dLen >> 0) & 0xFF); + ch347_in_buffer((uint8_t)(dLen >> 8) & 0xFF); ch347.lastCmd = CMD_Bit; ch347.len_idx = ch347.buffer_idx - 2; - ch347.len_value = DLen; + ch347.len_value = dLen; } else { /* update the ch347 struct cmd data leng */ - ch347.len_value += DLen; + ch347.len_value += dLen; /* update the cmd packet valid leng */ ch347.buffer[ch347.len_idx] = (uint8_t)(ch347.len_value >> 0) & 0xFF; @@ -1005,90 +1048,98 @@ static void CH347_WriteRead(struct scan_command *cmd, uint8_t *bits, if ((i + 1) == nb1) TMS_Bit = TMS_H; - CH347_In_Buffer(TMS_Bit | TDI_Bit | TCK_L | TRST_H); - CH347_In_Buffer(TMS_Bit | TDI_Bit | TCK_H | TRST_H); + ch347_in_buffer(TMS_Bit | TDI_Bit | TCK_L | TRST_H); + ch347_in_buffer(TMS_Bit | TDI_Bit | TCK_H | TRST_H); } - CH347_In_Buffer(TMS_Bit | TDI_Bit | TCK_L | TRST_H); + ch347_in_buffer(TMS_Bit | TDI_Bit | TCK_L | TRST_H); } ch347.TMS = TMS_Bit; ch347.TDI = TDI_Bit; ch347.TCK = TCK_L; - if (IsRead) { - tempLength = ((DLen / 2) + CH347_CMD_HEADER); + if (isRead) { + tempLength = ((dLen / 2) + CH347_CMD_HEADER); totalReadLength += tempLength; ch347.read_count += tempLength; readLen += tempLength; - DI = BI = 0; + di = bi = 0; } - if (IsRead && totalReadLength > 0) { + if (isRead && totalReadLength > 0) { if (ch347.pack_size == STANDARD_PACK && bits && cmd) { - CH347_Flush_Buffer(); - CH347_Read_Scan(readData, readLen); + ch347_flush_buffer(); + ch347_read_scan(readData, readLen); } - CH347_ScanDataToFields(cmd, readData); + ch347_scan_data_to_fields(cmd, readData); } tempIndex = ch347.buffer_idx; for (i = 0; i < CH347_CMD_HEADER; i++) - CH347_In_Buffer(0); - BI = CH347_CMD_HEADER; - BI = CH347_IdleClock(BI); + ch347_in_buffer(0); + bi = CH347_CMD_HEADER; + bi = ch347_idle_clock(bi); - combinePackets(CH347_CMD_JTAG_BIT_OP, tempIndex, BI); + ch347_combine_packets(CH347_CMD_JTAG_BIT_OP, tempIndex, bi); if (readData) { free(readData); readData = NULL; } } -static void CH347_RunTest(int cycles, tap_state_t state) +/** + * @brief Toggle the Tap state to run test/idle + * @param cycles + * @param state + */ +static void ch347_run_test(int cycles, tap_state_t state) { LOG_DEBUG_IO("%s(cycles=%i, end_state=%d)", __func__, cycles, state); if (tap_get_state() != TAP_IDLE) - CH347_MoveState(TAP_IDLE, 0); + ch347_move_state(TAP_IDLE, 0); uint8_t tmsValue = 0; - CH347_TmsChange(&tmsValue, 7, 1); + ch347_tms_change(&tmsValue, 7, 1); - CH347_WriteRead(NULL, NULL, cycles, SCAN_OUT); - CH347_MoveState(state, 0); + ch347.writeRead(NULL, NULL, cycles, SCAN_OUT); + ch347_move_state(state, 0); } -static void CH347_TableClocks(int cycles) +/** + * @brief ??? + * @param cycles + * @param state + */ +static void ch347_stable_clocks(int cycles) { LOG_DEBUG_IO("%s(cycles=%i)", __func__, cycles); - CH347_WriteRead(NULL, NULL, cycles, SCAN_OUT); + ch347.writeRead(NULL, NULL, cycles, SCAN_OUT); } /** - * CH347_Scan - Switch to SHIFT-DR or SHIFT-IR status for scanning + * @brief Switch to SHIFT-DR or SHIFT-IR status for scanning * @param cmd Upper layer transfer command parameters * * @return Success returns ERROR_OK */ -static int CH347_Scan(struct scan_command *cmd) +static int ch347_scan(struct scan_command *cmd) { int scan_bits; uint8_t *buf = NULL; enum scan_type type; int ret = ERROR_OK; - static const char *const type2str[] = { - "", "SCAN_IN", "SCAN_OUT", "SCAN_IO" - }; + static const char *const type2str[] = {"", "SCAN_IN", "SCAN_OUT", "SCAN_IO"}; char *log_buf = NULL; type = jtag_scan_type(cmd); scan_bits = jtag_build_buffer(cmd, &buf); if (cmd->ir_scan) - CH347_MoveState(TAP_IRSHIFT, 0); + ch347_move_state(TAP_IRSHIFT, 0); else - CH347_MoveState(TAP_DRSHIFT, 0); + ch347_move_state(TAP_DRSHIFT, 0); - log_buf = HexToString(buf, DIV_ROUND_UP(scan_bits, 8)); + log_buf = ch347_hex_to_string(buf, DIV_ROUND_UP(scan_bits, 8)); LOG_DEBUG_IO("Scan"); LOG_DEBUG_IO("%s(scan=%s, type=%s, bits=%d, buf=[%s], end_state=%d)", __func__, @@ -1098,27 +1149,36 @@ static int CH347_Scan(struct scan_command *cmd) free(log_buf); - CH347_WriteRead(cmd, buf, scan_bits, type); + ch347.writeRead(cmd, buf, scan_bits, type); free(buf); - CH347_MoveState(cmd->end_state, 1); + ch347_move_state(cmd->end_state, 1); return ret; } -static void CH347_Sleep(int us) +/** + * @brief Sleep for a specific timspan + * @param us Sleep time in microseconds + */ +static void ch347_sleep(int us) { LOG_DEBUG_IO("%s(us=%d)", __func__, us); jtag_sleep(us); } +/** + * @brief Executes the command quene + * + * @return Success returns ERROR_OK + */ static int ch347_execute_queue(void) { struct jtag_command *cmd; int ret = ERROR_OK; - CH347_SetActivityLed(LED_ON); + ch347_set_activity_led(LED_ON); for (cmd = jtag_command_queue; ret == ERROR_OK && cmd; cmd = cmd->next) { @@ -1130,26 +1190,26 @@ static int ch347_execute_queue(void) ch347_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); break; case JTAG_RUNTEST: - CH347_RunTest(cmd->cmd.runtest->num_cycles, + ch347_run_test(cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); break; case JTAG_STABLECLOCKS: - CH347_TableClocks(cmd->cmd.stableclocks->num_cycles); + ch347_stable_clocks(cmd->cmd.stableclocks->num_cycles); break; case JTAG_TLR_RESET: - CH347_MoveState(cmd->cmd.statemove->end_state, 0); + ch347_move_state(cmd->cmd.statemove->end_state, 0); break; case JTAG_PATHMOVE: - CH347_MovePath(cmd->cmd.pathmove); + ch347_move_path(cmd->cmd.pathmove); break; case JTAG_TMS: - CH347_TMS(cmd->cmd.tms); + ch347_tms(cmd->cmd.tms); break; case JTAG_SLEEP: - CH347_Sleep(cmd->cmd.sleep->us); + ch347_sleep(cmd->cmd.sleep->us); break; case JTAG_SCAN: - ret = CH347_Scan(cmd->cmd.scan); + ret = ch347_scan(cmd->cmd.scan); break; default: LOG_ERROR("BUG: unknown JTAG command type 0x%X", cmd->type); @@ -1158,25 +1218,22 @@ static int ch347_execute_queue(void) } } - CH347_Flush_Buffer(); - CH347_SetActivityLed(LED_OFF); + ch347_flush_buffer(); + ch347_set_activity_led(LED_OFF); return ret; } /** - * ch347_init - CH347 Initialization function + * @brief CH347 Initialization function * - * Todo: - * Initialize dynamic library functions - * Open Device + * Todo: Initialize dynamic library functions / Open Device * @return Success returns 0, failure returns ERROR_FAIL */ static int ch347_init(void) { - DevIsOpened = CH347OpenDevice(ugIndex); - ugIndex = DevIsOpened; - - if (DevIsOpened < 0) { + dev_is_opened = ch347_open_device(); + + if (!dev_is_opened) { LOG_ERROR("CH347 open error"); return ERROR_FAIL; } else { @@ -1184,7 +1241,7 @@ static int ch347_init(void) } if (!swd_mode) { - /* ch347 init */ + /* ch347 jtag init */ ch347.TCK = 0; ch347.TMS = 0; ch347.TDI = 0; @@ -1203,40 +1260,46 @@ static int ch347_init(void) bit_copy_queue_init(&ch347.read_queue); tap_set_state(TAP_RESET); - } else { /* swd init */ - CH347SWD_INIT(ugIndex, 0); + } else { + ch347_swd_init_cmd(0); } return ERROR_OK; } /** - * ch347_quit - CH347 Device Release Function + * @brief CH347 Device Release Function * - * Todo: - * Reset JTAG pin signal - * Close - * @return always returns 0 + * Todo: Reset JTAG pin signal / Close + * @return always returns 0 */ static int ch347_quit(void) { // on close set the LED on, because the state without JTAG is on - CH347_SetActivityLed(LED_ON); + ch347_set_activity_led(LED_ON); unsigned long retlen = 4; uint8_t byte[4] = {CH347_CMD_JTAG_BIT_OP, 0x01, 0x00, ch347.TRST}; if (!swd_mode) { - CH347_Write(byte, &retlen); + ch347_write(byte, &retlen); bit_copy_discard(&ch347.read_queue); } - if (DevIsOpened) { - CH347CloseDevice(ugIndex); + if (dev_is_opened) { + ch347_close_device(); LOG_DEBUG_IO("CH347 close"); - DevIsOpened = false; + dev_is_opened = false; } return 0; } -static bool Check_Speed(uint64_t iIndex, uint8_t iClockRate) +/** + * @brief Sends the CH347_CMD_JTAG_INIT (D0) command to get the jtag + * interface initalized with the speed index + * @param iClockRate Clock rate + * + * @return true if the device supports STANDARD_PACK mode; + * false if the device supports LARGER_PACK mode + */ +static bool ch347_check_speed(uint8_t iClockRate) { unsigned long int i = 0, j; bool retVal; @@ -1252,55 +1315,60 @@ static bool Check_Speed(uint64_t iIndex, uint8_t iClockRate) cmdBuf[i++] = ch347.TCK | ch347.TDI | ch347.TMS | ch347.TRST; uint64_t mLength = i; - if (!CH347WriteData(iIndex, cmdBuf, &mLength) || (mLength != i)) + if (!ch347_write_data(cmdBuf, &mLength) || (mLength != i)) return false; mLength = 4; memset(cmdBuf, 0, sizeof(cmdBuf)); - if (!CH347ReadData(iIndex, cmdBuf, &mLength) || (mLength != 4)) + if (!ch347_read_data(cmdBuf, &mLength) || (mLength != 4)) return false; - retVal = ((cmdBuf[0] == CH347_CMD_JTAG_INIT) && \ - (cmdBuf[CH347_CMD_HEADER] == 0)); + retVal = ((cmdBuf[0] == CH347_CMD_JTAG_INIT) && (cmdBuf[CH347_CMD_HEADER] == 0)); return retVal; } -static bool CH347Jtag_INIT(uint64_t iIndex, uint8_t iClockRate) +/** + * @brief Initializes the jtag interface + * @param iClockRate Clock rate + * + * @return true if the device supports STANDARD_PACK mode; + * false if the device supports LARGER_PACK mode + */ +static bool ch347_jtag_init(uint8_t iClockRate) { - ch347.pack_size = (Check_Speed(iIndex, 0x09) == true) ? \ - STANDARD_PACK : LARGER_PACK; + // when checking with speed index 9 we can see if the device supports STANDARD_PACK or LARGER_PACK mode + ch347.pack_size = (ch347_check_speed(0x09) == true) ? STANDARD_PACK : LARGER_PACK; if (ch347.pack_size == STANDARD_PACK) { if (iClockRate - 2 < 0) - return Check_Speed(iIndex, 0); + return ch347_check_speed(0); else - return Check_Speed(iIndex, iClockRate - 2); + return ch347_check_speed(iClockRate - 2); } - return Check_Speed(iIndex, iClockRate); + return ch347_check_speed(iClockRate); } /** - * ch347_speed - CH347 TCK frequency setting - * @param speed Frequency size set - * @return Success returns ERROR_OK,failed returns FALSE + * @brief CH347 TCK frequency setting + * @param speed Frequency size set + * + * @return Success returns ERROR_OK,failed returns FALSE */ static int ch347_speed(int speed) { unsigned long i = 0; uint8_t clockRate; int retval = -1; - int speed_clock[8] = { - KHZ(468.75), KHZ(937.5), MHZ(1.875), - MHZ(3.75), MHZ(7.5), MHZ(15), MHZ(30), MHZ(60) - }; + // there are these 8 speeds possible + int speed_clock[8] = {KHZ(468.75), KHZ(937.5), MHZ(1.875), MHZ(3.75), MHZ(7.5), MHZ(15), MHZ(30), MHZ(60)}; if (!swd_mode) { for (i = 0; i < (sizeof(speed_clock) / sizeof(int)); i++) { if ((speed >= speed_clock[i]) && (speed <= speed_clock[i + 1])) { clockRate = i + 1; - retval = CH347Jtag_INIT(ugIndex, clockRate); + retval = ch347_jtag_init(clockRate); if (!retval) { LOG_ERROR("Couldn't set CH347 TCK speed"); return retval; @@ -1308,7 +1376,7 @@ static int ch347_speed(int speed) break; } } else if (speed < speed_clock[0]) { - retval = CH347Jtag_INIT(ugIndex, 0); + retval = ch347_jtag_init(0); if (!retval) { LOG_ERROR("Couldn't set CH347 TCK speed"); return retval; @@ -1321,12 +1389,26 @@ static int ch347_speed(int speed) return ERROR_OK; } +/** + * @brief divides the input speed by 1000 + * @param speed Frequency size set + * @param khz Output of the speed in kHz + * + * @return Always ERROR_OK + */ static int ch347_speed_div(int speed, int *khz) { *khz = speed / 1000; return ERROR_OK; } +/** + * @brief multiplies the input speed by 1000 + * @param khz Speed in kHz + * @param jtag_speed Output frequency + * + * @return ERROR_OK at success; ERROR_FAIL if khz is zero + */ static int ch347_khz(int khz, int *jtag_speed) { if (khz == 0) { @@ -1337,19 +1419,24 @@ static int ch347_khz(int khz, int *jtag_speed) return ERROR_OK; } +/** + * @brief Sets the TRST pin + * @param status Pin status + * + * @return ERROR_OK at success; ERROR_FAIL otherwise + */ static int ch347_trst_out(unsigned char status) { - unsigned long int BI = 0; + unsigned long int bi = 0; unsigned char byte = 0; unsigned char cmdPacket[4] = ""; - cmdPacket[BI++] = CH347_CMD_JTAG_BIT_OP; - cmdPacket[BI++] = 0x01; - cmdPacket[BI++] = 0; - byte = ch347.TCK | ch347.TDI | ch347.TMS | (ch347.TRST = - (status ? TRST_H : TRST_L)); - cmdPacket[BI++] = byte; - - if (!CH347_Write(cmdPacket, &BI)) { + cmdPacket[bi++] = CH347_CMD_JTAG_BIT_OP; + cmdPacket[bi++] = 0x01; + cmdPacket[bi++] = 0; + byte = ch347.TCK | ch347.TDI | ch347.TMS | (ch347.TRST = (status ? TRST_H : TRST_L)); + cmdPacket[bi++] = byte; + + if (!ch347_write(cmdPacket, &bi)) { LOG_ERROR("TRST set failure."); return ERROR_FAIL; } @@ -1357,6 +1444,11 @@ static int ch347_trst_out(unsigned char status) return ERROR_OK; } +/** + * @brief The command handler for setting the device usb vid/pid + * + * @return ERROR_OK at success; ERROR_COMMAND_SYNTAX_ERROR otherwise + */ COMMAND_HANDLER(ch347_handle_vid_pid_command) { if (CMD_ARGC != 2) { @@ -1370,6 +1462,11 @@ COMMAND_HANDLER(ch347_handle_vid_pid_command) return ERROR_OK; } +/** + * @brief The command handler for resetting the target device via trst pin + * + * @return Always ERROR_OK + */ COMMAND_HANDLER(ch347_trst) { ch347_trst_out(TRST_L); @@ -1378,6 +1475,11 @@ COMMAND_HANDLER(ch347_trst) return ERROR_OK; } +/** + * @brief The command handler for setting the device description that should be found + * + * @return ERROR_OK at success; ERROR_COMMAND_SYNTAX_ERROR otherwise + */ COMMAND_HANDLER(ch347_handle_device_desc_command) { if (CMD_ARGC == 1) { @@ -1392,6 +1494,11 @@ COMMAND_HANDLER(ch347_handle_device_desc_command) return ERROR_OK; } +/** + * @brief The command handler for configuring which GPIO pin is used as activity LED + * + * @return ERROR_OK at success; ERROR_COMMAND_SYNTAX_ERROR otherwise + */ COMMAND_HANDLER(ch347_handle_activity_led_command) { if (CMD_ARGC != 1) @@ -1464,6 +1571,11 @@ static const struct command_registration ch347_command_handlers[] = { }, COMMAND_REGISTRATION_DONE}; +/** + * @brief Initialization for the swd mode + * + * @return ERROR_OK at success; ERROR_FAIL otherwise + */ static int ch347_swd_init(void) { PCH347_SWD_IO pswd_io; @@ -1515,8 +1627,7 @@ static void ch347_swd_queue_flush(void) CH347_CMD_HEADER); ch347_swd_context.send_buf[2] = (uint8_t)((ch347_swd_context.send_len - CH347_CMD_HEADER) >> 8); - if (!CH347WriteData(ugIndex, ch347_swd_context.send_buf, &mLength) || - (mLength != ch347_swd_context.send_len)) { + if (!ch347_write_data(ch347_swd_context.send_buf, &mLength) || (mLength != ch347_swd_context.send_len)) { ch347_swd_context.queued_retval = ERROR_FAIL; LOG_DEBUG("CH347WriteData error "); return; @@ -1524,9 +1635,7 @@ static void ch347_swd_queue_flush(void) ch347_swd_context.recv_len = 0; do { mLength = CH347_MAX_RECV_BUF - ch347_swd_context.recv_len; - if (!CH347ReadData(ugIndex, - &ch347_swd_context.recv_buf[ch347_swd_context.recv_len], - &mLength)) { + if (!ch347_read_data(&ch347_swd_context.recv_buf[ch347_swd_context.recv_len], &mLength)) { ch347_swd_context.queued_retval = ERROR_FAIL; LOG_DEBUG("CH347ReadData error "); return; @@ -1541,6 +1650,7 @@ static void ch347_swd_queue_flush(void) ch347_swd_context.need_recv_len); } } + static void ch347_wrtie_swd_reg(uint8_t cmd, const uint8_t *out, uint8_t parity) { ch347_swd_context.send_buf[ch347_swd_context.send_len++] = @@ -1588,8 +1698,7 @@ static void ch347_read_swd_reg(uint8_t cmd) ch347_swd_context.need_recv_len += 1 + 1 + 4 + 1; } -static int ch347_swd_switch_out(enum swd_special_seq seq, const uint8_t *out, - unsigned out_len) +static int ch347_swd_switch_out(enum swd_special_seq seq, const uint8_t *out, unsigned out_len) { PCH347_SWD_IO pswd_io; if ((ch347_swd_context.send_len + @@ -1658,6 +1767,11 @@ static bool ch347_chk_buf_size(uint8_t cmd, uint32_t ap_delay_clk) return bflush; } +/* TODO: ch347_swd_send_idle / ch347_swd_run_queue are + functions that are calling each other - a cyclic dependency + => declare one to get it compiled */ +static int ch347_swd_run_queue(void); + static void ch347_swd_send_idle(uint32_t ap_delay_clk) { PCH347_SWD_IO pswd_io; @@ -1677,106 +1791,6 @@ static void ch347_swd_send_idle(uint32_t ap_delay_clk) list_add_tail(&pswd_io->list_entry, &ch347_swd_context.send_cmd_head); } -static void ch347_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, - uint32_t ap_delay_clk) -{ - PCH347_SWD_IO pswd_io; - if (ap_delay_clk > 255) - printf("ch347_swd_queue_cmd ap_delay_clk = %d\r\n", - ap_delay_clk); - - if (ch347_swd_context.sent_cmd_count >= CH347_MAX_SEND_CMD) - ch347_swd_run_queue(); - - if (!ch347_chk_buf_size(cmd, ap_delay_clk)) - ch347_swd_run_queue(); - - pswd_io = ch347_get_one_swd_io(); - if (!pswd_io) { - ch347_swd_run_queue(); - pswd_io = ch347_get_one_swd_io(); - if (!pswd_io) { - LOG_DEBUG("ch347_swd_queue_cmd error "); - ch347_swd_context.queued_retval = ERROR_FAIL; - return; - } - } - - pswd_io->cmd = cmd | SWD_CMD_START | SWD_CMD_PARK; - - if (pswd_io->cmd & SWD_CMD_RNW) { - pswd_io->usbcmd = CH347_CMD_SWD_REG_R; - pswd_io->dst = dst; - ch347_read_swd_reg(pswd_io->cmd); - } else { - pswd_io->usbcmd = CH347_CMD_SWD_REG_W; - pswd_io->value = data; - ch347_wrtie_swd_reg(pswd_io->cmd, (uint8_t *)&data, - parity_u32(data)); - } - - ch347_swd_context.sent_cmd_count++; - list_add_tail(&pswd_io->list_entry, &ch347_swd_context.send_cmd_head); - /* Insert idle cycles after AP accesses to avoid WAIT */ - if (cmd & SWD_CMD_APNDP) { - if (ap_delay_clk == 0) - printf("ap_delay_clk == 0"); - ch347_swd_send_idle(ap_delay_clk); - } -} - -static int ch347_swd_switch_seq(enum swd_special_seq seq) -{ - printf("ch347_swd_switch_seq %d \r\n", seq); - switch (seq) { - case LINE_RESET: - LOG_DEBUG("SWD line reset"); - return ch347_swd_switch_out(seq, swd_seq_line_reset, - swd_seq_line_reset_len); - case JTAG_TO_SWD: - LOG_DEBUG("JTAG-to-SWD"); - return ch347_swd_switch_out(seq, swd_seq_jtag_to_swd, - swd_seq_jtag_to_swd_len); - case JTAG_TO_DORMANT: - LOG_DEBUG("JTAG-to-DORMANT"); - return ch347_swd_switch_out(seq, swd_seq_jtag_to_dormant, - swd_seq_jtag_to_dormant_len); - case SWD_TO_JTAG: - LOG_DEBUG("SWD-to-JTAG"); - return ch347_swd_switch_out(seq, swd_seq_swd_to_jtag, - swd_seq_swd_to_jtag_len); - case SWD_TO_DORMANT: - LOG_DEBUG("SWD-to-DORMANT"); - return ch347_swd_switch_out(seq, swd_seq_swd_to_dormant, - swd_seq_swd_to_dormant_len); - case DORMANT_TO_SWD: - LOG_DEBUG("DORMANT-to-SWD"); - return ch347_swd_switch_out(seq, swd_seq_dormant_to_swd, - swd_seq_dormant_to_swd_len); - case DORMANT_TO_JTAG: - LOG_DEBUG("DORMANT-to-JTAG"); - return ch347_swd_switch_out(seq, swd_seq_dormant_to_jtag, - swd_seq_dormant_to_jtag_len); - default: - LOG_ERROR("Sequence %d not supported", seq); - return ERROR_FAIL; - } -} - -static void ch347_swd_read_reg(uint8_t cmd, uint32_t *value, - uint32_t ap_delay_clk) -{ - assert(cmd & SWD_CMD_RNW); - ch347_swd_queue_cmd(cmd, value, 0, ap_delay_clk); -} - -static void ch347_swd_write_reg(uint8_t cmd, uint32_t value, - uint32_t ap_delay_clk) -{ - assert(!(cmd & SWD_CMD_RNW)); - ch347_swd_queue_cmd(cmd, NULL, value, ap_delay_clk); -} - static int ch347_swd_run_queue(void) { LOG_DEBUG_IO("Executing %u queued transactions", @@ -1800,7 +1814,7 @@ static int ch347_swd_run_queue(void) if ((ch347_swd_context.need_recv_len + 1) > CH347_MAX_RECV_BUF) goto skip_idle; - ch347_swd_send_idle(8); + ch347_swd_send_idle((uint32_t)8); skip_idle: @@ -1936,6 +1950,105 @@ static int ch347_swd_run_queue(void) return retval; } +static void ch347_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint32_t ap_delay_clk) +{ + PCH347_SWD_IO pswd_io; + if (ap_delay_clk > 255) + printf("ch347_swd_queue_cmd ap_delay_clk = %d\r\n", + ap_delay_clk); + + if (ch347_swd_context.sent_cmd_count >= CH347_MAX_SEND_CMD) + ch347_swd_run_queue(); + + if (!ch347_chk_buf_size(cmd, ap_delay_clk)) + ch347_swd_run_queue(); + + pswd_io = ch347_get_one_swd_io(); + if (!pswd_io) { + ch347_swd_run_queue(); + pswd_io = ch347_get_one_swd_io(); + if (!pswd_io) { + LOG_DEBUG("ch347_swd_queue_cmd error "); + ch347_swd_context.queued_retval = ERROR_FAIL; + return; + } + } + + pswd_io->cmd = cmd | SWD_CMD_START | SWD_CMD_PARK; + + if (pswd_io->cmd & SWD_CMD_RNW) { + pswd_io->usbcmd = CH347_CMD_SWD_REG_R; + pswd_io->dst = dst; + ch347_read_swd_reg(pswd_io->cmd); + } else { + pswd_io->usbcmd = CH347_CMD_SWD_REG_W; + pswd_io->value = data; + ch347_wrtie_swd_reg(pswd_io->cmd, (uint8_t *)&data, + parity_u32(data)); + } + + ch347_swd_context.sent_cmd_count++; + list_add_tail(&pswd_io->list_entry, &ch347_swd_context.send_cmd_head); + /* Insert idle cycles after AP accesses to avoid WAIT */ + if (cmd & SWD_CMD_APNDP) { + if (ap_delay_clk == 0) + printf("ap_delay_clk == 0"); + ch347_swd_send_idle(ap_delay_clk); + } +} + +static int ch347_swd_switch_seq(enum swd_special_seq seq) +{ + printf("ch347_swd_switch_seq %d \r\n", seq); + switch (seq) { + case LINE_RESET: + LOG_DEBUG("SWD line reset"); + return ch347_swd_switch_out(seq, swd_seq_line_reset, + swd_seq_line_reset_len); + case JTAG_TO_SWD: + LOG_DEBUG("JTAG-to-SWD"); + return ch347_swd_switch_out(seq, swd_seq_jtag_to_swd, + swd_seq_jtag_to_swd_len); + case JTAG_TO_DORMANT: + LOG_DEBUG("JTAG-to-DORMANT"); + return ch347_swd_switch_out(seq, swd_seq_jtag_to_dormant, + swd_seq_jtag_to_dormant_len); + case SWD_TO_JTAG: + LOG_DEBUG("SWD-to-JTAG"); + return ch347_swd_switch_out(seq, swd_seq_swd_to_jtag, + swd_seq_swd_to_jtag_len); + case SWD_TO_DORMANT: + LOG_DEBUG("SWD-to-DORMANT"); + return ch347_swd_switch_out(seq, swd_seq_swd_to_dormant, + swd_seq_swd_to_dormant_len); + case DORMANT_TO_SWD: + LOG_DEBUG("DORMANT-to-SWD"); + return ch347_swd_switch_out(seq, swd_seq_dormant_to_swd, + swd_seq_dormant_to_swd_len); + case DORMANT_TO_JTAG: + LOG_DEBUG("DORMANT-to-JTAG"); + return ch347_swd_switch_out(seq, swd_seq_dormant_to_jtag, + swd_seq_dormant_to_jtag_len); + default: + LOG_ERROR("Sequence %d not supported", seq); + return ERROR_FAIL; + } +} + +static void ch347_swd_read_reg(uint8_t cmd, uint32_t *value, + uint32_t ap_delay_clk) +{ + assert(cmd & SWD_CMD_RNW); + ch347_swd_queue_cmd(cmd, value, 0, ap_delay_clk); +} + +static void ch347_swd_write_reg(uint8_t cmd, uint32_t value, + uint32_t ap_delay_clk) +{ + assert(!(cmd & SWD_CMD_RNW)); + ch347_swd_queue_cmd(cmd, NULL, value, ap_delay_clk); +} + static const struct swd_driver ch347_swd = { .init = ch347_swd_init, .switch_seq = ch347_swd_switch_seq, @@ -1965,4 +2078,4 @@ struct adapter_driver ch347_adapter_driver = { .jtag_ops = &ch347_interface, .swd_ops = &ch347_swd, -}; +}; \ No newline at end of file From 9dda7626e035d2a83115133eccd002dea1cd9b2e Mon Sep 17 00:00:00 2001 From: EasyDevKits Date: Wed, 11 Oct 2023 21:21:44 +0200 Subject: [PATCH 16/22] Added manufacturer, product and serial number to log output Misspelling in function name fixed --- src/jtag/drivers/ch347.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/src/jtag/drivers/ch347.c b/src/jtag/drivers/ch347.c index bdb1650c2f..c9cacb81f0 100755 --- a/src/jtag/drivers/ch347.c +++ b/src/jtag/drivers/ch347.c @@ -215,13 +215,31 @@ static bool ch347_open_device(void) char firmwareVersion; if (jtag_libusb_control_transfer(ch347_handle, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, - VENDOR_VERSION, 0, 0, &firmwareVersion, sizeof(firmwareVersion), USB_WRITE_TIMEOUT, NULL) != ERROR_OK) - { + VENDOR_VERSION, 0, 0, &firmwareVersion, sizeof(firmwareVersion), USB_WRITE_TIMEOUT, NULL) != ERROR_OK) { LOG_ERROR("ch347 unable to get firmware version"); return false; } - LOG_INFO("CH347 found (Chip version=%X.%2X, Firmware=0x%02X)", + char manufacturer[256+1]; + if (libusb_get_string_descriptor_ascii(ch347_handle, ch347_device_descriptor.iManufacturer, + (unsigned char *)manufacturer, sizeof(manufacturer)-1) < 0) { + strcpy(manufacturer, "(unknown)"); + } + char product[256+1]; + if (libusb_get_string_descriptor_ascii(ch347_handle, ch347_device_descriptor.iProduct, + (unsigned char *)product, sizeof(product)-1) < 0) { + strcpy(product, "(unknown)"); + } + char serialNumber[256+1]; + if (libusb_get_string_descriptor_ascii(ch347_handle, ch347_device_descriptor.iSerialNumber, + (unsigned char *)serialNumber, sizeof(serialNumber)-1) < 0) { + strcpy(serialNumber, "(unknown)"); + } + + LOG_INFO("CH347 %s from vendor %s with serial number %s found. (Chip version=%X.%2X, Firmware=0x%02X)", + product, + manufacturer, + serialNumber, (ch347_device_descriptor.bcdDevice >> 8) & 0xFF, ch347_device_descriptor.bcdDevice & 0xFF, firmwareVersion); @@ -1651,7 +1669,7 @@ static void ch347_swd_queue_flush(void) } } -static void ch347_wrtie_swd_reg(uint8_t cmd, const uint8_t *out, uint8_t parity) +static void ch347_write_swd_reg(uint8_t cmd, const uint8_t *out, uint8_t parity) { ch347_swd_context.send_buf[ch347_swd_context.send_len++] = CH347_CMD_SWD_REG_W; @@ -1668,7 +1686,7 @@ static void ch347_wrtie_swd_reg(uint8_t cmd, const uint8_t *out, uint8_t parity) ch347_swd_context.need_recv_len += (1 + 1); } -static void ch347_wrtie_spec_seq(const uint8_t *out, uint8_t out_len) +static void ch347_write_spec_seq(const uint8_t *out, uint8_t out_len) { ch347_swd_context.send_buf[ch347_swd_context.send_len++] = CH347_CMD_SWD_SEQ_W; @@ -1710,7 +1728,7 @@ static int ch347_swd_switch_out(enum swd_special_seq seq, const uint8_t *out, un pswd_io = ch347_get_one_swd_io(); if (pswd_io) { - ch347_wrtie_spec_seq(out, out_len); + ch347_write_spec_seq(out, out_len); list_add_tail(&pswd_io->list_entry, &ch347_swd_context.send_cmd_head); return ERROR_OK; @@ -1786,7 +1804,7 @@ static void ch347_swd_send_idle(uint32_t ap_delay_clk) return; } } - ch347_wrtie_spec_seq(NULL, ap_delay_clk); + ch347_write_spec_seq(NULL, ap_delay_clk); list_add_tail(&pswd_io->list_entry, &ch347_swd_context.send_cmd_head); } @@ -1983,7 +2001,7 @@ static void ch347_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint3 } else { pswd_io->usbcmd = CH347_CMD_SWD_REG_W; pswd_io->value = data; - ch347_wrtie_swd_reg(pswd_io->cmd, (uint8_t *)&data, + ch347_write_swd_reg(pswd_io->cmd, (uint8_t *)&data, parity_u32(data)); } From cfe9291af238f50255722357ff3cbf105fab4997 Mon Sep 17 00:00:00 2001 From: EasyDevKits <142944713+EasyDevKits@users.noreply.github.com> Date: Wed, 11 Oct 2023 21:40:38 +0200 Subject: [PATCH 17/22] Update README.md --- README.md | 159 ++---------------------------------------------------- 1 file changed, 3 insertions(+), 156 deletions(-) diff --git a/README.md b/README.md index 2a3adac74c..f45520fc58 100755 --- a/README.md +++ b/README.md @@ -4,50 +4,10 @@ **This repository is forked from [espressif/openocd-esp32](https://github.com/espressif/openocd-esp32) and contains modifications for working with [EasyDevKits](https://www.easydevkits.com/)** -OpenOCD provides on-chip programming and debugging support with a -layered architecture of JTAG interface and TAP support including: - -- (X)SVF playback to facilitate automated boundary scan and FPGA/CPLD - programming; -- debug target support (e.g. ARM, MIPS): single-stepping, - breakpoints/watchpoints, gprof profiling, etc; -- flash chip drivers (e.g. CFI, NAND, internal flash); -- embedded TCL interpreter for easy scripting. - -Several network interfaces are available for interacting with OpenOCD: -telnet, TCL, and GDB. The GDB server enables OpenOCD to function as a -"remote target" for source-level debugging of embedded systems using -the GNU GDB program (and the others who talk GDB protocol, e.g. IDA -Pro). - -This README file contains an overview of the following topics: - -- quickstart instructions, -- how to find and build more OpenOCD documentation, -- list of the supported hardware, -- the installation and build process, -- packaging tips. - - -# Quickstart for the impatient - -If you have a popular board then just start OpenOCD with its config, -e.g.: - - ```openocd -f board/stm32f4discovery.cfg``` - -If you are connecting a particular adapter with some specific target, -you need to source both the jtag interface and the target configs, -e.g.: - - ```openocd -f interface/ftdi/jtagkey2.cfg -c "transport select jtag" -f target/ti_calypso.cfg``` - - ```openocd -f interface/stlink.cfg -c "transport select hla_swd" -f target/stm32l0.cfg``` - -After OpenOCD startup, connect GDB with - - (gdb) target extended-remote localhost:3333 +If you need more information about OpenOCD please refer to the [main project](https://openocd.org/) +The EasyDevKits project integrates a target chip (in this case an ESP32) with a JTAG adapter chip on a single development board. +For an introduction you can visit [EasyDevKits](https://www.easydevkits.com/) or watch the introduction video on [Youtube](https://www.youtube.com/watch?v=Hq00uXbZy-M) # OpenOCD Documentation @@ -68,119 +28,6 @@ by subscribing to the OpenOCD developer mailing list: openocd-devel@lists.sourceforge.net -# Building the OpenOCD Documentation - -By default the OpenOCD build process prepares documentation in the -"Info format" and installs it the standard way, so that "info openocd" -can access it. - -Additionally, the OpenOCD User's Guide can be produced in the -following different formats: - - **If PDFVIEWER is set, this creates and views the PDF User Guide.** - - ```make pdf && ${PDFVIEWER} doc/openocd.pdf``` - - **If HTMLVIEWER is set, this creates and views the HTML User Guide.** - - ```make html && ${HTMLVIEWER} doc/openocd.html/index.html``` - -The OpenOCD Developer Manual contains information about the internal -architecture and other details about the code: - - **NB! make sure doxygen is installed, type doxygen --version** - - ```make doxygen && ${HTMLVIEWER} doxygen/index.html``` - - -# Supported hardware - -## JTAG adapters - -AM335x, ARM-JTAG-EW, ARM-USB-OCD, ARM-USB-TINY, AT91RM9200, axm0432, BCM2835, -Bus Blaster, Buspirate, Cadence DPI, Cadence vdebug, Chameleon, CMSIS-DAP, -Cortino, Cypress KitProg, DENX, Digilent JTAG-SMT2, DLC 5, DLP-USB1232H, -**EasyDevKits**, embedded projects, Espressif USB JTAG Programmer, -eStick, FlashLINK, FlossJTAG, Flyswatter, Flyswatter2, -FTDI FT232R, Gateworks, Hoegl, ICDI, ICEBear, J-Link, JTAG VPI, JTAGkey, -JTAGkey2, JTAG-lock-pick, KT-Link, Linux GPIOD, Lisa/L, LPC1768-Stick, -Mellanox rshim, MiniModule, NGX, Nuvoton Nu-Link, Nu-Link2, NXHX, NXP IMX GPIO, -OOCDLink, Opendous, OpenJTAG, Openmoko, OpenRD, OSBDM, Presto, Redbee, -Remote Bitbang, RLink, SheevaPlug devkit, Stellaris evkits, -ST-LINK (SWO tracing supported), STM32-PerformanceStick, STR9-comStick, -sysfsgpio, TI XDS110, TUMPA, Turtelizer, ULINK, USB-A9260, USB-Blaster, -USB-JTAG, USBprog, VPACLink, VSLLink, Wiggler, XDS100v2, Xilinx XVC/PCIe, -Xverve. - -## Debug targets - -ARM: AArch64, ARM11, ARM7, ARM9, Cortex-A/R (v7-A/R), Cortex-M (ARMv{6/7/8}-M), -FA526, Feroceon/Dragonite, XScale. -ARCv2, AVR32, DSP563xx, DSP5680xx, EnSilica eSi-RISC, EJTAG (MIPS32, MIPS64), -ESP32, ESP32-S2, ESP32-S3, Intel Quark, LS102x-SAP, RISC-V, ST STM8, -Xtensa. - -## Flash drivers - -ADUC702x, AT91SAM, AT91SAM9 (NAND), ATH79, ATmega128RFA1, Atmel SAM, AVR, CFI, -DSP5680xx, EFM32, EM357, eSi-RISC, eSi-TSMC, EZR32HG, FM3, FM4, Freedom E SPI, -i.MX31, Kinetis, LPC8xx/LPC1xxx/LPC2xxx/LPC541xx, LPC2900, LPC3180, LPC32xx, -LPCSPIFI, Marvell QSPI, MAX32, Milandr, MXC, NIIET, nRF51, nRF52 , NuMicro, -NUC910, Orion/Kirkwood, PIC32mx, PSoC4/5LP/6, Renesas RPC HF and SH QSPI, -S3C24xx, S3C6400, SiM3x, SiFive Freedom E, Stellaris, ST BlueNRG, STM32, -STM32 QUAD/OCTO-SPI for Flash/FRAM/EEPROM, STMSMI, STR7x, STR9x, SWM050, -TI CC13xx, TI CC26xx, TI CC32xx, TI MSP432, Winner Micro w600, Xilinx XCF, -XMC1xxx, XMC4xxx. - - -# Installing OpenOCD - -## A Note to OpenOCD Users - -If you would rather be working "with" OpenOCD rather than "on" it, your -operating system or JTAG interface supplier may provide binaries for -you in a convenient-enough package. - -Such packages may be more stable than git mainline, where -bleeding-edge development takes place. These "Packagers" produce -binary releases of OpenOCD after the developers produces new "release" -versions of the source code. Previous versions of OpenOCD cannot be -used to diagnose problems with the current release, so users are -encouraged to keep in contact with their distribution package -maintainers or interface vendors to ensure suitable upgrades appear -regularly. - -Users of these binary versions of OpenOCD must contact their Packager to -ask for support or newer versions of the binaries; the OpenOCD -developers do not support packages directly. - -## A Note to OpenOCD Packagers - -You are a PACKAGER of OpenOCD if you: - -- Sell dongles and include pre-built binaries; -- Supply tools or IDEs (a development solution integrating OpenOCD); -- Build packages (e.g. RPM or DEB files for a GNU/Linux distribution). - -As a PACKAGER, you will experience first reports of most issues. -When you fix those problems for your users, your solution may help -prevent hundreds (if not thousands) of other questions from other users. - -If something does not work for you, please work to inform the OpenOCD -developers know how to improve the system or documentation to avoid -future problems, and follow-up to help us ensure the issue will be fully -resolved in our future releases. - -That said, the OpenOCD developers would also like you to follow a few -suggestions: - -- Send patches, including config files, upstream, participate in the - discussions; -- Enable all the options OpenOCD supports, even those unrelated to your - particular hardware; -- Use "ftdi" interface adapter driver for the FTDI-based devices. - - # Building OpenOCD The INSTALL file contains generic instructions for running 'configure' From 8c854988feb7d8f602d95f1f7bae65985c7faba0 Mon Sep 17 00:00:00 2001 From: EasyDevKits Date: Thu, 12 Oct 2023 00:47:23 +0200 Subject: [PATCH 18/22] CH347: Error message for libusb_claim_interface enhanced --- src/jtag/drivers/ch347.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/jtag/drivers/ch347.c b/src/jtag/drivers/ch347.c index c9cacb81f0..3540fc4d5a 100755 --- a/src/jtag/drivers/ch347.c +++ b/src/jtag/drivers/ch347.c @@ -207,8 +207,9 @@ static bool ch347_open_device(void) struct libusb_device_descriptor ch347_device_descriptor; libusb_get_device_descriptor(libusb_get_device(ch347_handle), &ch347_device_descriptor); - if (libusb_claim_interface(ch347_handle, CH347_MPHSI_INTERFACE)) { - LOG_ERROR("ch347 unable to claim interface"); + int err_code = libusb_claim_interface(ch347_handle, CH347_MPHSI_INTERFACE); + if (err_code != ERROR_OK) { + LOG_ERROR("ch347 unable to claim interface: %s", libusb_error_name(err_code)); return false; } From 6d371ffcaf2ec26072a01e1274e966850203c072 Mon Sep 17 00:00:00 2001 From: EasyDevKits Date: Thu, 12 Oct 2023 23:47:32 +0200 Subject: [PATCH 19/22] adjusted for esp32 flavour --- .github/workflows/issue_comment.yml | 19 +++++++++++++++++++ .github/workflows/new_issues.yml | 19 +++++++++++++++++++ .github/workflows/new_prs.yml | 25 +++++++++++++++++++++++++ .gitignore | 11 +++++++++++ 4 files changed, 74 insertions(+) create mode 100755 .github/workflows/issue_comment.yml create mode 100755 .github/workflows/new_issues.yml create mode 100755 .github/workflows/new_prs.yml mode change 100644 => 100755 .gitignore diff --git a/.github/workflows/issue_comment.yml b/.github/workflows/issue_comment.yml new file mode 100755 index 0000000000..9ca538fc22 --- /dev/null +++ b/.github/workflows/issue_comment.yml @@ -0,0 +1,19 @@ +name: Sync issue comments to JIRA + +# This workflow will be triggered when new issue comment is created (including PR comments) +on: issue_comment + +jobs: + sync_issue_comments_to_jira: + name: Sync Issue Comments to Jira + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Sync issue comments to JIRA + uses: espressif/github-actions/sync_issues_to_jira@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + JIRA_PASS: ${{ secrets.JIRA_PASS }} + JIRA_PROJECT: OCD + JIRA_URL: ${{ secrets.JIRA_URL }} + JIRA_USER: ${{ secrets.JIRA_USER }} diff --git a/.github/workflows/new_issues.yml b/.github/workflows/new_issues.yml new file mode 100755 index 0000000000..efa672cc18 --- /dev/null +++ b/.github/workflows/new_issues.yml @@ -0,0 +1,19 @@ +name: Sync issues to Jira + +# This workflow will be triggered when a new issue is opened +on: issues + +jobs: + sync_issues_to_jira: + name: Sync issues to Jira + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Sync GitHub issues to Jira project + uses: espressif/github-actions/sync_issues_to_jira@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + JIRA_PASS: ${{ secrets.JIRA_PASS }} + JIRA_PROJECT: OCD + JIRA_URL: ${{ secrets.JIRA_URL }} + JIRA_USER: ${{ secrets.JIRA_USER }} diff --git a/.github/workflows/new_prs.yml b/.github/workflows/new_prs.yml new file mode 100755 index 0000000000..3cb5a4b230 --- /dev/null +++ b/.github/workflows/new_prs.yml @@ -0,0 +1,25 @@ + +name: Sync remain PRs to Jira + +# This workflow will be triggered every hour, to sync remaining PRs (i.e. PRs with zero comment) to Jira project +# Note that, PRs can also get synced when new PR comment is created +on: + schedule: + - cron: "0 * * * *" + +jobs: + sync_prs_to_jira: + name: Sync PRs to Jira + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Sync PRs to Jira project + uses: espressif/github-actions/sync_issues_to_jira@master + with: + cron_job: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + JIRA_PASS: ${{ secrets.JIRA_PASS }} + JIRA_PROJECT: OCD + JIRA_URL: ${{ secrets.JIRA_URL }} + JIRA_USER: ${{ secrets.JIRA_USER }} diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 index ecdfee76f4..d440620f12 --- a/.gitignore +++ b/.gitignore @@ -117,3 +117,14 @@ tcl-lite/* # A compile_commands.json can be generated using bear and will help tools such # as clangd to locate header files and use correct $CFLAGS compile_commands.json +compile +config.guess +config.sub +depcomp +install-sh +ltmain.sh +mdate-sh +missing +texinfo.tex +.vscode/launch.json +tcl/openocd.cfg From 2d4cf8c5fa08cf08d6a0db6ebb32943bfe03a5b4 Mon Sep 17 00:00:00 2001 From: EasyDevKits <142944713+EasyDevKits@users.noreply.github.com> Date: Thu, 12 Oct 2023 23:58:03 +0200 Subject: [PATCH 20/22] Delete .github/workflows/OpenOCD EasyDevKits CI.yml --- .github/workflows/OpenOCD EasyDevKits CI.yml | 59 -------------------- 1 file changed, 59 deletions(-) delete mode 100755 .github/workflows/OpenOCD EasyDevKits CI.yml diff --git a/.github/workflows/OpenOCD EasyDevKits CI.yml b/.github/workflows/OpenOCD EasyDevKits CI.yml deleted file mode 100755 index 9205c38043..0000000000 --- a/.github/workflows/OpenOCD EasyDevKits CI.yml +++ /dev/null @@ -1,59 +0,0 @@ -name: OpenOCD EasyDevKits CI - -on: - push: - branches: [ "master" ] - pull_request: - branches: [ "master" ] - -jobs: - build-linux: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - name: Install dependencies - run: sudo apt-get -y install libusb-1.0 - - name: Bootstrap - run: ./bootstrap - - name: Configure - run: ./configure - - name: Make - run: make - - name: Create package - run: make DESTDIR=/tmp install - - uses: actions/upload-artifact@v3 - with: - name: openocd-easydevkits-linux - path: /tmp/usr/local - - build-windows: - - runs-on: windows-latest - - defaults: - run: - shell: msys2 {0} - - steps: - - uses: actions/checkout@v3 - - uses: msys2/setup-msys2@v2 - with: - msystem: MINGW32 - update: true - #for MINGW64 but not working - install: base-devel mingw-w64-x86_64-toolchain git libtool pkg-config autoconf automake texinfo mingw-w64-x86_64-libusb - install: base-devel mingw-w64-i686-gcc mingw-w64-i686-toolchain git libtool pkg-config autoconf automake texinfo mingw-w64-i686-libusb - - - name: Bootstrap - run: ./bootstrap - - name: Configure - run: ./configure - - name: Make - run: make - - name: Create package - run: make DESTDIR=/tmp install - - uses: actions/upload-artifact@v3 - with: - name: openocd-easydevkits-windows - path: D:\a\_temp\msys64\tmp\mingw32 From 21952c1c493bda500b493478562a8c626d0a07c6 Mon Sep 17 00:00:00 2001 From: EasyDevKits Date: Fri, 13 Oct 2023 00:01:40 +0200 Subject: [PATCH 21/22] .gitignore reverted for esp32 flavour --- .gitignore | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/.gitignore b/.gitignore index d440620f12..ecdfee76f4 100755 --- a/.gitignore +++ b/.gitignore @@ -117,14 +117,3 @@ tcl-lite/* # A compile_commands.json can be generated using bear and will help tools such # as clangd to locate header files and use correct $CFLAGS compile_commands.json -compile -config.guess -config.sub -depcomp -install-sh -ltmain.sh -mdate-sh -missing -texinfo.tex -.vscode/launch.json -tcl/openocd.cfg From 9ca33498c29a41c83bcb3893c1315e94a0007dac Mon Sep 17 00:00:00 2001 From: EasyDevKits <142944713+EasyDevKits@users.noreply.github.com> Date: Fri, 13 Oct 2023 00:03:27 +0200 Subject: [PATCH 22/22] Delete README.md --- README.md | 186 ------------------------------------------------------ 1 file changed, 186 deletions(-) delete mode 100755 README.md diff --git a/README.md b/README.md deleted file mode 100755 index f45520fc58..0000000000 --- a/README.md +++ /dev/null @@ -1,186 +0,0 @@ -[![OpenOCD EasyDevKits CI](https://github.com/EasyDevKits/openocd-easydevkits/actions/workflows/OpenOCD%20EasyDevKits%20CI.yml/badge.svg)](https://github.com/EasyDevKits/openocd-easydevkits/actions/workflows/OpenOCD%20EasyDevKits%20CI.yml) - -# Welcome to OpenOCD for EasyDevKits! - -**This repository is forked from [espressif/openocd-esp32](https://github.com/espressif/openocd-esp32) and contains modifications for working with [EasyDevKits](https://www.easydevkits.com/)** - -If you need more information about OpenOCD please refer to the [main project](https://openocd.org/) - -The EasyDevKits project integrates a target chip (in this case an ESP32) with a JTAG adapter chip on a single development board. -For an introduction you can visit [EasyDevKits](https://www.easydevkits.com/) or watch the introduction video on [Youtube](https://www.youtube.com/watch?v=Hq00uXbZy-M) - -# OpenOCD Documentation - -In addition to the in-tree documentation, the latest manuals may be -viewed online at the following URLs: - - OpenOCD User's Guide: - http://openocd.org/doc/html/index.html - - OpenOCD Developer's Manual: - http://openocd.org/doc/doxygen/html/index.html - -These reflect the latest development versions, so the following section -introduces how to build the complete documentation from the package. - -For more information, refer to these documents or contact the developers -by subscribing to the OpenOCD developer mailing list: - - openocd-devel@lists.sourceforge.net - -# Building OpenOCD - -The INSTALL file contains generic instructions for running 'configure' -and compiling the OpenOCD source code. That file is provided by -default for all GNU autotools packages. If you are not familiar with -the GNU autotools, then you should read those instructions first. - -The remainder of this document tries to provide some instructions for -those looking for a quick-install. - -## OpenOCD Dependencies - -GCC or Clang is currently required to build OpenOCD. The developers -have begun to enforce strict code warnings (-Wall, -Werror, -Wextra, -and more) and use C99-specific features: inline functions, named -initializers, mixing declarations with code, and other tricks. While -it may be possible to use other compilers, they must be somewhat -modern and could require extending support to conditionally remove -GCC-specific extensions. - -You'll also need: - -- make -- libtool -- pkg-config >= 0.23 or pkgconf - -OpenOCD uses jimtcl library; build from git can retrieve jimtcl as git -submodule. - -Additionally, for building from git: - -- autoconf >= 2.69 -- automake >= 1.14 -- texinfo >= 5.0 - -Optional USB-based adapter drivers need libusb-1.0. - -Optional USB-Blaster, ASIX Presto and OpenJTAG interface adapter -drivers need: - - libftdi: http://www.intra2net.com/en/developer/libftdi/index.php - -Optional CMSIS-DAP adapter driver needs HIDAPI library. - -Optional linuxgpiod adapter driver needs libgpiod library. - -Optional J-Link adapter driver needs libjaylink library. - -Optional ARM disassembly needs capstone library. - -Optional development script checkpatch needs: - -- perl -- python -- python-ply - -## Permissions delegation - -Running OpenOCD with root/administrative permissions is strongly -discouraged for security reasons. - -For USB devices on GNU/Linux you should use the contrib/60-openocd.rules -file. It probably belongs somewhere in /etc/udev/rules.d, but -consult your operating system documentation to be sure. Do not forget -to add yourself to the "plugdev" group. - -For parallel port adapters on GNU/Linux and FreeBSD please change your -"ppdev" (parport* or ppi*) device node permissions accordingly. - -For parport adapters on Windows you need to run install_giveio.bat -(it's also possible to use "ioperm" with Cygwin instead) to give -ordinary users permissions for accessing the "LPT" registers directly. - -## Compiling OpenOCD - -To build OpenOCD, use the following sequence of commands: - - ```./bootstrap (when building from the git repository)``` - - ```./configure [options]``` - - ```make``` - - ```sudo make install``` - -The 'configure' step generates the Makefiles required to build -OpenOCD, usually with one or more options provided to it. The first -'make' step will build OpenOCD and place the final executable in -'./src/'. The final (optional) step, ``make install'', places all of -the files in the required location. - -To see the list of all the supported options, run - ```./configure --help``` - -## Cross-compiling Options - -Cross-compiling is supported the standard autotools way, you just need -to specify the cross-compiling target triplet in the --host option, -e.g. for cross-building for Windows 32-bit with MinGW on Debian: - - ```./configure --host=i686-w64-mingw32 [options]``` - -To make pkg-config work nicely for cross-compiling, you might need an -additional wrapper script as described at - - https://autotools.io/pkgconfig/cross-compiling.html - -This is needed to tell pkg-config where to look for the target -libraries that OpenOCD depends on. Alternatively, you can specify -*_CFLAGS and *_LIBS environment variables directly, see "./configure ---help" for the details. - -For a more or less complete script that does all this for you, see - - contrib/cross-build.sh - -## Parallel Port Dongles - -If you want to access the parallel port using the PPDEV interface you -have to specify both --enable-parport AND --enable-parport-ppdev, since -the later option is an option to the parport driver. - -The same is true for the --enable-parport-giveio option, you have to -use both the --enable-parport AND the --enable-parport-giveio option -if you want to use giveio instead of ioperm parallel port access -method. - - -## Obtaining OpenOCD From GIT - -You can download the current GIT version with a GIT client of your -choice from the main repository: - - git://git.code.sf.net/p/openocd/code - -You may prefer to use a mirror: - - http://repo.or.cz/r/openocd.git - git://repo.or.cz/openocd.git - -Using the GIT command line client, you might use the following command -to set up a local copy of the current repository (make sure there is no -directory called "openocd" in the current directory): - - ```git clone git://git.code.sf.net/p/openocd/code openocd``` - -Then you can update that at your convenience using - - ```git pull``` - -There is also a gitweb interface, which you can use either to browse -the repository or to download arbitrary snapshots using HTTP: - - http://repo.or.cz/w/openocd.git - -Snapshots are compressed tarballs of the source tree, about 1.3 MBytes -each at this writing.