​With the attached patch (relative to GIT repository)​, I'm able to program
an ATtiny9 via TPI using a USBtiny programmer (such as SparkFun AVR Pocket
Programmer).
​
Example command:

 $ ./
avrdude -Cavrdude.conf -pt9 -cusbtiny -Uflash:w:/tmp/out.hex

​   --david​
--
eGauge Systems LLC, http://egauge.net/, 1.877-EGAUGE1, fax 720.545.9768
diff --git a/avrdude/usbtiny.c b/avrdude/usbtiny.c
index ff2597f..0329f2f 100644
--- a/avrdude/usbtiny.c
+++ b/avrdude/usbtiny.c
@@ -37,6 +37,7 @@
 #include "pgm.h"
 #include "config.h"
 #include "usbtiny.h"
+#include "tpi.h"
 
 #if defined(HAVE_LIBUSB)      // we use LIBUSB to talk to the board
 #if defined(HAVE_USB_H)
@@ -68,6 +69,9 @@ struct pdata
   int retries;
 };
 
+static int usbtiny_tpi_txtx(PROGRAMMER *, unsigned char, unsigned char);
+static int usbtiny_tpi_txrx(PROGRAMMER *, unsigned char);
+
 #define PDATA(pgm) ((struct pdata *)(pgm->cookie))
 
 // ----------------------------------------------------------------------
@@ -330,10 +334,28 @@ static int usbtiny_set_sck_period (PROGRAMMER *pgm, 
double v)
   return 0;
 }
 
+static unsigned char reverse(unsigned char b) {
+  return
+    (  (b & 0x01) << 7)
+    | ((b & 0x02) << 5)
+    | ((b & 0x04) << 3)
+    | ((b & 0x08) << 1)
+    | ((b & 0x10) >> 1)
+    | ((b & 0x20) >> 3)
+    | ((b & 0x40) >> 5)
+    | ((b & 0x80) >> 7);
+}
+
+/* Convert word from host byte order to big-endian byte-order,
+   little-endian bit order: */
+static unsigned short h2be(unsigned short w) {
+  return (w << 8) | (w >> 8);
+}
 
 static int usbtiny_initialize (PROGRAMMER *pgm, AVRPART *p )
 {
   unsigned char res[4];        // store the response from usbtinyisp
+  int tries;
 
   // Check for bit-clock and tell the usbtiny to adjust itself
   if (pgm->bitclock > 0.0) {
@@ -355,8 +377,36 @@ static int usbtiny_initialize (PROGRAMMER *pgm, AVRPART *p 
)
   // Let the device wake up.
   usleep(50000);
 
-  // Attempt to use the underlying avrdude methods to connect (MEME: is this 
kosher?)
-  if (! usbtiny_avr_op(pgm, p, AVR_OP_PGM_ENABLE, res)) {
+  if (p->flags & AVRPART_HAS_TPI) {
+    if (verbose >= 2)
+      fprintf(stderr, "doing MOSI-MISO link check\n");
+
+    memset(res, 0xaa, sizeof(res));
+    if (usb_in(pgm, USBTINY_SPI, h2be(0x1234), h2be(0x5678),
+              res, 4, 32 * PDATA(pgm)->sck_period)
+       < 0)
+    {
+      fprintf(stderr, "usb_in() failed\n");
+      return -1;
+    }
+    if (res[0] != 0x12 || res[1] != 0x34 || res[2] != 0x56 || res[3] != 0x78) {
+      fprintf(stderr, "MOSI->MISO check failed (got 0x%02x 0x%02x 0x%02x 
0x%02x)\n",
+             res[0], res[1], res[2], res[3]);
+      return -1;
+    }
+
+    /* keep TPIDATA high for >= 16 clock cycles: */
+    if (usb_in(pgm, USBTINY_SPI, 0xffff, 0xffff, res, 4, 32 * 
PDATA(pgm)->sck_period)
+       < 0)
+    {
+      fprintf(stderr, "Unable to switch chip into TPI mode\n");
+      return -1;
+    }
+  }
+
+  for (tries = 0; tries < 4; ++tries) {
+    if (pgm->program_enable(pgm, p) >= 0)
+      break;
     // no response, RESET and try again
     if (usb_control(pgm, USBTINY_POWERUP,
                    PDATA(pgm)->sck_period, RESET_HIGH) < 0 ||
@@ -364,11 +414,9 @@ static int usbtiny_initialize (PROGRAMMER *pgm, AVRPART *p 
)
                    PDATA(pgm)->sck_period, RESET_LOW) < 0)
       return -1;
     usleep(50000);
-    if ( ! usbtiny_avr_op( pgm, p, AVR_OP_PGM_ENABLE, res)) {
-      // give up
-      return -1;
-    }
   }
