update CH347 (#424)

This commit is contained in:
ZhiYuanNJ 2024-02-29 03:44:49 +08:00 committed by GitHub
parent 85d9ca5d20
commit 4af0bf6ed5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 90 additions and 92 deletions

View File

@ -22,7 +22,12 @@
using namespace std; using namespace std;
#define CH347JTAG_VID 0x1a86 #define CH347JTAG_VID 0x1a86
#define CH347JTAG_PID 0x55dd #define CH347T_JTAG_PID 0x55dd //ch347T
#define CH347F_JTAG_PID 0x55de //ch347F
#define KHZ(n) (uint32_t)((n)*UINT32_C(1000))
#define MHZ(n) (uint32_t)((n)*UINT32_C(1000000))
#define GHZ(n) (uint32_t)((n)*UINT32_C(1000000000))
#define CH347JTAG_INTF 2 #define CH347JTAG_INTF 2
#define CH347JTAG_WRITE_EP 0x06 #define CH347JTAG_WRITE_EP 0x06
@ -51,17 +56,17 @@ static void LIBUSB_CALL sync_cb(struct libusb_transfer *transfer) {
// defer should only be used with rlen == 0 // defer should only be used with rlen == 0
int CH347Jtag::usb_xfer(unsigned wlen, unsigned rlen, unsigned *ract, bool defer) { int CH347Jtag::usb_xfer(unsigned wlen, unsigned rlen, unsigned *ract, bool defer)
{
int actual_length = 0;
if (_verbose) { if (_verbose) {
fprintf(stderr, "usb_xfer: deferred: %ld\n", obuf - _obuf); fprintf(stderr, "usb_xfer: deferred: %ld\n", obuf - _obuf);
} }
if (defer && !rlen && obuf - _obuf + wlen < MAX_BUFFER - 12) { if (defer && !rlen && obuf - _obuf + wlen < (MAX_BUFFER - 12)) {
obuf += wlen; obuf += wlen;
return 0; return 0;
} }
// write out whole buffer
if (obuf - _obuf > MAX_BUFFER) { if (obuf - _obuf > MAX_BUFFER) {
throw runtime_error("buffer overflow"); throw runtime_error("buffer overflow");
} }
@ -84,66 +89,39 @@ int CH347Jtag::usb_xfer(unsigned wlen, unsigned rlen, unsigned *ract, bool defer
fprintf(stderr, "}\n\n"); fprintf(stderr, "}\n\n");
} }
int wcomplete = 0, rcomplete = 0; int r = 0;
libusb_fill_bulk_transfer(wtrans, dev_handle, CH347JTAG_WRITE_EP, obuf, if (wlen) {
wlen, sync_cb, &wcomplete, CH347JTAG_TIMEOUT); if ((r = libusb_bulk_transfer(dev_handle, CH347JTAG_WRITE_EP, obuf, wlen, &actual_length, CH347JTAG_TIMEOUT)) < 0 ) {
int r = libusb_submit_transfer(wtrans);
if (r < 0)
return r;
if (rlen) {
rcomplete = 0;
libusb_fill_bulk_transfer(rtrans, dev_handle, CH347JTAG_READ_EP, ibuf,
rlen, sync_cb, &rcomplete, CH347JTAG_TIMEOUT);
r = libusb_submit_transfer(rtrans);
if (r < 0)
return r; return r;
} else { }
rcomplete = 1;
} }
while (!wcomplete) { if (_verbose) {
r = libusb_handle_events_completed(usb_ctx, &wcomplete); fprintf(stderr, "obuf[%d] = {", wlen);
if (r < 0) { for (unsigned i = 0; i < wlen; ++i) {
if (r != LIBUSB_ERROR_INTERRUPTED) { fprintf(stderr, "%02x ", obuf[i]);
libusb_cancel_transfer(wtrans); }
if (rlen) libusb_cancel_transfer(rtrans); fprintf(stderr, "}\n\n");
}
obuf = _obuf;
int rlen_total = 0;
uint8_t *pibuf = ibuf;
if (rlen){
while (rlen) {
if ((r = libusb_bulk_transfer(dev_handle, CH347JTAG_READ_EP, pibuf, rlen, &actual_length, CH347JTAG_TIMEOUT)) < 0 ) {
return r;
} }
continue; if (_verbose) {
} fprintf(stderr, "ibuf[%d] = {", actual_length);
if (!wtrans->dev_handle) { for (int i = rlen_total; i < rlen_total + actual_length; ++i) {
wtrans->status = LIBUSB_TRANSFER_NO_DEVICE; fprintf(stderr, "%02x ", ibuf[i]);
wcomplete = 1; }
} fprintf(stderr, "}\n\n");
}
while (!rcomplete) {
r = libusb_handle_events_completed(usb_ctx, &rcomplete);
if (r < 0) {
if (r != LIBUSB_ERROR_INTERRUPTED)
libusb_cancel_transfer(rtrans);
continue;
}
if (!rtrans->dev_handle) {
rtrans->status = LIBUSB_TRANSFER_NO_DEVICE;
rcomplete = 1;
}
}
if (wtrans->status != LIBUSB_TRANSFER_COMPLETED) {
return LIBUSB_ERROR_IO;
}
if (rlen) {
if (rtrans->status != LIBUSB_TRANSFER_COMPLETED) {
return LIBUSB_ERROR_IO;
}
if ((int)rlen > rtrans->actual_length) {
throw runtime_error("input buffer underflow");
}
if (ract) *ract = rtrans->actual_length;
if (_verbose) {
fprintf(stderr, "ibuf[%d] = {", rtrans->actual_length);
for (int i = 0; i < rtrans->actual_length; ++i) {
fprintf(stderr, "%02x ", ibuf[i]);
} }
fprintf(stderr, "}\n\n"); rlen -= actual_length;
pibuf += actual_length;
rlen_total += actual_length;
} }
*ract = rlen_total;
} }
return 0; return 0;
} }
@ -164,10 +142,13 @@ int CH347Jtag::setClk(const uint8_t &factor) {
return 0; return 0;
} }
CH347Jtag::CH347Jtag(uint32_t clkHZ, int8_t verbose): CH347Jtag::CH347Jtag(uint32_t clkHZ, int8_t verbose, int vid, int pid, uint8_t bus_addr, uint8_t dev_addr):
_verbose(verbose>1), dev_handle(NULL), usb_ctx(NULL), obuf(_obuf) _verbose(verbose>1), dev_handle(NULL), usb_ctx(NULL), obuf(_obuf)
{ {
libusb_device** devs;
int actual_length = 0; int actual_length = 0;
int i = 0;
ssize_t cnt;
struct libusb_device_descriptor desc; struct libusb_device_descriptor desc;
struct libusb_device *dev; struct libusb_device *dev;
int rv; int rv;
@ -175,8 +156,19 @@ CH347Jtag::CH347Jtag(uint32_t clkHZ, int8_t verbose):
printError("libusb init failed"); printError("libusb init failed");
goto err_exit; goto err_exit;
} }
dev_handle = libusb_open_device_with_vid_pid(usb_ctx, CH347JTAG_VID, cnt = libusb_get_device_list(NULL, &devs);
CH347JTAG_PID); if (cnt < 0) goto err_exit;
while ((dev = devs[i++]) != NULL) {
if (libusb_get_device_descriptor(dev, &desc) < 0)
continue;
if (desc.idVendor != vid || desc.idProduct != pid)
continue;
if (bus_addr != 0 && dev_addr != 0 && (libusb_get_bus_number(dev) != bus_addr || libusb_get_device_address(dev) != dev_addr))
continue;
libusb_open(dev, &dev_handle);
break;
}
libusb_free_device_list(devs, 1);
if (!dev_handle) { if (!dev_handle) {
printError("fails to open device"); printError("fails to open device");
goto usb_exit; goto usb_exit;
@ -193,8 +185,11 @@ CH347Jtag::CH347Jtag(uint32_t clkHZ, int8_t verbose):
goto usb_exit; goto usb_exit;
} }
if (desc.bcdDevice < 0x241) { if (desc.bcdDevice < 0x241 && pid == CH347T_JTAG_PID) {
_is_largerPack = false;
printWarn("Old version of the chip, JTAG might not work"); printWarn("Old version of the chip, JTAG might not work");
}else{
_is_largerPack = true;
} }
if (libusb_set_auto_detach_kernel_driver(dev_handle, true)) { if (libusb_set_auto_detach_kernel_driver(dev_handle, true)) {
@ -243,27 +238,28 @@ CH347Jtag::~CH347Jtag()
int CH347Jtag::_setClkFreq(uint32_t clkHZ) int CH347Jtag::_setClkFreq(uint32_t clkHZ)
{ {
#if 1 int setClk_index = 0;
unsigned i = 0, sl = 60000000 >> 5; uint32_t speed_clock_larger_pack[8] = {
for (; i < 6; ++i, sl <<= 1) { KHZ(468.75), KHZ(937.5), MHZ(1.875), MHZ(3.75),
if (clkHZ < sl) MHZ(7.5), MHZ(15), MHZ(30), MHZ(60)
break; };
uint32_t speed_clock_standard_pack[6] = {
MHZ(1.875), MHZ(3.75),
MHZ(7.5), MHZ(15), MHZ(30), MHZ(60)
};
uint32_t *ptr = _is_largerPack ? speed_clock_larger_pack : speed_clock_standard_pack;
int size = (_is_largerPack?sizeof(speed_clock_larger_pack):sizeof(speed_clock_standard_pack)) / sizeof(uint32_t);
for (int i = 0; i < size; ++i) {
if (clkHZ > ptr[i] && clkHZ <= ptr[i+1]){
setClk_index = i + 1;
}
} }
#else if (setClk(setClk_index)) {
int i = 6;
unsigned sl = 60000000;
for (; i > 1; --i, sl >>= 1) {
if (clkHZ > sl)
break;
}
#endif
_clkHZ = sl;
if (setClk(i)) {
printError("failed to set clock rate"); printError("failed to set clock rate");
return 0; return 0;
} }
char mess[256]; char mess[256];
snprintf(mess, 256, "JTAG TCK frequency set to %.3f MHz\n\n", _clkHZ/1e6); snprintf(mess, 256, "JTAG TCK frequency set to %.3f MHz\n\n", (double)ptr[setClk_index] / MHZ(1));
printInfo(mess); printInfo(mess);
return _clkHZ; return _clkHZ;
} }
@ -271,9 +267,10 @@ int CH347Jtag::_setClkFreq(uint32_t clkHZ)
int CH347Jtag::writeTMS(const uint8_t *tms, uint32_t len, bool flush_buffer, int CH347Jtag::writeTMS(const uint8_t *tms, uint32_t len, bool flush_buffer,
__attribute__((unused)) const uint8_t tdi) __attribute__((unused)) const uint8_t tdi)
{ {
if (get_obuf_length() < (int)(len * 2 + 4)) { // check if there is enough room left // if (get_obuf_length() < (int)(len * 2 + 4)) { // check if there is enough room left
flush(); // flush();
} // }
flush();
uint8_t *ptr = obuf; uint8_t *ptr = obuf;
for (uint32_t i = 0; i < len; ++i) { for (uint32_t i = 0; i < len; ++i) {
if (ptr == obuf) { if (ptr == obuf) {
@ -424,12 +421,12 @@ int CH347Jtag::writeTDI(const uint8_t *tx, uint8_t *rx, uint32_t len, bool end)
cerr << "writeTDI: invalid read data: " << endl; cerr << "writeTDI: invalid read data: " << endl;
return -EXIT_FAILURE; return -EXIT_FAILURE;
} }
for (unsigned i = 0; i < size / 8; ++i) { for (unsigned i = 0; i < size; ++i) {
uint8_t b = 0; if (ibuf[3 + i] == 0x01) {
uint8_t *xb = &ibuf[3 + i * 8]; *rptr |= (0x01 << i);
for (unsigned j = 0; j < 8; ++j) }else{
b |= (xb[j] & 1) << j; *rptr &= ~(0x01 << i);
*rptr++ = b; }
} }
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@ -12,7 +12,7 @@ constexpr unsigned MAX_BUFFER = 512;
class CH347Jtag : public JtagInterface { class CH347Jtag : public JtagInterface {
public: public:
CH347Jtag(uint32_t clkHZ, int8_t verbose); CH347Jtag(uint32_t clkHZ, int8_t verbose, int vid, int pid, uint8_t bus_addr, uint8_t dev_addr);
virtual ~CH347Jtag(); virtual ~CH347Jtag();
int setClkFreq(uint32_t clkHZ) override { return _setClkFreq(clkHZ); }; int setClkFreq(uint32_t clkHZ) override { return _setClkFreq(clkHZ); };
@ -32,6 +32,7 @@ class CH347Jtag : public JtagInterface {
private: private:
bool _verbose; bool _verbose;
bool _is_largerPack;
int setClk(const uint8_t &factor); int setClk(const uint8_t &factor);
libusb_device_handle *dev_handle; libusb_device_handle *dev_handle;

View File

@ -103,7 +103,7 @@ Jtag::Jtag(const cable_t &cable, const jtag_pins_conf_t *pin_conf,
_jtag = new CH552_jtag(cable, dev, serial, clkHZ, verbose); _jtag = new CH552_jtag(cable, dev, serial, clkHZ, verbose);
break; break;
case MODE_CH347: case MODE_CH347:
_jtag = new CH347Jtag(clkHZ, verbose); _jtag = new CH347Jtag(clkHZ, verbose, cable.vid, cable.pid, cable.bus_addr, cable.device_addr);
break; break;
case MODE_DIRTYJTAG: case MODE_DIRTYJTAG:
_jtag = new DirtyJtag(clkHZ, verbose); _jtag = new DirtyJtag(clkHZ, verbose);