Adds initial avrftdi TPI support.
Device identification is possible tested under OS X 10.6.8 with an FT4232H and ATtiny10. git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@1145 81a1dc3b-b13d-400b-aceb-764788c761c2
This commit is contained in:
parent
38c5f51a33
commit
008ff9bb97
|
@ -96,6 +96,8 @@ libavrdude_a_SOURCES = \
|
||||||
avrdude.h \
|
avrdude.h \
|
||||||
avrftdi.c \
|
avrftdi.c \
|
||||||
avrftdi.h \
|
avrftdi.h \
|
||||||
|
avrftdi_tpi.c \
|
||||||
|
avrftdi_tpi.h \
|
||||||
avrpart.c \
|
avrpart.c \
|
||||||
avrpart.h \
|
avrpart.h \
|
||||||
bitbang.c \
|
bitbang.c \
|
||||||
|
|
144
avrftdi.c
144
avrftdi.c
|
@ -38,8 +38,8 @@
|
||||||
#include "pgm.h"
|
#include "pgm.h"
|
||||||
#include "avrftdi.h"
|
#include "avrftdi.h"
|
||||||
#include "avrpart.h"
|
#include "avrpart.h"
|
||||||
#include "tpi.h"
|
#include "avrftdi_tpi.h"
|
||||||
#include "usbasp.h"
|
#include "avrftdi_private.h"
|
||||||
|
|
||||||
#ifdef HAVE_LIBUSB_1_0
|
#ifdef HAVE_LIBUSB_1_0
|
||||||
#ifdef HAVE_LIBFTDI1
|
#ifdef HAVE_LIBFTDI1
|
||||||
|
@ -64,26 +64,6 @@ enum { ERR, WARN, INFO, DEBUG, TRACE };
|
||||||
|
|
||||||
#define FTDI_DEFAULT_MASK ( (1 << (FTDI_SCK - 1)) | (1 << (FTDI_MOSI - 1)) )
|
#define FTDI_DEFAULT_MASK ( (1 << (FTDI_SCK - 1)) | (1 << (FTDI_MOSI - 1)) )
|
||||||
|
|
||||||
#define E(x, ftdi) \
|
|
||||||
do { \
|
|
||||||
if ((x)) { \
|
|
||||||
log_err("%s: %s (%d) %s", \
|
|
||||||
#x, strerror(errno), errno, ftdi_get_error_string(ftdi)); \
|
|
||||||
return -1; \
|
|
||||||
} \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
#define E_VOID(x, ftdi) \
|
|
||||||
do { \
|
|
||||||
if ((x)) { \
|
|
||||||
log_err("%s: %s (%d) %s", \
|
|
||||||
#x, strerror(errno), errno, ftdi_get_error_string(ftdi)); \
|
|
||||||
} \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
#define to_pdata(pgm) \
|
|
||||||
((avrftdi_t *)((pgm)->cookie))
|
|
||||||
|
|
||||||
/* This is for running the code without having a FTDI-device.
|
/* This is for running the code without having a FTDI-device.
|
||||||
* The generated code is useless! For debugging purposes only.
|
* The generated code is useless! For debugging purposes only.
|
||||||
* This should never be defined, unless you know what you are
|
* This should never be defined, unless you know what you are
|
||||||
|
@ -92,22 +72,6 @@ enum { ERR, WARN, INFO, DEBUG, TRACE };
|
||||||
*/
|
*/
|
||||||
//#define DRYRUN
|
//#define DRYRUN
|
||||||
|
|
||||||
typedef struct avrftdi_s {
|
|
||||||
/* pointer to struct maintained by libftdi to identify the device */
|
|
||||||
struct ftdi_context* ftdic;
|
|
||||||
/* bitmask of values for pins. bit 0 represents pin 0 ([A|B]DBUS0) */
|
|
||||||
uint16_t pin_value;
|
|
||||||
/* bitmask of pin direction. a '1' make a pin an output.
|
|
||||||
* bit 0 corresponds to pin 0. */
|
|
||||||
uint16_t pin_direction;
|
|
||||||
/* don't know. not useful. someone put it in. */
|
|
||||||
uint16_t led_mask;
|
|
||||||
/* total number of pins supported by a programmer. varies with FTDI chips */
|
|
||||||
int pin_limit;
|
|
||||||
/* internal RX buffer of the device. needed for INOUT transfers */
|
|
||||||
int rx_buffer_size;
|
|
||||||
} avrftdi_t;
|
|
||||||
|
|
||||||
static int write_flush(avrftdi_t *);
|
static int write_flush(avrftdi_t *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -586,6 +550,71 @@ static int avrftdi_transmit(avrftdi_t* pdata, unsigned char mode, unsigned char
|
||||||
return written;
|
return written;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* this function tries to sync up with the FTDI. See FTDI application note AN_129.
|
||||||
|
* AN_135 uses 0xab as bad command and enables/disables loopback around synchronisation.
|
||||||
|
* This may fail if data is left in the buffer (i.e. avrdude aborted with ctrl-c)
|
||||||
|
* or the device is in an illegal state (i.e. a previous program).
|
||||||
|
* If the FTDI is out of sync, the buffers are cleared ("purged") and the
|
||||||
|
* sync is re-tried.
|
||||||
|
* if it still fails, we return an error code. higher level code may than abort.
|
||||||
|
* the device may be reset by unplugging the device and plugging it back in.
|
||||||
|
* resetting the device did not always help for me.
|
||||||
|
*/
|
||||||
|
static int ftdi_sync(avrftdi_t* pdata)
|
||||||
|
{
|
||||||
|
unsigned char illegal_cmd[] = {0xaa};
|
||||||
|
unsigned char reply[2];
|
||||||
|
unsigned int i, n;
|
||||||
|
unsigned int retry = 0;
|
||||||
|
unsigned char latency;
|
||||||
|
|
||||||
|
ftdi_get_latency_timer(pdata->ftdic, &latency);
|
||||||
|
fprintf(stderr, "Latency: %d\n", latency);
|
||||||
|
|
||||||
|
do{
|
||||||
|
n = ftdi_read_data(pdata->ftdic, reply, 1);
|
||||||
|
} while(n > 0);
|
||||||
|
retry:
|
||||||
|
/* send command "0xaa", which is an illegal command. */
|
||||||
|
E(ftdi_write_data(pdata->ftdic, illegal_cmd, sizeof(illegal_cmd)) != sizeof(illegal_cmd), pdata->ftdic);
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
do {
|
||||||
|
#ifndef DRYRUN
|
||||||
|
n = ftdi_read_data(pdata->ftdic, &reply[i], sizeof(reply) - i);
|
||||||
|
E(n < 0, pdata->ftdic);
|
||||||
|
//fprintf(stderr, "%s\n", ftdi_get_error_string(pdata->ftdic));
|
||||||
|
#else
|
||||||
|
n = sizeof(reply) - i;
|
||||||
|
#endif
|
||||||
|
i += n;
|
||||||
|
} while (i < sizeof(reply));
|
||||||
|
|
||||||
|
/* 0xfa is return code for illegal command - we expect that, since we issued an
|
||||||
|
* illegal command (0xaa)
|
||||||
|
* the next byte will be the illegal command, the FTDI is complaining about.
|
||||||
|
*/
|
||||||
|
if(reply[0] == 0xfa && reply[1] == illegal_cmd[0])
|
||||||
|
{
|
||||||
|
/* if the FTDI is complaining about the right thing, everything is fine */
|
||||||
|
fprintf(stderr, "FTDI is in sync.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "FTDI out of sync. Received 0x%02x 0x%02x\n", reply[0], reply[1]);
|
||||||
|
if(retry < 4)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Trying to re-sync by purging buffers. Attempt\n");
|
||||||
|
E(ftdi_usb_purge_buffers(pdata->ftdic), pdata->ftdic);
|
||||||
|
retry++;
|
||||||
|
goto retry;
|
||||||
|
} else
|
||||||
|
fprintf(stderr, "Aborting. Try resetting or unplugging the device.\n");
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static int write_flush(avrftdi_t* pdata)
|
static int write_flush(avrftdi_t* pdata)
|
||||||
{
|
{
|
||||||
unsigned char buf[6];
|
unsigned char buf[6];
|
||||||
|
@ -615,23 +644,36 @@ static int write_flush(avrftdi_t* pdata)
|
||||||
*
|
*
|
||||||
* Add.: purge does NOT flush. It clears. Also, it is unkown, when the purge
|
* Add.: purge does NOT flush. It clears. Also, it is unkown, when the purge
|
||||||
* command actually arrives at the chip.
|
* command actually arrives at the chip.
|
||||||
* Use read-pin-status command as sync.
|
* Use read pin status command as sync.
|
||||||
*/
|
*/
|
||||||
#ifndef DRYRUN
|
#ifndef DRYRUN
|
||||||
//E(ftdi_usb_purge_buffers(pdata->ftdic), pdata->ftdic);
|
//E(ftdi_usb_purge_buffers(pdata->ftdic), pdata->ftdic);
|
||||||
|
|
||||||
unsigned char cmd[] = { GET_BITS_LOW, SEND_IMMEDIATE };
|
unsigned char cmd[] = { GET_BITS_LOW, SEND_IMMEDIATE };
|
||||||
unsigned int n;
|
unsigned int n;
|
||||||
|
int retries = 0;
|
||||||
|
int num = 0;
|
||||||
E(ftdi_write_data(pdata->ftdic, cmd, sizeof(cmd)) != sizeof(cmd), pdata->ftdic);
|
E(ftdi_write_data(pdata->ftdic, cmd, sizeof(cmd)) != sizeof(cmd), pdata->ftdic);
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
n = ftdi_read_data(pdata->ftdic, cmd, 1);
|
n = ftdi_read_data(pdata->ftdic, cmd, 1);
|
||||||
|
if(n > 0)
|
||||||
|
{
|
||||||
|
avrftdi_print(0, "Low byte lines: 0x%02x\n", cmd[0]);
|
||||||
|
num += n;
|
||||||
|
}
|
||||||
|
if(!n)
|
||||||
|
{
|
||||||
|
retries++;
|
||||||
|
}
|
||||||
E(n < 0, pdata->ftdic);
|
E(n < 0, pdata->ftdic);
|
||||||
} while(n < 1);
|
} while(retries < 1/*n < 1*/);
|
||||||
|
|
||||||
|
avrftdi_print(0, "Read %d extra bytes\n", num-1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -698,12 +740,21 @@ static int avrftdi_open(PROGRAMMER * pgm, char *port)
|
||||||
}
|
}
|
||||||
|
|
||||||
ftdi_set_latency_timer(pdata->ftdic, 1);
|
ftdi_set_latency_timer(pdata->ftdic, 1);
|
||||||
|
//ftdi_write_data_set_chunksize(pdata->ftdic, 16);
|
||||||
|
//ftdi_read_data_set_chunksize(pdata->ftdic, 16);
|
||||||
|
|
||||||
/* set SPI mode */
|
/* set SPI mode */
|
||||||
E(ftdi_set_bitmode(pdata->ftdic, 0, BITMODE_RESET) < 0, pdata->ftdic);
|
E(ftdi_set_bitmode(pdata->ftdic, 0, BITMODE_RESET) < 0, pdata->ftdic);
|
||||||
E(ftdi_set_bitmode(pdata->ftdic, pdata->pin_direction & 0xff, BITMODE_MPSSE) < 0, pdata->ftdic);
|
E(ftdi_set_bitmode(pdata->ftdic, pdata->pin_direction & 0xff, BITMODE_MPSSE) < 0, pdata->ftdic);
|
||||||
E(ftdi_usb_purge_buffers(pdata->ftdic), pdata->ftdic);
|
E(ftdi_usb_purge_buffers(pdata->ftdic), pdata->ftdic);
|
||||||
|
|
||||||
|
/*
|
||||||
|
ret = ftdi_sync(pdata);
|
||||||
|
if(ret < 0)
|
||||||
|
return ret;
|
||||||
|
*/
|
||||||
|
write_flush(pdata);
|
||||||
|
|
||||||
if (pgm->baudrate) {
|
if (pgm->baudrate) {
|
||||||
set_frequency(pdata, pgm->baudrate);
|
set_frequency(pdata, pgm->baudrate);
|
||||||
} else if(pgm->bitclock) {
|
} else if(pgm->bitclock) {
|
||||||
|
@ -781,7 +832,6 @@ static int avrftdi_open(PROGRAMMER * pgm, char *port)
|
||||||
if (add_pin(pgm, PIN_AVR_MOSI)) return -1;
|
if (add_pin(pgm, PIN_AVR_MOSI)) return -1;
|
||||||
if (add_pin(pgm, PIN_AVR_RESET)) return -1;
|
if (add_pin(pgm, PIN_AVR_RESET)) return -1;
|
||||||
|
|
||||||
|
|
||||||
/* gather the rest of the pins */
|
/* gather the rest of the pins */
|
||||||
if (add_pins(pgm, PPI_AVR_VCC)) return -1;
|
if (add_pins(pgm, PPI_AVR_VCC)) return -1;
|
||||||
if (add_pins(pgm, PPI_AVR_BUFF)) return -1;
|
if (add_pins(pgm, PPI_AVR_BUFF)) return -1;
|
||||||
|
@ -829,6 +879,13 @@ static void avrftdi_close(PROGRAMMER * pgm)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int avrftdi_initialize(PROGRAMMER * pgm, AVRPART * p)
|
static int avrftdi_initialize(PROGRAMMER * pgm, AVRPART * p)
|
||||||
|
{
|
||||||
|
if(p->flags & AVRPART_HAS_TPI)
|
||||||
|
{
|
||||||
|
/* see avrftdi_tpi.c */
|
||||||
|
avrftdi_tpi_initialize(pgm, p);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
set_pin(pgm, PIN_AVR_RESET, OFF);
|
set_pin(pgm, PIN_AVR_RESET, OFF);
|
||||||
set_pins(pgm, PPI_AVR_BUFF, OFF);
|
set_pins(pgm, PPI_AVR_BUFF, OFF);
|
||||||
|
@ -845,6 +902,7 @@ static int avrftdi_initialize(PROGRAMMER * pgm, AVRPART * p)
|
||||||
set_pin(pgm, PIN_AVR_RESET, OFF);
|
set_pin(pgm, PIN_AVR_RESET, OFF);
|
||||||
/*wait at least 20ms bevor issuing spi commands to avr */
|
/*wait at least 20ms bevor issuing spi commands to avr */
|
||||||
usleep(20 * 1000);
|
usleep(20 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
return pgm->program_enable(pgm, p);
|
return pgm->program_enable(pgm, p);
|
||||||
}
|
}
|
||||||
|
@ -965,6 +1023,7 @@ static int avrftdi_eeprom_write(PROGRAMMER *pgm, AVRPART *p, AVRMEM *m,
|
||||||
avr_set_addr(m->op[AVR_OP_WRITE], &cmd[3], add);
|
avr_set_addr(m->op[AVR_OP_WRITE], &cmd[3], add);
|
||||||
avr_set_input(m->op[AVR_OP_WRITE], &cmd[3], *data++);
|
avr_set_input(m->op[AVR_OP_WRITE], &cmd[3], *data++);
|
||||||
|
|
||||||
|
//avrftdi_transmit(to_pdata(pgm), MPSSE_DO_WRITE, cmd, cmd, 4);
|
||||||
E(ftdi_write_data(to_pdata(pgm)->ftdic, cmd, sizeof(cmd)) != sizeof(cmd),
|
E(ftdi_write_data(to_pdata(pgm)->ftdic, cmd, sizeof(cmd)) != sizeof(cmd),
|
||||||
to_pdata(pgm)->ftdic);
|
to_pdata(pgm)->ftdic);
|
||||||
|
|
||||||
|
@ -1237,11 +1296,14 @@ avrftdi_setup(PROGRAMMER * pgm)
|
||||||
pdata->pin_value = 0;
|
pdata->pin_value = 0;
|
||||||
pdata->pin_direction = 0;
|
pdata->pin_direction = 0;
|
||||||
pdata->led_mask = 0;
|
pdata->led_mask = 0;
|
||||||
|
pdata->guard_bits = 128 + 2;
|
||||||
|
pdata->set_pin = &set_pin;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
avrftdi_teardown(PROGRAMMER * pgm)
|
avrftdi_teardown(PROGRAMMER * pgm)
|
||||||
{
|
{
|
||||||
|
fprintf(stderr, "\n%s: Unintializing programmer.\n", progname);
|
||||||
avrftdi_t* pdata = to_pdata(pgm);
|
avrftdi_t* pdata = to_pdata(pgm);
|
||||||
|
|
||||||
if(pdata) {
|
if(pdata) {
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
#pragma once
|
||||||
|
#include "ac_cfg.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBFTDI1
|
||||||
|
# include <libftdi1/ftdi.h>
|
||||||
|
#else
|
||||||
|
# error "libftdi1 required for avrftdi."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "pgm.h"
|
||||||
|
|
||||||
|
#define E(x, ftdi) \
|
||||||
|
do { \
|
||||||
|
if ((x)) \
|
||||||
|
{ \
|
||||||
|
fprintf(stderr, "%s:%d %s() %s: %s (%d)\n\t%s\n", \
|
||||||
|
__FILE__, __LINE__, __FUNCTION__, \
|
||||||
|
#x, strerror(errno), errno, ftdi_get_error_string(ftdi)); \
|
||||||
|
return -1; \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define E_VOID(x, ftdi) \
|
||||||
|
do { \
|
||||||
|
if ((x)) \
|
||||||
|
{ \
|
||||||
|
fprintf(stderr, "%s:%d %s() %s: %s (%d)\n\t%s\n", \
|
||||||
|
__FILE__, __LINE__, __FUNCTION__, \
|
||||||
|
#x, strerror(errno), errno, ftdi_get_error_string(ftdi)); \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
|
||||||
|
#define to_pdata(pgm) \
|
||||||
|
((avrftdi_t *)((pgm)->cookie))
|
||||||
|
|
||||||
|
typedef struct avrftdi_s {
|
||||||
|
/* pointer to struct maintained by libftdi to identify the device */
|
||||||
|
struct ftdi_context* ftdic;
|
||||||
|
/* bitmask of values for pins. bit 0 represents pin 0 ([A|B]DBUS0) */
|
||||||
|
uint16_t pin_value;
|
||||||
|
/* bitmask of pin direction. a '1' make a pin an output.
|
||||||
|
* bit 0 corresponds to pin 0. */
|
||||||
|
uint16_t pin_direction;
|
||||||
|
/* don't know. not useful. someone put it in. */
|
||||||
|
uint16_t led_mask;
|
||||||
|
/* total number of pins supported by a programmer. varies with FTDI chips */
|
||||||
|
int pin_limit;
|
||||||
|
/* internal RX buffer of the device. needed for INOUT transfers */
|
||||||
|
int rx_buffer_size;
|
||||||
|
/* number of guard bits for TPI. should be moved to struct PROGRAMMER */
|
||||||
|
int guard_bits;
|
||||||
|
/* function pointer to the set_pin function, so that we do not have to drag
|
||||||
|
* it into global scope. it's a hack, but i think it's slightly better than
|
||||||
|
* the alternative.
|
||||||
|
*/
|
||||||
|
int (*set_pin)(PROGRAMMER *, int, int);
|
||||||
|
} avrftdi_t;
|
||||||
|
|
||||||
|
void avrftdi_print(int level, const char * fmt, ...);
|
||||||
|
|
|
@ -0,0 +1,352 @@
|
||||||
|
#include "ac_cfg.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "pgm.h"
|
||||||
|
#include "avrpart.h"
|
||||||
|
#include "pindefs.h"
|
||||||
|
#include "tpi.h"
|
||||||
|
#include "usbasp.h"
|
||||||
|
|
||||||
|
#include "avrftdi_tpi.h"
|
||||||
|
#include "avrftdi_private.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBUSB_1_0
|
||||||
|
#ifdef HAVE_LIBFTDI1
|
||||||
|
|
||||||
|
#include <libusb-1.0/libusb.h>
|
||||||
|
#include <libftdi1/ftdi.h>
|
||||||
|
|
||||||
|
static void
|
||||||
|
avrftdi_debug_frame(uint16_t frame)
|
||||||
|
{
|
||||||
|
static char bit_name[] = "IDLES01234567PSS";
|
||||||
|
//static char bit_name[] = "SSP76543210SELDI";
|
||||||
|
char line0[34], line1[34], line2[34];
|
||||||
|
int bit, pos;
|
||||||
|
|
||||||
|
for(bit = 0; bit < 16; bit++)
|
||||||
|
{
|
||||||
|
pos = 16 - bit - 1;
|
||||||
|
if(frame & (1 << pos))
|
||||||
|
{
|
||||||
|
line0[2*pos] = '_';
|
||||||
|
line0[2*pos+1] = ' ';
|
||||||
|
|
||||||
|
line2[2*pos] = ' ';
|
||||||
|
line2[2*pos+1] = ' ';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
line0[2*pos] = ' ';
|
||||||
|
line0[2*pos+1] = ' ';
|
||||||
|
|
||||||
|
line2[2*pos] = '-';
|
||||||
|
line2[2*pos+1] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
line1[2*pos] = bit_name[pos];
|
||||||
|
line1[2*pos+1] = ' ';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
line0[32] = 0;
|
||||||
|
line1[32] = 0;
|
||||||
|
line2[32] = 0;
|
||||||
|
|
||||||
|
avrftdi_print(0, "%s\n", line0);
|
||||||
|
avrftdi_print(0, "%s\n", line1);
|
||||||
|
//avrftdi_print(0, "%s\n", line2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
avrftdi_tpi_initialize(PROGRAMMER * pgm, AVRPART * p)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
avrftdi_t* pdata = to_pdata(pgm);
|
||||||
|
unsigned char buf[] = { MPSSE_DO_WRITE | MPSSE_WRITE_NEG | MPSSE_LSB, 0x01, 0x00, 0xff, 0xff };
|
||||||
|
|
||||||
|
avrftdi_print(0, "Using TPI interface\n");
|
||||||
|
|
||||||
|
pgm->program_enable = avrftdi_tpi_program_enable;
|
||||||
|
pgm->cmd_tpi = avrftdi_cmd_tpi;
|
||||||
|
pgm->chip_erase = avrftdi_tpi_chip_erase;
|
||||||
|
//pgm->read_byte = avrftdi_tpi_read_byte;
|
||||||
|
//pgm->write_byte = avrftdi_tpi_write_byte;
|
||||||
|
|
||||||
|
avrftdi_print(0, "Setting /Reset pin low\n");
|
||||||
|
pdata->set_pin(pgm, PIN_AVR_RESET, OFF);
|
||||||
|
pdata->set_pin(pgm, PIN_AVR_SCK, OFF);
|
||||||
|
pdata->set_pin(pgm, PIN_AVR_MOSI, ON);
|
||||||
|
usleep(20 * 1000);
|
||||||
|
|
||||||
|
pdata->set_pin(pgm, PIN_AVR_RESET, ON);
|
||||||
|
/* worst case 128ms */
|
||||||
|
usleep(2 * 128 * 1000);
|
||||||
|
|
||||||
|
/*setting rst back to 0 */
|
||||||
|
pdata->set_pin(pgm, PIN_AVR_RESET, OFF);
|
||||||
|
/*wait at least 20ms bevor issuing spi commands to avr */
|
||||||
|
usleep(20 * 1000);
|
||||||
|
|
||||||
|
avrftdi_print(0, "Sending 16 init clock cycles ... ");
|
||||||
|
ret = ftdi_write_data(pdata->ftdic, buf, sizeof(buf));
|
||||||
|
avrftdi_print(0, "Done.\n");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TPI_BIT_PAR 0x2000
|
||||||
|
|
||||||
|
static uint16_t
|
||||||
|
tpi_byte2frame(uint8_t byte)
|
||||||
|
{
|
||||||
|
uint16_t frame = 0xc00f;
|
||||||
|
int parity = __builtin_popcount(byte) & 1;
|
||||||
|
|
||||||
|
frame |= ((byte << 5) & 0x1fe0);
|
||||||
|
|
||||||
|
if(parity)
|
||||||
|
frame |= TPI_BIT_PAR;
|
||||||
|
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
tpi_frame2byte(uint16_t frame, uint8_t * byte)
|
||||||
|
{
|
||||||
|
/* drop partity + 2 stop bits */
|
||||||
|
*byte = (frame >> 1) & 0xff;
|
||||||
|
|
||||||
|
int parity = __builtin_popcount(*byte) & 1;
|
||||||
|
int parity_rcvd = (frame & 0x200) ? 1 : 0;
|
||||||
|
|
||||||
|
avrftdi_print(1, "Recevied frame with payload 0x%02x and parity %d.\n", *byte, parity);
|
||||||
|
|
||||||
|
return parity != parity_rcvd;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TPI_FRAME_SIZE 2
|
||||||
|
|
||||||
|
static int
|
||||||
|
avrftdi_tpi_break(PROGRAMMER * pgm)
|
||||||
|
{
|
||||||
|
unsigned char buffer[] = { MPSSE_DO_WRITE | MPSSE_WRITE_NEG | MPSSE_LSB, 1, 0, 0x80, 0x01 };
|
||||||
|
E(ftdi_write_data(to_pdata(pgm)->ftdic, buffer, sizeof(buffer)) != sizeof(buffer), to_pdata(pgm)->ftdic);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
avrftdi_tpi_write_byte(PROGRAMMER * pgm, unsigned char byte)
|
||||||
|
{
|
||||||
|
uint16_t frame;
|
||||||
|
|
||||||
|
struct ftdi_context* ftdic = to_pdata(pgm)->ftdic;
|
||||||
|
|
||||||
|
unsigned char buffer[] = { MPSSE_DO_WRITE | MPSSE_WRITE_NEG | MPSSE_LSB, 1, 0, 0, 0 };
|
||||||
|
|
||||||
|
frame = tpi_byte2frame(byte);
|
||||||
|
|
||||||
|
buffer[3] = frame & 0xff;
|
||||||
|
buffer[4] = frame >> 8;
|
||||||
|
|
||||||
|
avrftdi_print(1, "TPI frame: 0x%02x 0x%02x, data byte 0x%02x\n",
|
||||||
|
buffer[6], buffer[7], byte);
|
||||||
|
avrftdi_print(2, "FTDI raw data: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
|
||||||
|
buffer[0], buffer[1], buffer[2], buffer[3], buffer[4] /*, buffer[5], buffer[6], buffer[7]*/);
|
||||||
|
|
||||||
|
avrftdi_debug_frame(frame);
|
||||||
|
|
||||||
|
E(ftdi_write_data(ftdic, buffer, sizeof(buffer)) != sizeof(buffer), ftdic);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
avrftdi_tpi_read_byte(PROGRAMMER * pgm, unsigned char * byte)
|
||||||
|
{
|
||||||
|
uint16_t frame;
|
||||||
|
|
||||||
|
int guard_bits = to_pdata(pgm)->guard_bits;
|
||||||
|
int bytes = ((guard_bits + 7) / 8) + 2;
|
||||||
|
int i = 0, n = 0;
|
||||||
|
|
||||||
|
/* worst case size:
|
||||||
|
* - 128 guard bits
|
||||||
|
* - 2 default idle bits
|
||||||
|
* - 12 frame bits
|
||||||
|
* = 142 bits
|
||||||
|
*/
|
||||||
|
unsigned char buffer[bytes];
|
||||||
|
|
||||||
|
if(bytes > sizeof(buffer))
|
||||||
|
avrftdi_print(0, "Requested more bytes (%d) than available buffer space (%d)\n", bytes, sizeof(buffer));
|
||||||
|
|
||||||
|
avrftdi_print(1, "Guard bit size (incl. default idle bits) is %d\n", guard_bits);
|
||||||
|
avrftdi_print(1, "Reading %d bytes for guard bits + frame\n", bytes);
|
||||||
|
|
||||||
|
/* set it high, so the PDI won't detect we're driving the line */
|
||||||
|
to_pdata(pgm)->set_pin(pgm, PIN_AVR_MOSI, ON);
|
||||||
|
|
||||||
|
buffer[0] = MPSSE_DO_READ | MPSSE_WRITE_NEG | MPSSE_LSB;
|
||||||
|
buffer[1] = (bytes-1) & 0xff;
|
||||||
|
buffer[2] = ((bytes-1) >> 8) & 0xff;
|
||||||
|
buffer[3] = SEND_IMMEDIATE;
|
||||||
|
|
||||||
|
avrftdi_print(3, "Read request: 0x%02x 0x%02x 0x%02x 0x%02x\n",
|
||||||
|
buffer[0], buffer[1], buffer[2], buffer[3]);
|
||||||
|
|
||||||
|
ftdi_write_data(to_pdata(pgm)->ftdic, buffer, 4);
|
||||||
|
|
||||||
|
memset(buffer, 0, sizeof(buffer));
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
do {
|
||||||
|
n = ftdi_read_data(to_pdata(pgm)->ftdic, &buffer[i], bytes - i);
|
||||||
|
E(n < 0, to_pdata(pgm)->ftdic);
|
||||||
|
i += n;
|
||||||
|
} while(i < bytes);
|
||||||
|
|
||||||
|
/* dismiss at least (guard_bits / 8) bytes */
|
||||||
|
i = guard_bits / 8;
|
||||||
|
frame = buffer[i] | (buffer[i+1] << 8);
|
||||||
|
|
||||||
|
/* now shift the rest of guard bits out */
|
||||||
|
i = guard_bits - (i*8);
|
||||||
|
frame >>= i;
|
||||||
|
|
||||||
|
avrftdi_print(1, "Received frame 0x%04x (LSB first)\n", frame);
|
||||||
|
|
||||||
|
return tpi_frame2byte(frame, byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
avrftdi_tpi_program_enable(PROGRAMMER * pgm, AVRPART * p)
|
||||||
|
{
|
||||||
|
int retry;
|
||||||
|
int err;
|
||||||
|
int i;
|
||||||
|
unsigned char byte = 0;
|
||||||
|
|
||||||
|
avrftdi_print(0, "TPI program enable\n");
|
||||||
|
|
||||||
|
//TODO determine guard time:
|
||||||
|
//-disable output possible -> guard time
|
||||||
|
//-else: minimum guard time
|
||||||
|
/* set guard time */
|
||||||
|
//avrftdi_tpi_write_byte(pgm, TPI_OP_SSTCS(TPIPCR));
|
||||||
|
//avrftdi_tpi_write_byte(pgm, TPIPCR_GT_2b);
|
||||||
|
|
||||||
|
/* send SKEY */
|
||||||
|
avrftdi_tpi_write_byte(pgm, TPI_CMD_SKEY);
|
||||||
|
for(i = sizeof(tpi_skey) - 1; i >= 0; --i)
|
||||||
|
avrftdi_tpi_write_byte(pgm, tpi_skey[i]);
|
||||||
|
|
||||||
|
/* check if device is ready */
|
||||||
|
for(retry = 0; retry < 10; retry++)
|
||||||
|
{
|
||||||
|
avrftdi_print(0, "Reading Identification register\n");
|
||||||
|
avrftdi_tpi_write_byte(pgm, TPI_OP_SLDCS(TPIIR));
|
||||||
|
err = avrftdi_tpi_read_byte(pgm, &byte);
|
||||||
|
if(err || byte != 0x80)
|
||||||
|
{
|
||||||
|
avrftdi_print(0, "Error. Sending break.\n");
|
||||||
|
avrftdi_tpi_break(pgm);
|
||||||
|
avrftdi_tpi_break(pgm);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
avrftdi_print(0, "Reading Status register\n");
|
||||||
|
avrftdi_tpi_write_byte(pgm, TPI_OP_SLDCS(TPISR));
|
||||||
|
err = avrftdi_tpi_read_byte(pgm, &byte);
|
||||||
|
if(err || !(byte & TPISR_NVMEN))
|
||||||
|
{
|
||||||
|
avrftdi_print(0, "Error. Sending break.\n");
|
||||||
|
avrftdi_tpi_break(pgm);
|
||||||
|
avrftdi_tpi_break(pgm);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
avrftdi_print(0, "error connecting to target\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
avrftdi_tpi_nvm_waitbusy(PROGRAMMER * pgm)
|
||||||
|
{
|
||||||
|
unsigned char byte;
|
||||||
|
int err;
|
||||||
|
int retry;
|
||||||
|
|
||||||
|
for(retry = 50; retry > 0; retry--)
|
||||||
|
{
|
||||||
|
avrftdi_tpi_write_byte(pgm, TPI_OP_SIN(NVMCSR));
|
||||||
|
err = avrftdi_tpi_read_byte(pgm, &byte);
|
||||||
|
if(err || (byte & NVMCSR_BSY))
|
||||||
|
continue;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
avrftdi_cmd_tpi(PROGRAMMER * pgm, unsigned char cmd[], int cmd_len,
|
||||||
|
unsigned char res[], int res_len)
|
||||||
|
{
|
||||||
|
int i, err = 0;
|
||||||
|
|
||||||
|
for(i = 0; i < cmd_len; i++)
|
||||||
|
{
|
||||||
|
err = avrftdi_tpi_write_byte(pgm, cmd[i]);
|
||||||
|
if(err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < res_len; i++)
|
||||||
|
{
|
||||||
|
err = avrftdi_tpi_read_byte(pgm, &res[i]);
|
||||||
|
if(err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
avrftdi_tpi_chip_erase(PROGRAMMER * pgm, AVRPART * p)
|
||||||
|
{
|
||||||
|
/* Set PR to flash */
|
||||||
|
avrftdi_tpi_write_byte(pgm, TPI_OP_SSTPR(0));
|
||||||
|
avrftdi_tpi_write_byte(pgm, 0x01);
|
||||||
|
avrftdi_tpi_write_byte(pgm, TPI_OP_SSTPR(1));
|
||||||
|
avrftdi_tpi_write_byte(pgm, 0x40);
|
||||||
|
/* select ERASE */
|
||||||
|
avrftdi_tpi_write_byte(pgm, TPI_OP_SOUT(NVMCMD));
|
||||||
|
avrftdi_tpi_write_byte(pgm, NVMCMD_CHIP_ERASE);
|
||||||
|
/* dummy write */
|
||||||
|
avrftdi_tpi_write_byte(pgm, TPI_OP_SST_INC);
|
||||||
|
avrftdi_tpi_write_byte(pgm, 0x00);
|
||||||
|
avrftdi_tpi_nvm_waitbusy(pgm);
|
||||||
|
|
||||||
|
usleep(p->chip_erase_delay);
|
||||||
|
pgm->initialize(pgm, p);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /*HAVE_LIBFTDI*/
|
||||||
|
#endif /* HAVE_LIBFTDI */
|
||||||
|
|
||||||
|
#else /*HAVE_LIBUSB*/
|
||||||
|
|
||||||
|
#endif /*HAVE_LIBUSB*/
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "pgm.h"
|
||||||
|
#include "avrpart.h"
|
||||||
|
|
||||||
|
//int avrftdi_tpi_write_byte(PROGRAMMER * pgm, unsigned char byte);
|
||||||
|
//int avrftdi_tpi_read_byte(PROGRAMMER * pgm, unsigned char * byte);
|
||||||
|
int avrftdi_tpi_program_enable(PROGRAMMER * pgm, AVRPART * p);
|
||||||
|
int avrftdi_tpi_chip_erase(PROGRAMMER * pgm, AVRPART * p);
|
||||||
|
int avrftdi_cmd_tpi(PROGRAMMER * pgm, unsigned char cmd[], int cmd_len,
|
||||||
|
unsigned char res[], int res_len);
|
||||||
|
int avrftdi_tpi_initialize(PROGRAMMER * pgm, AVRPART * p);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue