Add support for ATmega168p CPU
[pub/USBasp.git] / firmware / main.c
index a01cfe8..a5d679f 100644 (file)
 /*
-  USBasp - USB in-circuit programmer for Atmel AVR controllers
-
-  Thomas Fischl <tfischl@gmx.de>
-
-  License:
-  The project is built with AVR USB driver by Objective Development, which is
-  published under an own licence based on the GNU General Public License (GPL).
-  USBasp is also distributed under this enhanced licence. See Documentation.
-
-  Target.........: ATMega8 at 12 MHz
-  Creation Date..: 2005-02-20
-  Last change....: 2005-10-08
-
-  PC2 SCK speed option. GND  -> slow (8khz SCK),
-                        open -> fast (375kHz SCK)
-*/
+ * USBasp - USB in-circuit programmer for Atmel AVR controllers
+ *
+ * Thomas Fischl <tfischl@gmx.de>
+ *
+ * License........: GNU GPL v2 (see Readme.txt)
+ * Target.........: ATMega8 at 12 MHz
+ * Creation Date..: 2005-02-20
+ * Last change....: 2009-02-28
+ *
+ * PC2 SCK speed option.
+ * GND  -> slow (8khz SCK),
+ * open -> software set speed (default is 375kHz SCK)
+ */
 
 #include <avr/io.h>
-#include <avr/signal.h>
 #include <avr/interrupt.h>
 #include <avr/pgmspace.h>
 #include <avr/wdt.h>
 
+#include "usbasp.h"
 #include "usbdrv.h"
 #include "isp.h"
 #include "clock.h"
-
-#define USBASP_FUNC_CONNECT     1
-#define USBASP_FUNC_DISCONNECT  2
-#define USBASP_FUNC_TRANSMIT    3
-#define USBASP_FUNC_READFLASH   4
-#define USBASP_FUNC_ENABLEPROG  5
-#define USBASP_FUNC_WRITEFLASH  6
-#define USBASP_FUNC_READEEPROM  7
-#define USBASP_FUNC_WRITEEEPROM 8
-
-#define PROG_STATE_IDLE         0
-#define PROG_STATE_WRITEFLASH   1
-#define PROG_STATE_READFLASH    2
-#define PROG_STATE_READEEPROM   3
-#define PROG_STATE_WRITEEEPROM  4
-
-#define PROG_BLOCKFLAG_FIRST    1
-#define PROG_BLOCKFLAG_LAST     2
-
-#define ledRedOn()    PORTC &= ~(1 << PC1)
-#define ledRedOff()   PORTC |= (1 << PC1)
-#define ledGreenOn()  PORTC &= ~(1 << PC0)
-#define ledGreenOff() PORTC |= (1 << PC0)
+#include "tpi.h"
+#include "tpi_defs.h"
 
 static uchar replyBuffer[8];
 
 static uchar prog_state = PROG_STATE_IDLE;
+static uchar prog_sck = USBASP_ISP_SCK_AUTO;
 
-static unsigned int prog_address;
+static uchar prog_address_newmode = 0;
+static unsigned long prog_address;
 static unsigned int prog_nbytes = 0;
-static unsigned int prog_pagesize; //TP: Mega128 fix
+static unsigned int prog_pagesize;
 static uchar prog_blockflags;
 static uchar prog_pagecounter;
 
