Add support for ATmega168p CPU
[pub/USBasp.git] / firmware / isp.c
index 6305aac..fa6c7be 100644 (file)
@@ -6,7 +6,7 @@
  *                  over ISP interface
  * Licence........: GNU GPL v2 (see Readme.txt)
  * Creation Date..: 2005-02-23
- * Last change....: 2009-02-28
+ * Last change....: 2010-01-19
  */
 
 #include <avr/io.h>
 #define spiHWdisable() SPCR = 0
 
 uchar sck_sw_delay;
+uchar sck_sw_delay_loops;
 uchar sck_spcr;
 uchar sck_spsr;
+uchar isp_hiaddr;
 
 void spiHWenable() {
        SPCR = sck_spcr;
@@ -30,66 +32,102 @@ void ispSetSCKOption(uchar option) {
        if (option == USBASP_ISP_SCK_AUTO)
                option = USBASP_ISP_SCK_375;
 
-       if (option >= USBASP_ISP_SCK_93_75) {
+       if (((F_CPU <= 12000000) && (option >= USBASP_ISP_SCK_93_75))
+        || ((F_CPU > 12000000) && (option >= USBASP_ISP_SCK_187_5))) {
                ispTransmit = ispTransmit_hw;
                sck_spsr = 0;
+               sck_sw_delay = 1;       /* force RST#/SCK pulse for 320us */
+               sck_sw_delay_loops = 1;
 
                switch (option) {
 
                case USBASP_ISP_SCK_1500:
-                       /* enable SPI, master, 1.5MHz, XTAL/8 */
-                       sck_spcr = (1 << SPE) | (1 << MSTR) | (1 << SPR0);
-                       sck_spsr = (1 << SPI2X);
+#                      if (F_CPU <= 12000000)
+                               /* enable SPI, master, 1.5MHz, XTAL/8 */
+                               sck_spcr = (1 << SPE) | (1 << MSTR) | (1 << SPR0);
+                               sck_spsr = (1 << SPI2X);
+#                      else
+                               /* enable SPI, master, ~1.1MHz, XTAL/16 */
+                               sck_spcr = (1 << SPE) | (1 << MSTR) | (1 << SPR0);
+#                      endif
+                       break;
                case USBASP_ISP_SCK_750:
-                       /* enable SPI, master, 750kHz, XTAL/16 */
-                       sck_spcr = (1 << SPE) | (1 << MSTR) | (1 << SPR0);
+#                      if (F_CPU <= 12000000)
+                               /* enable SPI, master, 750kHz, XTAL/16 */
+                               sck_spcr = (1 << SPE) | (1 << MSTR) | (1 << SPR0);
+#                      else
+                               /* enable SPI, master, ~531kHz, XTAL/32 */
+                               sck_spcr = (1 << SPE) | (1 << MSTR) | (1 << SPR1);
+                               sck_spsr = (1 << SPI2X);
+#                      endif
                        break;
                case USBASP_ISP_SCK_375:
                default:
-                       /* enable SPI, master, 375kHz, XTAL/32 (default) */
-                       sck_spcr = (1 << SPE) | (1 << MSTR) | (1 << SPR1);
-                       sck_spsr = (1 << SPI2X);
+#                      if (F_CPU <= 12000000)
+                               /* enable SPI, master, 375kHz, XTAL/32 (default) */
+                               sck_spcr = (1 << SPE) | (1 << MSTR) | (1 << SPR1);
+                               sck_spsr = (1 << SPI2X);
+#                      else
+                               /* enable SPI, master, ~265.6kHz XTAL/64 (default) */
+                               sck_spcr = (1 << SPE) | (1 << MSTR) | (1 << SPR1);
+#                      endif
                        break;
                case USBASP_ISP_SCK_187_5:
-                       /* enable SPI, master, 187.5kHz XTAL/64 */
-                       sck_spcr = (1 << SPE) | (1 << MSTR) | (1 << SPR1);
-                       break;
-               case USBASP_ISP_SCK_93_75:
-                       /* enable SPI, master, 93.75kHz XTAL/128 */
-                       sck_spcr = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0);
+#                      if (F_CPU <= 12000000)
+                               /* enable SPI, master, 187.5kHz XTAL/64 */
+                               sck_spcr = (1 << SPE) | (1 << MSTR) | (1 << SPR1);
+#                      else
+                               /* enable SPI, master, ~132.81kHz XTAL/128 */
+                               sck_spcr = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0);
+#                      endif
                        break;
+#              if (F_CPU <= 12000000)
+                       case USBASP_ISP_SCK_93_75:
+                               /* enable SPI, master, 93.75kHz XTAL/128 */
+                               sck_spcr = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0);
+                               break;
+#              endif
                }
 
        } else {
                ispTransmit = ispTransmit_sw;
+               sck_sw_delay_loops = 1;
+
                switch (option) {
 
+#              if (F_CPU > 12000000)
+                       case USBASP_ISP_SCK_93_75:
+                       sck_sw_delay = 2;
+
+                       break;
+#              endif
                case USBASP_ISP_SCK_32:
-                       sck_sw_delay = 3;
+                       sck_sw_delay = ((3 * (F_CPU/1000000L) + 11) / 12);
 
                        break;
                case USBASP_ISP_SCK_16:
-                       sck_sw_delay = 6;
+                       sck_sw_delay = ((6 * (F_CPU/1000000L) + 11) / 12);
 
                        break;
                case USBASP_ISP_SCK_8:
-                       sck_sw_delay = 12;
+                       sck_sw_delay = ((12 * (F_CPU/1000000L) + 11) / 12);
 
                        break;
                case USBASP_ISP_SCK_4:
-                       sck_sw_delay = 24;
+                       sck_sw_delay = ((24 * (F_CPU/1000000L) + 11) / 12);
 
                        break;
                case USBASP_ISP_SCK_2:
-                       sck_sw_delay = 48;
+                       sck_sw_delay = ((48 * (F_CPU/1000000L) + 11) / 12);
 
                        break;
                case USBASP_ISP_SCK_1:
-                       sck_sw_delay = 96;
+                       sck_sw_delay = ((96 * (F_CPU/1000000L) + 11) / 12);
 
                        break;
                case USBASP_ISP_SCK_0_5:
-                       sck_sw_delay = 192;
+                       sck_sw_delay = ((96 * (F_CPU/1000000L) + 11) / 12);
+                       sck_sw_delay_loops = 2;
 
                        break;
                }
@@ -99,7 +137,11 @@ void ispSetSCKOption(uchar option) {
 void ispDelay() {
 
        uint8_t starttime = TIMERVALUE;
-       while ((uint8_t) (TIMERVALUE - starttime) < sck_sw_delay) {
+       uint8_t loops = sck_sw_delay_loops;
+
+       while (loops--) {
+               while ((uint8_t) (TIMERVALUE - starttime) < sck_sw_delay) {
+               }
        }
 }
 
@@ -122,6 +164,9 @@ void ispConnect() {
        if (ispTransmit == ispTransmit_hw) {
                spiHWenable();
        }
+
+       /* Initial extended address value */
+       isp_hiaddr = 0;
 }
 
 void ispDisconnect() {
@@ -190,10 +235,11 @@ uchar ispEnterProgrammingMode() {
 
                spiHWdisable();
 
-               /* pulse SCK */
-               ISP_OUT |= (1 << ISP_SCK); /* SCK high */
+               /* pulse RST */
                ispDelay();
-               ISP_OUT &= ~(1 << ISP_SCK); /* SCK low */
+               ISP_OUT |= (1 << ISP_RST); /* RST high */
+               ispDelay();
+               ISP_OUT &= ~(1 << ISP_RST); /* RST low */
                ispDelay();
 
                if (ispTransmit == ispTransmit_hw) {
@@ -205,7 +251,28 @@ uchar ispEnterProgrammingMode() {
        return 1; /* error: device dosn't answer */
 }
 
+static void ispUpdateExtended(unsigned long address)
+{
+       uchar curr_hiaddr;
+
+       curr_hiaddr = (address >> 17);
+
+       /* check if extended address byte is changed */
+       if(isp_hiaddr != curr_hiaddr)
+       {
+               isp_hiaddr = curr_hiaddr;
+               /* Load Extended Address byte */
+               ispTransmit(0x4D);
+               ispTransmit(0x00);
+               ispTransmit(isp_hiaddr);
+               ispTransmit(0x00);
+       }
+}
+
 uchar ispReadFlash(unsigned long address) {
+
+       ispUpdateExtended(address);
+
        ispTransmit(0x20 | ((address & 1) << 3));
        ispTransmit(address >> 9);
        ispTransmit(address >> 1);
@@ -220,6 +287,8 @@ uchar ispWriteFlash(unsigned long address, uchar data, uchar pollmode) {
         }
         */
 
+       ispUpdateExtended(address);
+
        ispTransmit(0x40 | ((address & 1) << 3));
        ispTransmit(address >> 9);
        ispTransmit(address >> 1);
@@ -253,6 +322,9 @@ uchar ispWriteFlash(unsigned long address, uchar data, uchar pollmode) {
 }
 
 uchar ispFlushPage(unsigned long address, uchar pollvalue) {
+
+       ispUpdateExtended(address);
+
        ispTransmit(0x4C);
        ispTransmit(address >> 9);
        ispTransmit(address >> 1);