USBasp/firmware/isp.c
Stefan Beller 4d0f5b8b15 Add the capability to read out a buffer at the USBasp.
This buffer should be filled by target device.
As the USBasp is slave at USB side, it should also be slave at
the SPI side, so it can handle the buffering well.
2012-05-20 16:41:43 +02:00

346 lines
6.4 KiB
C
Executable File

/*
* 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
uchar sck_sw_delay;
uchar sck_spcr;
uchar sck_spsr;
uchar isp_hiaddr;
void spiHWenable() {
SPCR = sck_spcr;
SPSR = sck_spsr;
}
void ispSetSCKOption(uchar option) {
if (option == USBASP_ISP_SCK_AUTO)
option = USBASP_ISP_SCK_375;
if (option >= USBASP_ISP_SCK_93_75) {
ispTransmit = ispTransmit_hw;
sck_spsr = 0;
sck_sw_delay = 1; /* force RST#/SCK pulse for 320us */
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);
case USBASP_ISP_SCK_750:
/* enable SPI, master, 750kHz, XTAL/16 */
sck_spcr = (1 << SPE) | (1 << MSTR) | (1 << SPR0);
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);
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);
break;
}
} else {
ispTransmit = ispTransmit_sw;
switch (option) {
case USBASP_ISP_SCK_32:
sck_sw_delay = 3;
break;
case USBASP_ISP_SCK_16:
sck_sw_delay = 6;
break;
case USBASP_ISP_SCK_8:
sck_sw_delay = 12;
break;
case USBASP_ISP_SCK_4:
sck_sw_delay = 24;
break;
case USBASP_ISP_SCK_2:
sck_sw_delay = 48;
break;
case USBASP_ISP_SCK_1:
sck_sw_delay = 96;
break;
case USBASP_ISP_SCK_0_5:
sck_sw_delay = 192;
break;
}
}
}
void ispDelay() {
uint8_t starttime = TIMERVALUE;
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);
/* 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 */
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));
/* disable hardware SPI */
spiHWdisable();
}
void spiInit() {
/* Set MISO output, all others input */
ISP_DDR = (1 << ISP_MISO);
/* Pull up SS' */
ISP_OUT = (1 << ISP_RST);
/* Enable SPI, slave mode */
SPCR = (1 << SPE | 1<< SPIE);
}
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 ispTransmit_hw(uchar send_byte) {
SPDR = send_byte;
while (!(SPSR & (1 << SPIF)))
;
return SPDR;
}
uchar ispEnterProgrammingMode() {
uchar check;
uchar count = 32;
while (count--) {
ispTransmit(0xAC);
ispTransmit(0x53);
check = ispTransmit(0);
ispTransmit(0);
if (check == 0x53) {
return 0;
}
spiHWdisable();
/* pulse RST */
ispDelay();
ISP_OUT |= (1 << ISP_RST); /* RST high */
ispDelay();
ISP_OUT &= ~(1 << ISP_RST); /* RST low */
ispDelay();
if (ispTransmit == ispTransmit_hw) {
spiHWenable();
}
}
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);
return ispTransmit(0);
}
uchar ispWriteFlash(unsigned long address, uchar data, uchar pollmode) {
/* 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);
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;
};
if ((uint8_t) (TIMERVALUE - starttime) > CLOCK_T_320us) {
starttime = TIMERVALUE;
retries--;
}
}
return 1; /* error */
}
}
uchar ispFlushPage(unsigned long address, uchar pollvalue) {
ispUpdateExtended(address);
ispTransmit(0x4C);
ispTransmit(address >> 9);
ispTransmit(address >> 1);
ispTransmit(0);
if (pollvalue == 0xFF) {
clockWait(15);
return 0;
} else {
/* polling flash */
uchar retries = 30;
uint8_t starttime = TIMERVALUE;
while (retries != 0) {
if (ispReadFlash(address) != 0xFF) {
return 0;
};
if ((uint8_t) (TIMERVALUE - starttime) > CLOCK_T_320us) {
starttime = TIMERVALUE;
retries--;
}
}
return 1; /* error */
}
}
uchar ispReadEEPROM(unsigned int address) {
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);
clockWait(30); // wait 9,6 ms
return 0;
}