X-Git-Url: http://git.linex4red.de/pub/USBasp.git/blobdiff_plain/1c9852b334371604476e95e9745978401941f056..4e5c8347645dbff6db701f227087e717e946b6fa:/firmware/isp.c diff --git a/firmware/isp.c b/firmware/isp.c index af928b488..fa6c7bef6 100644 --- a/firmware/isp.c +++ b/firmware/isp.c @@ -1,274 +1,376 @@ /* - isp.c - part of USB - - Autor..........: Thomas Fischl - Description....: Provides functions for communication/programming - over ISP interf - Licence........: Free under certain conditions. See Documentation. - Creation Date..: 2005-02-23 - Last change....: 2005-04-20 -*/ + * isp.c - part of USBasp + * + * Autor..........: Thomas Fischl + * 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 #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 int 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 int address, uchar data, uchar pollmode) { + ispUpdateExtended(address); - /* 0xFF is value after chip erase, so skip programming - if (data == 0xFF) { - return 0; - } - */ + ispTransmit(0x20 | ((address & 1) << 3)); + ispTransmit(address >> 9); + ispTransmit(address >> 1); + return ispTransmit(0); +} - ispTransmit(0x40 | ((address & 1) << 3)); - ispTransmit(address >> 9); - ispTransmit(address >> 1); - ispTransmit(data); +uchar ispWriteFlash(unsigned long address, uchar data, uchar pollmode) { - if (pollmode == 0) - return 0; + /* 0xFF is value after chip erase, so skip programming + if (data == 0xFF) { + return 0; + } + */ - if (data == 0x7F) { - clockWait(15); /* wait 4,8 ms */ - return 0; - } else { + ispUpdateExtended(address); - /* polling flash */ - uchar retries = 30; - uint8_t starttime = TIMERVALUE; - while (retries != 0) { - if (ispReadFlash(address) != 0x7F) { - return 0; - }; + ispTransmit(0x40 | ((address & 1) << 3)); + ispTransmit(address >> 9); + ispTransmit(address >> 1); + ispTransmit(data); - if ((uint8_t) (TIMERVALUE - starttime) > CLOCK_T_320us) { - starttime = TIMERVALUE; - retries --; - } + if (pollmode == 0) + return 0; - } - return 1; /* error */ - } + 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; + }; + + if ((uint8_t) (TIMERVALUE - starttime) > CLOCK_T_320us) { + starttime = TIMERVALUE; + retries--; + } + + } + return 1; /* error */ + } } +uchar ispFlushPage(unsigned long address, uchar pollvalue) { -uchar ispFlushPage(unsigned int address, uchar pollvalue) { - ispTransmit(0x4C); - ispTransmit(address >> 9); - ispTransmit(address >> 1); - ispTransmit(0); + ispUpdateExtended(address); + ispTransmit(0x4C); + ispTransmit(address >> 9); + ispTransmit(address >> 1); + ispTransmit(0); - if (pollvalue == 0xFF) { - clockWait(15); - return 0; - } else { + if (pollvalue == 0xFF) { + clockWait(15); + return 0; + } else { - /* polling flash */ - uchar retries = 30; - uint8_t starttime = TIMERVALUE; + /* polling flash */ + uchar retries = 30; + uint8_t starttime = TIMERVALUE; - while (retries != 0) { - if (ispReadFlash(address) != 0xFF) { - return 0; - }; + while (retries != 0) { + if (ispReadFlash(address) != 0xFF) { + return 0; + }; - if ((uint8_t) (TIMERVALUE - starttime) > CLOCK_T_320us) { - starttime = TIMERVALUE; - retries --; - } + if ((uint8_t) (TIMERVALUE - starttime) > CLOCK_T_320us) { + starttime = TIMERVALUE; + retries--; + } - } + } - return 1; /* error */ - } + return 1; /* error */ + } } - uchar ispReadEEPROM(unsigned int address) { - ispTransmit(0xA0); - ispTransmit(address >> 8); - ispTransmit(address); - return ispTransmit(0); + ispTransmit(0xA0); + ispTransmit(address >> 8); + ispTransmit(address); + return ispTransmit(0); } - uchar ispWriteEEPROM(unsigned int address, uchar data) { - ispTransmit(0xC0); - ispTransmit(address >> 8); - ispTransmit(address); - ispTransmit(data); + ispTransmit(0xC0); + ispTransmit(address >> 8); + ispTransmit(address); + ispTransmit(data); - clockWait(30); // wait 9,6 ms + clockWait(30); // wait 9,6 ms - 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; - - while (retries != 0) { - if (ispReadEEPROM(address) != 0xFF) { return 0; - }; - - if ((uint8_t) (TIMERVALUE - starttime) > CLOCK_T_320us) { - starttime = TIMERVALUE; - retries --; - } - - } - return 1; // error - } - */ - }