+  if (tries >= 4)
+    return -1;
   return 0;
 }
 
@@ -407,11 +455,133 @@ static int usbtiny_cmd(PROGRAMMER * pgm, const unsigned 
char *cmd, unsigned char
          res[2] == cmd[1]);              // AVR's do a delayed-echo thing
 }
 
+static unsigned char parity(unsigned char b)
+{
+  /* calculate parity: */
+  unsigned char parity = 0;
+  int i;
+
+  for (i = 0; i < 8; ++i) {
+    if (b & 1)
+      parity ^= 1;
+    b >>= 1;
+  }
+  return parity;
+}
+
+static int usbtiny_tpi_tx(PROGRAMMER *pgm, unsigned char b0)
+{
+  unsigned char res[4];
+  int nbytes;
+
+  /* Encode 1 start bit (0), 8 data bits, 1 parity, 2 stop bits (1)
+   inside 32 bits.  For easy debugging, start bit is the last bit of
+   the first byte, followed by the rest.  */
+
+  nbytes = usb_in(pgm, USBTINY_SPI,
+                 h2be(0xf000 | (reverse(b0) << 3) | parity(b0) << 2 | 0x3),
+                 0xffff,
+                 res, sizeof(res), 8 * sizeof(res) * PDATA(pgm)->sck_period);
+  if (nbytes < 0)
+    return -1;
+  if (verbose > 1)
+    fprintf(stderr, "CMD_TPI_TX: [0x%02x]\n", b0);
+  return 1;
+}
+
+static int usbtiny_tpi_txtx(PROGRAMMER *pgm, unsigned char b0, unsigned char 
b1)
+{
+  unsigned char res[4];
+  int nbytes;
+
+  /* Encode 1 start bit (0), 8 data bits, 1 parity, 2 stop bits (1)
+   inside 32 bits.  For easy debugging, start bit is the last bit of
+   the first byte, followed by the rest.  */
+
+  nbytes = usb_in(pgm, USBTINY_SPI,
+                 h2be(0xf000 | (reverse(b0) << 3) | parity(b0) << 2 | 0x3),
+                 h2be(0xf000 | (reverse(b1) << 3) | parity(b1) << 2 | 0x3),
+                 res, sizeof(res), 8 * sizeof(res) * PDATA(pgm)->sck_period);
+  if (nbytes < 0)
+    return -1;
+  if (verbose > 1)
+    fprintf(stderr, "CMD_TPI_TX_TX: [0x%02x 0x%02x]\n", b0, b1);
+  return 1;
+}
+
+static int usbtiny_tpi_txrx(PROGRAMMER *pgm, unsigned char b0)
+{
+  unsigned char res[4], r;
+  int nbytes;
+  short w;
+
+  /* Encode 1 start bit (0), 8 data bits, 1 parity, 2 stop bits (1)
+   inside 32 bits.  For easy debugging, start bit is the last bit of
+   the first byte, followed by the rest.  */
+
+  nbytes = usb_in(pgm, USBTINY_SPI,
+                 h2be(0xf000 | (reverse(b0) << 3) | parity(b0) << 2 | 0x3),
+                 0xffff,
+                 res, sizeof(res), 8 * sizeof(res) * PDATA(pgm)->sck_period);
+  if (nbytes < 0)
+    return -1;
+
+  w = (res[2] << 8) | res[3];
+  /* Look for start bit (there shoule be no more than two 1 bits): */
+  while (w < 0)
+    w <<= 1;
+  /* Now that we found the start bit, the top 9 bits contain the start
+     bit and the 8 data bits, but the latter in reverse order.  */
+  r = reverse(w >> 7);
+
+  if (verbose > 1)
+    fprintf(stderr, "CMD_TPI_TX_RX: [0x%02x -> 0x%02x]\n", b0, r);
+  return r;
+}
+
+int usbtiny_cmd_tpi(PROGRAMMER * pgm, const unsigned char *cmd,
+                       int cmd_len, unsigned char *res, int res_len)
+{
+  unsigned char b0, b1;
+  int r = -1, tx, rx;
+
+  for (tx = rx = 0; tx < cmd_len; ) {
+    b0 = cmd[tx++];
+    if (tx < cmd_len) {
+      b1 = cmd[tx++];
+      if ((r = usbtiny_tpi_txtx(pgm, b0, b1)) < 0)
+       return -1;
+    } else {
+      if (res_len > 0) {
+       if ((r = usbtiny_tpi_txrx(pgm, b0)) < 0)
+         return -1;
+       res[rx++] = r;
+      } else {
+       if ((r = usbtiny_tpi_tx(pgm, b0)) < 0)
+         return -1;
+      }
+    }
+  }
+
+  if (rx < res_len) {
+    fprintf(stderr, "%s: unexpected cmd_len=%d/res_len=%d\n",
+           __func__, cmd_len, res_len);
+    return -1;
+  }
+
+  if (r == -1)
+    return -1;
+  return 0;
+}
+
 /* Send the chip-erase command */
 static int usbtiny_chip_erase(PROGRAMMER * pgm, AVRPART * p)
 {
   unsigned char res[4];
 
+  if (p->flags & AVRPART_HAS_TPI)
+    return avr_tpi_chip_erase(pgm, p);
+
   if (p->op[AVR_OP_CHIP_ERASE] == NULL) {
     fprintf(stderr, "Chip erase instruction not defined for part \"%s\"\n",
             p->desc);
@@ -542,6 +712,16 @@ static int usbtiny_paged_write(PROGRAMMER * pgm, AVRPART * 
p, AVRMEM * m,
   return n_bytes;
 }
 
+static int usbtiny_program_enable(PROGRAMMER *pgm, AVRPART *p)
+{
+  unsigned char buf[4];
+
+  if (p->flags & AVRPART_HAS_TPI)
+    return avr_tpi_program_enable(pgm, p, 0x07);
+  else
+    return usbtiny_avr_op(pgm, p, AVR_OP_PGM_ENABLE, buf);
+}
+
 void usbtiny_initpgm ( PROGRAMMER* pgm )
 {
   strcpy(pgm->type, "USBtiny");
@@ -550,9 +730,10 @@ void usbtiny_initpgm ( PROGRAMMER* pgm )
   pgm->initialize      = usbtiny_initialize;
   pgm->enable          = usbtiny_enable;
   pgm->disable         = usbtiny_disable;
-  pgm->program_enable  = NULL;
+  pgm->program_enable  = usbtiny_program_enable;
   pgm->chip_erase      = usbtiny_chip_erase;
   pgm->cmd             = usbtiny_cmd;
+  pgm->cmd_tpi         = usbtiny_cmd_tpi;
   pgm->open            = usbtiny_open;
   pgm->close           = usbtiny_close;
   pgm->read_byte        = avr_read_byte_default;
_______________________________________________
avrdude-dev mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/avrdude-dev

Reply via email to