-
 uchar usbFunctionSetup(uchar data[8]) {
 
-  uchar len = 0;
-
-  if(data[1] == USBASP_FUNC_CONNECT){
-
-    /* set SCK speed */
-    if ((PINC & (1 << PC2)) == 0) {
-      ispSetSCKOption(ISP_SCK_SLOW);
-    } else {
-      ispSetSCKOption(ISP_SCK_FAST);
-    }
-
-    ispConnect();
-    ledRedOn();
-
-  } else if (data[1] == USBASP_FUNC_DISCONNECT) {
-    ispDisconnect();
-    ledRedOff();
-
-  } else if (data[1] == USBASP_FUNC_TRANSMIT) {
-    replyBuffer[0] = ispTransmit(data[2]);
-    replyBuffer[1] = ispTransmit(data[3]);
-    replyBuffer[2] = ispTransmit(data[4]);
-    replyBuffer[3] = ispTransmit(data[5]);
-    len = 4;
-
-  } else if (data[1] == USBASP_FUNC_READFLASH) {
-    prog_address = (data[3] << 8) | data[2];
-    prog_nbytes = (data[7] << 8) | data[6];
-    prog_state = PROG_STATE_READFLASH;
-    len = 0xff; /* multiple in */
-
-  } else if (data[1] == USBASP_FUNC_READEEPROM) {
-    prog_address = (data[3] << 8) | data[2];
-    prog_nbytes = (data[7] << 8) | data[6];
-    prog_state = PROG_STATE_READEEPROM;
-    len = 0xff; /* multiple in */
-
-  } else if (data[1] == USBASP_FUNC_ENABLEPROG) {
-    replyBuffer[0] = ispEnterProgrammingMode();;
-    len = 1;
-
-  } else if (data[1] == USBASP_FUNC_WRITEFLASH) {
-    prog_address = (data[3] << 8) | data[2];
-    prog_pagesize = data[4];
-    prog_blockflags = data[5] & 0x0F;
-    prog_pagesize += (((unsigned int)data[5] & 0xF0)<<4); //TP: Mega128 fix
-    if (prog_blockflags & PROG_BLOCKFLAG_FIRST) {
-      prog_pagecounter = prog_pagesize;
-    }
-    prog_nbytes = (data[7] << 8) | data[6];
-    prog_state = PROG_STATE_WRITEFLASH;
-    len = 0xff; /* multiple out */
-
-  } else if (data[1] == USBASP_FUNC_WRITEEEPROM) {
-    prog_address = (data[3] << 8) | data[2];
-    prog_pagesize = 0;
-    prog_blockflags = 0;
-    prog_nbytes = (data[7] << 8) | data[6];
-    prog_state = PROG_STATE_WRITEEEPROM;
-    len = 0xff; /* multiple out */
-  }
-
-  usbMsgPtr = replyBuffer;
-
-  return len;
-}
+       uchar len = 0;
 
