usbBlaster: add a low level to support both usbBlasterI(ftdi) and usbBlasterII(fx2)

This commit is contained in:
Gwenhael Goavec-Merou 2021-05-13 16:06:29 +02:00
parent e1e5efd652
commit 167d430c34
2 changed files with 234 additions and 74 deletions

View File

@ -27,6 +27,7 @@
#include "display.hpp"
#include "usbBlaster.hpp"
#include "ftdipp_mpsse.hpp"
#include "fx2_ll.hpp"
using namespace std;
@ -48,11 +49,39 @@ using namespace std;
#define display(...) do {}while(0)
#endif
UsbBlaster::UsbBlaster(bool verbose):
UsbBlaster::UsbBlaster(int vid, int pid, const std::string &firmware_path,
bool verbose):
_verbose(verbose), _nb_bit(0),
_curr_tms(0), _buffer_size(64)
{
init_internal();
if (pid == 0x6001)
ll_driver = new UsbBlasterI();
else if (pid == 0x6810)
ll_driver = new UsbBlasterII(firmware_path);
else
throw std::runtime_error("usb-blaster: unknown VID/PID");
_tck_pin = (1 << 0);
_tms_pin = (1 << 1);
_tdi_pin = (1 << 4);
_in_buf = (unsigned char *)malloc(sizeof(unsigned char) * _buffer_size);
_nb_bit = 0;
memset(_in_buf, 0, _buffer_size);
/* Force flush internal FT245 internal buffer */
if (pid == 0x6001) {
uint8_t val = DEFAULT | DO_WRITE | DO_BITBB | _tms_pin;
uint8_t tmp_buf[4096];
for (_nb_bit = 0; _nb_bit < 4096; _nb_bit += 2) {
tmp_buf[_nb_bit ] = val;
tmp_buf[_nb_bit + 1] = val | _tck_pin;
}
ll_driver->write(tmp_buf, _nb_bit, NULL, 0);
_nb_bit = 0;
}
}
UsbBlaster::~UsbBlaster()
@ -62,64 +91,9 @@ UsbBlaster::~UsbBlaster()
free(_in_buf);
}
void UsbBlaster::init_internal()
{
int ret;
_ftdi = ftdi_new();
if (_ftdi == NULL) {
cout << "open_device: failed to initialize ftdi" << endl;
throw std::exception();
}
ret = ftdi_usb_open(_ftdi, 0x09fb, 0x6001);
if (ret < 0) {
fprintf(stderr, "unable to open ftdi device: %d (%s)\n",
ret, ftdi_get_error_string(_ftdi));
ftdi_free(_ftdi);
throw std::exception();
}
ret = ftdi_usb_reset(_ftdi);
if (ret < 0) {
fprintf(stderr, "Error reset: %d (%s)\n",
ret, ftdi_get_error_string(_ftdi));
ftdi_free(_ftdi);
throw std::exception();
}
ret = ftdi_set_latency_timer(_ftdi, 2);
if (ret < 0) {
fprintf(stderr, "Error set latency timer: %d (%s)\n",
ret, ftdi_get_error_string(_ftdi));
ftdi_free(_ftdi);
throw std::exception();
}
_tck_pin = (1 << 0);
_tms_pin = (1 << 1);
_tdi_pin = (1 << 4);
_in_buf = (unsigned char *)malloc(sizeof(unsigned char) * _buffer_size);
/* Force flush internal FT245 internal buffer */
uint8_t val = DEFAULT | DO_WRITE | DO_BITBB | _tms_pin;
uint8_t tmp_buf[4096];
for (_nb_bit = 0; _nb_bit < 4096; _nb_bit += 2) {
tmp_buf[_nb_bit ] = val;
tmp_buf[_nb_bit + 1] = val | _tck_pin;
}
ftdi_write_data(_ftdi, tmp_buf, _nb_bit);
_nb_bit = 0;
memset(_in_buf, 0, _buffer_size);
}
int UsbBlaster::setClkFreq(uint32_t clkHZ)
{
(void) clkHZ;
printWarn("USB-Blaster has a 24MHz fixed frequency");
return 1;
return ll_driver->setClkFreq(clkHZ);
}
int UsbBlaster::writeTMS(uint8_t *tms, int len, bool flush_buffer)
@ -165,7 +139,6 @@ int UsbBlaster::writeTMS(uint8_t *tms, int len, bool flush_buffer)
if (ret < 0)
return ret;
}
//printInfo("writeTMS: end");
return len;
}
@ -174,7 +147,6 @@ int UsbBlaster::writeTMS(uint8_t *tms, int len, bool flush_buffer)
int UsbBlaster::writeTDI(uint8_t *tx, uint8_t *rx, uint32_t len, bool end)
{
uint32_t real_len = (end) ? len -1 : len;
uint32_t nb_byte = real_len >> 3;
uint32_t nb_bit = (real_len & 0x07);
@ -250,7 +222,6 @@ int UsbBlaster::writeTDI(uint8_t *tx, uint8_t *rx, uint32_t len, bool end)
/* set TMS high */
if (end) {
//printf("end\n");
_curr_tms = _tms_pin;
uint8_t mask = DEFAULT | DO_BITBB | _curr_tms;
if (tx && *tx_ptr & (1 << nb_bit))
@ -327,7 +298,7 @@ int UsbBlaster::flush()
*/
int UsbBlaster::writeByte(uint8_t *tdo, int nb_byte)
{
int ret = write(tdo != NULL, nb_byte);
int ret = write(tdo != NULL, nb_byte);
if (tdo && ret > 0)
memcpy(tdo, _in_buf, nb_byte);
return ret;
@ -357,24 +328,83 @@ int UsbBlaster::writeBit(uint8_t *tdo, int nb_bit)
int UsbBlaster::write(bool read, int rd_len)
{
int ret = 0;
if (_nb_bit == 0)
return 0;
ret = ftdi_write_data(_ftdi, _in_buf, _nb_bit);
if (ret != _nb_bit) {
printf("problem %d written %d\n", ret, _nb_bit);
int ret = ll_driver->write(_in_buf, _nb_bit,
(read)?_in_buf:NULL, rd_len);
_nb_bit = 0;
return ret;
}
/*
* USB Blash I specific implementation
*/
UsbBlasterI::UsbBlasterI()
{
int ret;
_ftdi = ftdi_new();
if (_ftdi == NULL) {
cout << "open_device: failed to initialize ftdi" << endl;
throw std::exception();
}
ret = ftdi_usb_open(_ftdi, 0x09fb, 0x6001);
if (ret < 0) {
fprintf(stderr, "unable to open ftdi device: %d (%s)\n",
ret, ftdi_get_error_string(_ftdi));
ftdi_free(_ftdi);
throw std::exception();
}
ret = ftdi_usb_reset(_ftdi);
if (ret < 0) {
fprintf(stderr, "Error reset: %d (%s)\n",
ret, ftdi_get_error_string(_ftdi));
ftdi_free(_ftdi);
throw std::exception();
}
ret = ftdi_set_latency_timer(_ftdi, 2);
if (ret < 0) {
fprintf(stderr, "Error set latency timer: %d (%s)\n",
ret, ftdi_get_error_string(_ftdi));
ftdi_free(_ftdi);
throw std::exception();
}
}
UsbBlasterI::~UsbBlasterI()
{
}
int UsbBlasterI::setClkFreq(uint32_t clkHZ)
{
(void) clkHZ;
printWarn("USB-BlasterI has a 24MHz fixed frequency");
return 1;
}
int UsbBlasterI::write(uint8_t *wr_buf, int wr_len,
uint8_t *rd_buf, int rd_len)
{
int ret = 0;
ret = ftdi_write_data(_ftdi, wr_buf, wr_len);
if (ret != wr_len) {
printf("problem %d written %d\n", ret, wr_len);
return ret;
}
if (read) {
if (rd_buf) {
int timeout = 100;
uint8_t byte_read = 0;
while (byte_read < rd_len && timeout != 0) {
timeout--;
ret = ftdi_read_data(_ftdi, _in_buf + byte_read, rd_len - byte_read);
ret = ftdi_read_data(_ftdi, rd_buf + byte_read, rd_len - byte_read);
if (ret < 0) {
printError("Write error: " + std::to_string(ret));
printError("Read error: " + std::to_string(ret));
return ret;
}
byte_read += ret;
@ -384,11 +414,85 @@ int UsbBlaster::write(bool read, int rd_len)
printError("Error: timeout " + std::to_string(byte_read) +
" " + std::to_string(rd_len));
for (int i=0; i < byte_read; i++)
printf("%02x ", _in_buf[i]);
printf("%02x ", rd_buf[i]);
printf("\n");
return 0;
}
}
return ret;
}
/*
* USB Blash II specific implementation
*/
UsbBlasterII::UsbBlasterII(const string &firmware_path)
{
uint8_t buf[5];
if (firmware_path.empty()) {
printError("missing FX2 firmware");
printError("use --probe-firmware with something");
printError("like /opt/altera/quartus/linux64/blaster_6810.hex");
throw std::runtime_error("usbBlasterII: missing firmware");
}
fx2 = new FX2_ll(0x09fb, 0x6810, 0x09fb, 0x6010, firmware_path);
if (!fx2->read_ctrl(0x94, 0, buf, 5)) {
throw std::runtime_error("Unable to read firmware version.");
}
printInfo("USB-Blaster II firmware version: " + std::string((char *)buf));
}
UsbBlasterII::~UsbBlasterII()
{
delete fx2;
}
int UsbBlasterII::setClkFreq(uint32_t clkHZ)
{
(void) clkHZ;
printWarn("USB-BlasterII has a 24MHz fixed frequency");
return 1;
}
int UsbBlasterII::write(uint8_t *wr_buf, int wr_len,
uint8_t *rd_buf, int rd_len)
{
int ret = 0;
ret = fx2->write(4, wr_buf, wr_len);
if (ret != wr_len) {
printf("problem %d written %d\n", ret, wr_len);
return ret;
}
if (rd_buf) {
uint8_t c = 0x5f;
ret = fx2->write(4, &c, 1);
if (ret != 1) {
printf("problem %d written %d\n", ret, wr_len);
return ret;
}
int timeout = 100;
uint8_t byte_read = 0;
while (byte_read < rd_len && timeout != 0) {
timeout--;
ret = fx2->read(8, rd_buf + byte_read, rd_len - byte_read);
if (ret < 0) {
printError("Read error: " + std::to_string(ret));
return ret;
}
byte_read += ret;
}
if (timeout == 0) {
printError("Error: timeout " + std::to_string(byte_read) +
" " + std::to_string(rd_len));
for (int i=0; i < byte_read; i++)
printf("%02x ", rd_buf[i]);
printf("\n");
return 0;
}
}
_nb_bit = 0;
return ret;
}

View File

@ -25,6 +25,22 @@
#include "board.hpp"
#include "jtagInterface.hpp"
#include "ftdipp_mpsse.hpp"
#include "fx2_ll.hpp"
/*!
* \file UsbBlaster.hpp
* \class UsbBlaster_ll
* \brief altera/intel usb blaster abstract class for blasterI and blasterII
* \author Gwenhael Goavec-Merou
*/
class UsbBlaster_ll {
public:
virtual ~UsbBlaster_ll() {}
virtual int setClkFreq(uint32_t clkHZ) = 0;
virtual int write(uint8_t *wr_buf, int wr_len,
uint8_t *rd_buf, int rd_len) = 0;
};
/*!
* \file UsbBlaster.hpp
@ -35,7 +51,8 @@
class UsbBlaster : public JtagInterface {
public:
UsbBlaster(bool verbose = false);
UsbBlaster(int vid, int pid, const std::string &firmware_path,
bool verbose = false);
virtual ~UsbBlaster();
int setClkFreq(uint32_t clkHZ) override;
@ -72,8 +89,7 @@ class UsbBlaster : public JtagInterface {
int flush() override;
private:
struct ftdi_context *_ftdi;
void init_internal();
UsbBlaster_ll *ll_driver;
int writeByte(uint8_t *tdo, int nb_byte);
int writeBit(uint8_t *tdo, int nb_bit);
int write(bool read, int rd_len);
@ -88,4 +104,44 @@ class UsbBlaster : public JtagInterface {
uint8_t _curr_tms;
uint16_t _buffer_size;
};
/*!
* \file UsbBlaster.hpp
* \class UsbBlasterI
* \brief altera/intel low level usb blaster class for blasterI
* \author Gwenhael Goavec-Merou
*/
class UsbBlasterI: public UsbBlaster_ll {
public:
UsbBlasterI();
virtual ~UsbBlasterI();
int setClkFreq(uint32_t clkHZ) override;
int write(uint8_t *wr_buf, int wr_len,
uint8_t *rd_buf, int rd_len) override;
private:
/*
* \brief init and configure FT245
*/
void init_internal();
struct ftdi_context *_ftdi; /*!< ftid_context */
};
/*!
* \file UsbBlaster.hpp
* \class UsbBlasterII
* \brief altera/intel low level usb blaster class for blasterII
* \author Gwenhael Goavec-Merou
*/
class UsbBlasterII: public UsbBlaster_ll {
public:
UsbBlasterII(const std::string &firmware_path);
virtual ~UsbBlasterII();
int setClkFreq(uint32_t clkHZ) override;
int write(uint8_t *wr_buf, int wr_len,
uint8_t *rd_buf, int rd_len) override;
private:
FX2_ll *fx2;
};
#endif