/*
- isp.c - part of USBasp
-
- Autor..........: Thomas Fischl <tfischl@gmx.de>
- Description....: Provides functions for communication/programming
- over ISP interface
- Licence........: GNU GPL v2 (see Readme.txt)
- Creation Date..: 2005-02-23
- Last change....: 2007-07-23
-*/
+ * isp.c - part of USBasp
+ *
+ * Autor..........: Thomas Fischl <tfischl@gmx.de>
+ * Description....: Provides functions for communication/programming
+ * over ISP interface
+ * Licence........: GNU GPL v2 (see Readme.txt)
+ * Creation Date..: 2005-02-23
+ * Last change....: 2010-01-19
+ */
#include <avr/io.h>
#include "isp.h"
#include "clock.h"
+#include "usbasp.h"
#define spiHWdisable() SPCR = 0
-void spiHWenable() {
+uchar sck_sw_delay;
+uchar sck_sw_delay_loops;
+uchar sck_spcr;
+uchar sck_spsr;
+uchar isp_hiaddr;
- /* enable SPI, master, 375kHz SCK */
- SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1);
- SPSR = (1 << SPI2X);
+void spiHWenable() {
+ SPCR = sck_spcr;
+ SPSR = sck_spsr;
}
void ispSetSCKOption(uchar option) {
- if (option == 0) {
-
- /* use software spi */
- ispTransmit = ispTransmit_sw;
- // spiHWdisable();
-
- } else {
-
- /* use hardware spi */
- ispTransmit = ispTransmit_hw;
-
- }
+ if (option == USBASP_ISP_SCK_AUTO)
+ option = USBASP_ISP_SCK_375;
+
+ 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:
+# 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:
+# 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:
+# 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:
+# 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 * (F_CPU/1000000L) + 11) / 12);
+
+ break;
+ case USBASP_ISP_SCK_16:
+ sck_sw_delay = ((6 * (F_CPU/1000000L) + 11) / 12);
+
+ break;
+ case USBASP_ISP_SCK_8:
+ sck_sw_delay = ((12 * (F_CPU/1000000L) + 11) / 12);
+
+ break;
+ case USBASP_ISP_SCK_4:
+ sck_sw_delay = ((24 * (F_CPU/1000000L) + 11) / 12);
+
+ break;
+ case USBASP_ISP_SCK_2:
+ sck_sw_delay = ((48 * (F_CPU/1000000L) + 11) / 12);
+
+ break;
+ case USBASP_ISP_SCK_1:
+ sck_sw_delay = ((96 * (F_CPU/1000000L) + 11) / 12);
+
+ break;
+ case USBASP_ISP_SCK_0_5:
+ sck_sw_delay = ((96 * (F_CPU/1000000L) + 11) / 12);
+ sck_sw_delay_loops = 2;
+
+ break;
+ }
+ }
}
void ispDelay() {
- uint8_t starttime = TIMERVALUE;
- while ((uint8_t) (TIMERVALUE - starttime) < 12) { }
+ uint8_t starttime = TIMERVALUE;
+ uint8_t loops = sck_sw_delay_loops;
+
+ while (loops--) {
+ while ((uint8_t) (TIMERVALUE - starttime) < sck_sw_delay) {
+ }
+ }
}
void ispConnect() {
- /* all ISP pins are inputs before */
- /* now set output pins */
- ISP_DDR |= (1 << ISP_RST) | (1 << ISP_SCK) | (1 << ISP_MOSI);
+ /* all ISP pins are inputs before */
+ /* now set output pins */
+ ISP_DDR |= (1 << ISP_RST) | (1 << ISP_SCK) | (1 << ISP_MOSI);
- /* reset device */
- ISP_OUT &= ~(1 << ISP_RST); /* RST low */
- ISP_OUT &= ~(1 << ISP_SCK); /* SCK low */
+ /* reset device */
+ ISP_OUT &= ~(1 << ISP_RST); /* RST low */
+ ISP_OUT &= ~(1 << ISP_SCK); /* SCK low */
- /* positive reset pulse > 2 SCK (target) */
- ispDelay();
- ISP_OUT |= (1 << ISP_RST); /* RST high */
- ispDelay();
- ISP_OUT &= ~(1 << ISP_RST); /* RST low */
+ /* positive reset pulse > 2 SCK (target) */
+ ispDelay();
+ ISP_OUT |= (1 << ISP_RST); /* RST high */
+ ispDelay();
+ ISP_OUT &= ~(1 << ISP_RST); /* RST low */
- if (ispTransmit == ispTransmit_hw) {
- spiHWenable();
- }
+ if (ispTransmit == ispTransmit_hw) {
+ spiHWenable();
+ }
+
+ /* Initial extended address value */
+ isp_hiaddr = 0;
}
void ispDisconnect() {
- /* 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));
+ /* 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));
- /* disable hardware SPI */
- spiHWdisable();
+ /* disable hardware SPI */
+ spiHWdisable();
}
uchar ispTransmit_sw(uchar send_byte) {
- uchar rec_byte = 0;
- uchar i;
- for (i = 0; i < 8; i++) {
-
- /* set MSB to MOSI-pin */
- if ((send_byte & 0x80) != 0) {
- ISP_OUT |= (1 << ISP_MOSI); /* MOSI high */
- } else {
- ISP_OUT &= ~(1 << ISP_MOSI); /* MOSI low */
- }
- /* shift to next bit */
- send_byte = send_byte << 1;
-
- /* receive data */
- rec_byte = rec_byte << 1;
- if ((ISP_IN & (1 << ISP_MISO)) != 0) {
- rec_byte++;
- }
-
- /* pulse SCK */
- ISP_OUT |= (1 << ISP_SCK); /* SCK high */
- ispDelay();
- ISP_OUT &= ~(1 << ISP_SCK); /* SCK low */
- ispDelay();
- }
-
- return rec_byte;
+ uchar rec_byte = 0;
+ uchar i;
+ for (i = 0; i < 8; i++) {
+
+ /* set MSB to MOSI-pin */
+ if ((send_byte & 0x80) != 0) {
+ ISP_OUT |= (1 << ISP_MOSI); /* MOSI high */
+ } else {
+ ISP_OUT &= ~(1 << ISP_MOSI); /* MOSI low */
+ }
+ /* shift to next bit */
+ send_byte = send_byte << 1;
+
+ /* receive data */
+ rec_byte = rec_byte << 1;
+ if ((ISP_IN & (1 << ISP_MISO)) != 0) {
+ rec_byte++;
+ }
+
+ /* pulse SCK */
+ ISP_OUT |= (1 << ISP_SCK); /* SCK high */
+ ispDelay();
+ ISP_OUT &= ~(1 << ISP_SCK); /* SCK low */
+ ispDelay();
+ }
+
+ return rec_byte;
}
uchar ispTransmit_hw(uchar send_byte) {
- SPDR = send_byte;
+ SPDR = send_byte;
- while (!(SPSR & (1 << SPIF)));
- return SPDR;
+ while (!(SPSR & (1 << SPIF)))
+ ;
+ return SPDR;
}
uchar ispEnterProgrammingMode() {
- uchar check;
- uchar count = 32;
+ uchar check;
+ uchar count = 32;
- while (count--) {
- ispTransmit(0xAC);
- ispTransmit(0x53);
- check = ispTransmit(0);
- ispTransmit(0);
+ while (count--) {
+ ispTransmit(0xAC);
+ ispTransmit(0x53);
+ check = ispTransmit(0);
+ ispTransmit(0);
- if (check == 0x53) {
- return 0;
- }
+ if (check == 0x53) {
+ return 0;
+ }
- spiHWdisable();
+ spiHWdisable();
- /* pulse SCK */
- ISP_OUT |= (1 << ISP_SCK); /* SCK high */
- ispDelay();
- ISP_OUT &= ~(1 << ISP_SCK); /* SCK low */
- ispDelay();
+ /* pulse RST */
+ ispDelay();
+ ISP_OUT |= (1 << ISP_RST); /* RST high */
+ ispDelay();
+ ISP_OUT &= ~(1 << ISP_RST); /* RST low */
+ ispDelay();
- if (ispTransmit == ispTransmit_hw) {
- spiHWenable();
- }
+ if (ispTransmit == ispTransmit_hw) {
+ spiHWenable();
+ }
- }
+ }
- return 1; /* error: device dosn't answer */
+ return 1; /* error: device dosn't answer */
}
-uchar ispReadFlash(unsigned long address) {
- ispTransmit(0x20 | ((address & 1) << 3));
- ispTransmit(address >> 9);
- ispTransmit(address >> 1);
- return ispTransmit(0);
+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) {
-uchar ispWriteFlash(unsigned long address, uchar data, uchar pollmode) {
+ ispUpdateExtended(address);
- /* 0xFF is value after chip erase, so skip programming
- if (data == 0xFF) {
- return 0;
- }
- */
-
- ispTransmit(0x40 | ((address & 1) << 3));
- ispTransmit(address >> 9);
- ispTransmit(address >> 1);
- ispTransmit(data);
-
- if (pollmode == 0)
- return 0;
-
- if (data == 0x7F) {
- clockWait(15); /* wait 4,8 ms */
- return 0;
- } else {
-
- /* polling flash */
- uchar retries = 30;
- uint8_t starttime = TIMERVALUE;
- while (retries != 0) {
- if (ispReadFlash(address) != 0x7F) {
- return 0;
- };
+ ispTransmit(0x20 | ((address & 1) << 3));
+ ispTransmit(address >> 9);
+ ispTransmit(address >> 1);
+ return ispTransmit(0);
+}
- if ((uint8_t) (TIMERVALUE - starttime) > CLOCK_T_320us) {
- starttime = TIMERVALUE;
- retries --;
- }
+uchar ispWriteFlash(unsigned long address, uchar data, uchar pollmode) {
- }
- return 1; /* error */
- }
+ /* 0xFF is value after chip erase, so skip programming
+ if (data == 0xFF) {
+ return 0;
+ }
+ */
-}
+ ispUpdateExtended(address);
+ ispTransmit(0x40 | ((address & 1) << 3));
+ ispTransmit(address >> 9);
+ ispTransmit(address >> 1);
+ ispTransmit(data);
-uchar ispFlushPage(unsigned long address, uchar pollvalue) {
- ispTransmit(0x4C);
- ispTransmit(address >> 9);
- ispTransmit(address >> 1);
- ispTransmit(0);
+ if (pollmode == 0)
+ return 0;
+ if (data == 0x7F) {
+ clockWait(15); /* wait 4,8 ms */
+ return 0;
+ } else {
- if (pollvalue == 0xFF) {
- clockWait(15);
- return 0;
- } else {
+ /* polling flash */
+ uchar retries = 30;
+ uint8_t starttime = TIMERVALUE;
+ while (retries != 0) {
+ if (ispReadFlash(address) != 0x7F) {
+ return 0;
+ };
- /* polling flash */
- uchar retries = 30;
- uint8_t starttime = TIMERVALUE;
+ if ((uint8_t) (TIMERVALUE - starttime) > CLOCK_T_320us) {
+ starttime = TIMERVALUE;
+ retries--;
+ }
- while (retries != 0) {
- if (ispReadFlash(address) != 0xFF) {
- return 0;
- };
+ }
+ return 1; /* error */
+ }
- if ((uint8_t) (TIMERVALUE - starttime) > CLOCK_T_320us) {
- starttime = TIMERVALUE;
- retries --;
- }
+}
- }
+uchar ispFlushPage(unsigned long address, uchar pollvalue) {
- return 1; /* error */
- }
+ ispUpdateExtended(address);
-}
+ ispTransmit(0x4C);
+ ispTransmit(address >> 9);
+ ispTransmit(address >> 1);
+ ispTransmit(0);
+ if (pollvalue == 0xFF) {
+ clockWait(15);
+ return 0;
+ } else {
-uchar ispReadEEPROM(unsigned int address) {
- ispTransmit(0xA0);
- ispTransmit(address >> 8);
- ispTransmit(address);
- return ispTransmit(0);
-}
+ /* polling flash */
+ uchar retries = 30;
+ uint8_t starttime = TIMERVALUE;
+ while (retries != 0) {
+ if (ispReadFlash(address) != 0xFF) {
+ return 0;
+ };
-uchar ispWriteEEPROM(unsigned int address, uchar data) {
+ if ((uint8_t) (TIMERVALUE - starttime) > CLOCK_T_320us) {
+ starttime = TIMERVALUE;
+ retries--;
+ }
- ispTransmit(0xC0);
- ispTransmit(address >> 8);
- ispTransmit(address);
- ispTransmit(data);
+ }
- clockWait(30); // wait 9,6 ms
+ return 1; /* error */
+ }
- return 0;
- /*
- if (data == 0xFF) {
- clockWait(30); // wait 9,6 ms
- return 0;
- } else {
+}
- // polling eeprom
- uchar retries = 30; // about 9,6 ms
- uint8_t starttime = TIMERVALUE;
+uchar ispReadEEPROM(unsigned int address) {
+ ispTransmit(0xA0);
+ ispTransmit(address >> 8);
+ ispTransmit(address);
+ return ispTransmit(0);
+}
- while (retries != 0) {
- if (ispReadEEPROM(address) != 0xFF) {
- return 0;
- };
+uchar ispWriteEEPROM(unsigned int address, uchar data) {
- if ((uint8_t) (TIMERVALUE - starttime) > CLOCK_T_320us) {
- starttime = TIMERVALUE;
- retries --;
- }
+ ispTransmit(0xC0);
+ ispTransmit(address >> 8);
+ ispTransmit(address);
+ ispTransmit(data);
- }
- return 1; // error
- }
- */
+ clockWait(30); // wait 9,6 ms
+ return 0;
}