+       if (data[1] == USBASP_FUNC_CONNECT) {
 
-uchar usbFunctionRead(uchar *data, uchar len) {
+               /* set SCK speed */
+               if ((PINC & (1 << PC2)) == 0) {
+                       ispSetSCKOption(USBASP_ISP_SCK_8);
+               } else {
+                       ispSetSCKOption(prog_sck);
+               }
 
-  uchar i;
-
-  /* check if programmer is in correct read state */
-  if ((prog_state != PROG_STATE_READFLASH) &&
-      (prog_state != PROG_STATE_READEEPROM)) {
-    return 0xff;
-  }
-
-  /* fill packet */
-  for (i = 0; i < len; i++) {
-    if (prog_state == PROG_STATE_READFLASH) {
-      data[i] = ispReadFlash(prog_address);
-    } else {
-      data[i] = ispReadEEPROM(prog_address);
-    }
-    prog_address++;
-  }
-
-  /* last packet? */
-  if (len < 8) {
-    prog_state = PROG_STATE_IDLE;
-  }
-
-  return len;
-}
+               /* set compatibility mode of address delivering */
+               prog_address_newmode = 0;
 
+               ledRedOn();
+               ispConnect();
 
-uchar usbFunctionWrite(uchar *data, uchar len) {
+       } else if (data[1] == USBASP_FUNC_DISCONNECT) {
+               ispDisconnect();
+               ledRedOff();
+
+       } else if (data[1] == USBASP_FUNC_TRANSMIT) {
+               replyBuffer[0] = ispTransmit(data[2]);
+               replyBuffer[1] = ispTransmit(data[3]);
+               replyBuffer[2] = ispTransmit(data[4]);
+               replyBuffer[3] = ispTransmit(data[5]);
+               len = 4;
+
+       } else if (data[1] == USBASP_FUNC_READFLASH) {
+
+               if (!prog_address_newmode)
+                       prog_address = (data[3] << 8) | data[2];
+
+               prog_nbytes = (data[7] << 8) | data[6];
+               prog_state = PROG_STATE_READFLASH;
+               len = 0xff; /* multiple in */
+
+       } else if (data[1] == USBASP_FUNC_READEEPROM) {
+
+               if (!prog_address_newmode)
+                       prog_address = (data[3] << 8) | data[2];
+
+               prog_nbytes = (data[7] << 8) | data[6];
+               prog_state = PROG_STATE_READEEPROM;
+               len = 0xff; /* multiple in */
+
+       } else if (data[1] == USBASP_FUNC_ENABLEPROG) {
+               replyBuffer[0] = ispEnterProgrammingMode();
+               len = 1;
+
+       } else if (data[1] == USBASP_FUNC_WRITEFLASH) {
+
+               if (!prog_address_newmode)
+                       prog_address = (data[3] << 8) | data[2];
+
+               prog_pagesize = data[4];
+               prog_blockflags = data[5] & 0x0F;
+               prog_pagesize += (((unsigned int) data[5] & 0xF0) << 4);
+               if (prog_blockflags & PROG_BLOCKFLAG_FIRST) {
+                       prog_pagecounter = prog_pagesize;
+               }
+               prog_nbytes = (data[7] << 8) | data[6];
+               prog_state = PROG_STATE_WRITEFLASH;
+               len = 0xff; /* multiple out */
+
+       } else if (data[1] == USBASP_FUNC_WRITEEEPROM) {
+
+               if (!prog_address_newmode)
+                       prog_address = (data[3] << 8) | data[2];
+
+               prog_pagesize = 0;
+               prog_blockflags = 0;
+               prog_nbytes = (data[7] << 8) | data[6];
+               prog_state = PROG_STATE_WRITEEEPROM;
+               len = 0xff; /* multiple out */
+
+       } else if (data[1] == USBASP_FUNC_SETLONGADDRESS) {
+
+               /* set new mode of address delivering (ignore address delivered in commands) */
+               prog_address_newmode = 1;
+               /* set new address */
+               prog_address = *((unsigned long*) &data[2]);
+
+       } else if (data[1] == USBASP_FUNC_SETISPSCK) {
+
+               /* set sck option */
+               prog_sck = data[2];
+               replyBuffer[0] = 0;
+               len = 1;
+
+       } else if (data[1] == USBASP_FUNC_TPI_CONNECT) {
+               tpi_dly_cnt = data[2] | (data[3] << 8);
+
+               /* RST high */
+               ISP_OUT |= (1 << ISP_RST);
+               ISP_DDR |= (1 << ISP_RST);
+
+               clockWait(3);
+
+               /* RST low */
+               ISP_OUT &= ~(1 << ISP_RST);
+               ledRedOn();
 
-  uchar i;
+               clockWait(16);
+               tpi_init();
 
-  /* check if programmer is in correct write state */
-  if ((prog_state != PROG_STATE_WRITEFLASH) &&
-      (prog_state != PROG_STATE_WRITEEEPROM)) {
-    return 0xff;
-  }
+       } else if (data[1] == USBASP_FUNC_TPI_DISCONNECT) {
 
+               tpi_send_byte(TPI_OP_SSTCS(TPISR));
+               tpi_send_byte(0);
 
-  for (i = 0; i < len; i++) {
+               clockWait(10);
 
-    if (prog_state == PROG_STATE_WRITEFLASH) {
-      /* Flash */
+               /* pulse RST */
+               ISP_OUT |= (1 << ISP_RST);
+               clockWait(5);
+               ISP_OUT &= ~(1 << ISP_RST);
+               clockWait(5);
 
-      if (prog_pagesize == 0) {
-       /* not paged */
-       ispWriteFlash(prog_address, data[i], 1);
-      } else {
-       /* paged */
-       ispWriteFlash(prog_address, data[i], 0);
-       prog_pagecounter --;
-       if (prog_pagecounter == 0) {
-         ispFlushPage(prog_address, data[i]);
-         prog_pagecounter = prog_pagesize;
+               /* set all ISP pins inputs */
+               ISP_DDR &= ~((1 << ISP_RST) | (1 << ISP_SCK) | (1 << ISP_MOSI));
+               /* switch pullups off */
+               ISP_OUT &= ~((1 << ISP_RST) | (1 << ISP_SCK) | (1 << ISP_MOSI));
+
+               ledRedOff();
+
+       } else if (data[1] == USBASP_FUNC_TPI_RAWREAD) {
+               replyBuffer[0] = tpi_recv_byte();
+               len = 1;
+
+       } else if (data[1] == USBASP_FUNC_TPI_RAWWRITE) {
+               tpi_send_byte(data[2]);
+
+       } else if (data[1] == USBASP_FUNC_TPI_READBLOCK) {
+               prog_address = (data[3] << 8) | data[2];
+               prog_nbytes = (data[7] << 8) | data[6];
+               prog_state = PROG_STATE_TPI_READ;
+               len = 0xff; /* multiple in */
+
+       } else if (data[1] == USBASP_FUNC_TPI_WRITEBLOCK) {
+               prog_address = (data[3] << 8) | data[2];
+               prog_nbytes = (data[7] << 8) | data[6];
+               prog_state = PROG_STATE_TPI_WRITE;
+               len = 0xff; /* multiple out */
+
+       } else if (data[1] == USBASP_FUNC_GETCAPABILITIES) {
+               replyBuffer[0] = USBASP_CAP_0_TPI;
+               replyBuffer[1] = 0;
+               replyBuffer[2] = 0;
+               replyBuffer[3] = 0;
+               len = 4;
        }
-      }
 
-    } else {
-      /* EEPROM */
-      ispWriteEEPROM(prog_address, data[i]);
-    }
+       usbMsgPtr = replyBuffer;
+
+       return len;
+}
+
+uchar usbFunctionRead(uchar *data, uchar len) {
+
+       uchar i;
 
-    prog_nbytes --;
+       /* check if programmer is in correct read state */
+       if ((prog_state != PROG_STATE_READFLASH) && (prog_state
+                       != PROG_STATE_READEEPROM) && (prog_state != PROG_STATE_TPI_READ)) {
+               return 0xff;
+       }
 
-    if (prog_nbytes == 0) {
-      prog_state = PROG_STATE_IDLE;
-      if ((prog_blockflags & PROG_BLOCKFLAG_LAST) &&
-         (prog_pagecounter != prog_pagesize)) {
+       /* fill packet TPI mode */
+       if(prog_state == PROG_STATE_TPI_READ)
+       {
+               tpi_read_block(prog_address, data, len);
+               prog_address += len;
+               return len;
+       }
 
-       /* last block and page flush pending, so flush it now */
-       ispFlushPage(prog_address, data[i]);
-      }
-    }
+       /* fill packet ISP mode */
+       for (i = 0; i < len; i++) {
+               if (prog_state == PROG_STATE_READFLASH) {
+                       data[i] = ispReadFlash(prog_address);
+               } else {
+                       data[i] = ispReadEEPROM(prog_address);
+               }
+               prog_address++;
+       }
 
-    prog_address ++;
-  }
+       /* last packet? */
+       if (len < 8) {
+               prog_state = PROG_STATE_IDLE;
+       }
 
-  return 0;
+       return len;
 }
 
+uchar usbFunctionWrite(uchar *data, uchar len) {
+
+       uchar retVal = 0;
+       uchar i;
+
+       /* check if programmer is in correct write state */
+       if ((prog_state != PROG_STATE_WRITEFLASH) && (prog_state
+                       != PROG_STATE_WRITEEEPROM) && (prog_state != PROG_STATE_TPI_WRITE)) {
+               return 0xff;
+       }
+
+       if (prog_state == PROG_STATE_TPI_WRITE)
+       {
+               tpi_write_block(prog_address, data, len);
+               prog_address += len;
+               prog_nbytes -= len;
+               if(prog_nbytes <= 0)
+               {
+                       prog_state = PROG_STATE_IDLE;
+                       return 1;
+               }
+               return 0;
+       }
+
+       for (i = 0; i < len; i++) {
+
+               if (prog_state == PROG_STATE_WRITEFLASH) {
+                       /* Flash */
+
+                       if (prog_pagesize == 0) {
+                               /* not paged */
+                               ispWriteFlash(prog_address, data[i], 1);
+                       } else {
+                               /* paged */
+                               ispWriteFlash(prog_address, data[i], 0);
+                               prog_pagecounter--;
+                               if (prog_pagecounter == 0) {
+                                       ispFlushPage(prog_address, data[i]);
+                                       prog_pagecounter = prog_pagesize;
+                               }
+                       }
 
-int main(void)
-{
-  uchar   i, j;
+               } else {
+                       /* EEPROM */
+                       ispWriteEEPROM(prog_address, data[i]);
+               }
 
-  PORTD = 0;
-  PORTB = 0;           /* no pullups on USB and ISP pins */
-  DDRD = ~(1 << 2);    /* all outputs except PD2 = INT0 */
+               prog_nbytes--;
 
-  DDRB = ~0;            /* output SE0 for USB reset */
-  j = 0;
-  while(--j){           /* USB Reset by device only required on Watchdog Reset */
-      i = 0;
-      while(--i);       /* delay >10ms for USB reset */
-  }
-  DDRB = 0;             /* all USB and ISP pins inputs */
+               if (prog_nbytes == 0) {
+                       prog_state = PROG_STATE_IDLE;
+                       if ((prog_blockflags & PROG_BLOCKFLAG_LAST) && (prog_pagecounter
+                                       != prog_pagesize)) {
 
-  DDRC = 0x03;          /* all inputs except PC0, PC1 */
-  PORTC = 0xfe;
+                               /* last block and page flush pending, so flush it now */
+                               ispFlushPage(prog_address, data[i]);
+                       }
 
-  clockInit();          /* init timer */
+                       retVal = 1; // Need to return 1 when no more data is to be received
+               }
 
-  ispSetSCKOption(ISP_SCK_FAST);
+               prog_address++;
+       }
+
+       return retVal;
+}
+
+int main(void) {
+       uchar i, j;
+
+       /* no pullups on USB and ISP pins */
+       PORTD = 0;
+       PORTB = 0;
+       /* all outputs except PD2 = INT0 */
+       DDRD = ~(1 << 2);
+
+       /* output SE0 for USB reset */
+       DDRB = ~0;
+       j = 0;
+       /* USB Reset by device only required on Watchdog Reset */
+       while (--j) {
+               i = 0;
+               /* delay >10ms for USB reset */
+               while (--i)
+                       ;
+       }
+       /* all USB and ISP pins inputs */
+       DDRB = 0;
+
+       /* all inputs except PC0, PC1 */
+       DDRC = 0x03;
+       PORTC = 0xfe;
 
-  usbInit();
-  sei();
-  for(;;){             /* main event loop */
-    usbPoll();
-  }
-  return 0;
+       /* init timer */
+       clockInit();
+
+       /* main event loop */
+       usbInit();
+       sei();
+       for (;;) {
+               usbPoll();
+       }
+       return 0;
 }