/* SP12: A serial programmer for working with Atmel AVR uCs */ /* Copyright (C) 1997-2008 Ken Huntington, Kevin Towers, */ /* Artur Pundsack, Pitronics. */ /* This program is free software; you can redistribute it and/or */ /* modify it under the terms of the GNU General Public License */ /* as published by the Free Software Foundation; either version 2 */ /* of the License, or (at your option) any later version. */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, */ /* MA 02111-1307, USA. */ /* Pitronics can be reached by email: sbolt@xs4all.nl */ /* Kevin Towers can be reached by email: ktowers@omnexcontrols.com */ /* Ken Huntington can be reached by email: kenh@compmore.net */ /* Artur Pundsack can be reached by email: ap@pa-tec.de */ #ifndef _SP12_H #define _SP12_H #define WORDLEN 16 #define DATALEN 5 #define FLASH_DATAPTR 6 #define MAXLEN 500 #define FLASHBUF_UPPERLIMIT 1048576L #define EEPROMBUF_UPPERLIMIT 8192L #define FILE_ERROR "does not exist, wrong format,\n address > limit, or HEX file checksum failure." #define FILE_WRITE_ERROR "Unable to write to, or finish writing to" #define STK200TEST 0x02 /* data-1 connected to status-7 */ #define STK200PRESENT 0x80 #define STK300TEST 0x01 /* data-0 connected to status-5 */ #define STK300PRESENT 0x20 /* * program control line definitions for sp12 cable/dongle */ #define S_SCK 0x01 /* SPI clock out */ #define S_MOSI 0x80 /* SPI data out */ #define S_MISO_BITNR 7 /* SPI data in bit number */ #define S_MISO_INV 0xFF /* inverted */ #define S_RESET 0x02 /* processor reset control */ #define S_ENABLE 0 /* Dummy */ #define S_PORTPOWER 0x7C /* `port power' bits */ #define S_DEFAULT_EXIT_STATE 0 #define S_PORTACTIVE 0x7C /* reserved for portControl() */ /* * program control line definitions for Kanda STK200 dongle */ #define K_SCK 0x10 /* SPI clock out */ #define K_MOSI 0x20 /* SPI data out */ #define K_MISO_BITNR 6 /* SPI data in bit number */ #define K_MISO_INV 0x00 /* not inverted */ #define K_RESET 0x80 /* processor reset control */ #define K_ENABLE 0x0C /* ~enables Kanda `dongle' */ #define K_PORTPOWER 0 /* Dummy */ #define K_DEFAULT_EXIT_STATE 0x0C #define K_PORTACTIVE 0x43 /* * These macros perform various bit operations on scalar types using bit masks */ #define bit_set(value, bit) ((value) |= (bit)) #define bit_clear(value, bit) ((value) &= ~(bit)) #define bit_comp(value, bit) ((value) ^= (bit)) #define bit_test(value, bit) (((value) & (bit)) != 0) /*---------------------- The global constants -----------------------*/ /*----------------------- defined in init.c ------------------------*/ extern unsigned long PROGRAM_ENABLE; extern unsigned long CHIP_ERASE; extern unsigned long READ_DEVICE; extern unsigned long READ_PROG_LO; extern unsigned long READ_PROG_HI; extern unsigned long WRITE_PROG_LO; extern unsigned long WRITE_PROG_HI; extern unsigned long LOAD_PAGE_HI; extern unsigned long LOAD_PAGE_LO; extern unsigned long LOAD_EXT_ADDR; /* AP, 15.01.2008: Added */ extern unsigned long WRITE_PAGE; extern unsigned long READ_EEPROM; extern unsigned long WRITE_EEPROM; extern unsigned long POLL_RDY_BSY; extern unsigned long WRITE_LOCK_HM; extern unsigned long WRITE_LOCK_LM; extern unsigned long READ_LOCK; extern unsigned long WRITE_FUSES_HM; extern unsigned long WRITE_FUSES_LM; extern unsigned long READ_FUSES; extern unsigned long WRITE_HIGH_FUSES_HM; extern unsigned long WRITE_HIGH_FUSES_LM; extern unsigned long READ_HIGH_FUSES; extern unsigned long WRITE_EXTD_FUSES_HM; extern unsigned long WRITE_EXTD_FUSES_LM; extern unsigned long READ_EXTD_FUSES; extern unsigned long READ_CALIBRATION; extern char CALIB_MESSAGE[MAXLEN]; extern char LOCK_MESSAGE[MAXLEN]; extern char FUSES_MESSAGE[MAXLEN]; extern char H_FUSES_MESSAGE[MAXLEN]; extern char X_FUSES_MESSAGE[MAXLEN]; extern int POLL_RBLSB; extern int POLL_RBLEN; extern int W_LOCKLSB; extern int R_LOCKLSB; extern int W_LOCKLEN; extern int R_LOCKLEN; extern int W_FUSESLSB; extern int R_FUSESLSB; extern int W_FUSESLEN; extern int R_FUSESLEN; extern int WH_FUSESLSB; extern int RH_FUSESLSB; extern int WH_FUSESLEN; extern int RH_FUSESLEN; extern int WX_FUSESLSB; extern int RX_FUSESLSB; extern int WX_FUSESLEN; extern int RX_FUSESLEN; extern int CALIBLSB; extern int CALIBLEN; /*-------------------- No more global constants ---------------------*/ /*---------------------- The global variables -----------------------*/ /*----------------------- defined in init.c ------------------------*/ extern unsigned char SCK; extern unsigned char MOSI; extern unsigned char MISO_BITNR; extern unsigned char MISO_INV; extern unsigned char RESET; extern unsigned char ENABLE; extern unsigned char PORTPOWER; extern unsigned char DEFAULT_EXIT_STATE; extern unsigned char PORTACTIVE; struct timeConsts { double loop; double port; /* time taken by outportb() */ unsigned long sckLO; unsigned long sckHI; unsigned long resetPuls; unsigned programEnable; unsigned chipErase; unsigned long byteWrite; unsigned long byteWriteDefault; int byteWriteAdjusted; /* a flag */ unsigned long pageWrite; unsigned long pageWriteDefault; int pageWriteAdjusted; /* a flag */ unsigned powerOn; }; struct device_info { unsigned char sigByte_0; unsigned char sigByte_1; unsigned char sigByte_2; char name[30]; char madeBy[30]; long eepromLimit; long flashLimit; int initPerformed; int pageMode; /* true if page programmed device */ int pageSize; int fuseMode; /* 0: AT90S1200, 2313, 4414, 8515 */ /* 4: 2343 (lock +r, RCEN +rw) */ /* 5: 2323 4434, 8535 (lock +r, */ /* FSTRT +rw) */ /* 6: (ATmega103/603) */ /* 7: 2333, 4433 (lock +r, CKSELx3 +rw */ /* BODx2 +rw) */ }; struct logging { char logPath[MAXLEN]; int logging; int query; }; extern struct timeConsts timeConst; extern struct device_info device; extern struct logging logging; extern int portAddress; extern int portStatus; extern int writeRetries; extern float clockSpdDefault; extern int KandaMode; /* Cable/dongle Kanda or sp12 */ extern int ExtAddr; /* AP, 15.01.2008: Added, Marker for crossing */ /* the 64k Flash boundary */ extern unsigned char outbyte; /* current state of device */ /* control port */ /*-------------------- No more global variables ---------------------*/ /* * A few prototypes. */ /* Look for the rc file, using environment variable `SP12' (if */ /* this variable has not been set, the current directory is used). */ /* If the rc file exists, then read the time constants and the */ /* parallel port address from this file. If the rc file is not */ /* found, then calibrate the time constants, check for available */ /* parallel ports, set (usually the primary) address, and write */ /* it all into a new rc file. Afterwards check if the parallel */ /* port is actually there (guarding against a corrupt rc file, and */ /* setting the port data register to 0xF0), and also check if the */ /* time constants aren't 0. exit(1) if a check fails. */ /* Based on either the KANDA setting in _sp12rc or the name by */ /* which the program is called (sp12 or sp12.kanda), the */ /* parallel port pinout is adapted to the cable/dongles supplied */ /* with the Atmel/Kanda STK200/300 starter kits, or to the */ /* original SP12 cable and Ken Huntington's dongle. */ void initSp12(char *howWeAreCalled); /* Takes a devicecode (like 0392) or identifier ((-i)433) and sets */ /* the device commands, messages and other parameters as found in */ /* _sp12dev. */ /* Returns 1 if _sp12dev not found; 2 if a line in _sp12dev is */ /* corrupt; 3 if _sp12dev has no entry for the deviceCode or */ /* identifier and the deviceCode (as an int) if all is well. */ int setDevicePars(int initFlag, char *identifier); /* Collects all device codes and names from _sp12dev, and shows */ /* them on screen. */ /* Returns 1 if _sp12dev not found, else zero. */ int supported(void); /* Delay by executing loops, not so empty as to be caught by */ /* the compiler's optimization efforts. */ void loopDelay(unsigned long loops); /* Determines the number of bits in command, and shifts them */ /* highest bit first into unsigned char output, which then */ /* is used to clock them out bit by bit through Centronics */ /* data-7. */ /* Reads back and returns whatever the uC clocks out on Miso */ /* while the command is clocked in. */ /* Power bits prior state assumed on; left on at return. */ /* SCK prior state assumed lo; left lo at return. */ unsigned long clockOutCommand(unsigned long command); /* Accepts a 32-bit address, and shifts it highest bit first */ /* into unsigned char output, which then is used to clock the */ /* bits out one by one hrough Centronics data-7 */ /* Power bits prior state assumed on; left on at return. */ /* SCK prior state assumed lo; left lo at return. */ void clockOutAddress(unsigned long address); /* Read one data byte from the status register of the */ /* Centronics port. */ /* Power bits prior state assumed on; left on at return. */ /* SCK prior state assumed lo; left lo at return. */ unsigned char clockInByte(void); /* Accepts a 32-bit address. Reads the codeWord in two steps */ /* from the device connected to the Centronics port. */ /* Power bits prior state assumed on; left on at return. */ /* SCK prior state assumed lo; left lo at return. */ unsigned int readCodeWord(unsigned long address); /* Accepts a 16-bit codeWord and a 7-bit address. Writes the code */ /* in two steps with no delays into the ATMega device connected to */ /* the Centronics port. */ /* Power bits prior state assumed on; left on at return. */ /* SCK prior state assumed lo; left lo at return. */ void loadCodePage(unsigned long address, unsigned int codeWord); /* Accepts a 32-bit page number and programs it into the ATMega */ /* device connected to the Centronics parallel port. */ /* The page is read back and compared with the buffer; if all */ /* is well, 0 is returned, else 1. */ /* Power bits prior state assumed on; left on at return. */ /* SCK prior state assumed lo; left lo at return. */ int writeCodePage(unsigned int flashBuf[], unsigned long address); /* Accepts a 16-bit codeWord and a 16-bit address. Writes the code */ /* in two steps into the device connected to the Centronics port and */ /* verifies arrival. Returns 1 if verify fails three times, else 0. */ /* The time constant byteWrite is adjusted dynamically, */ /* if the device is not a 1200(A) and optimizeFlag allows. */ /* Power bits prior state assumed on; left on at return. */ /* SCK prior state assumed lo; left lo at return. */ /* AP, 15.01.2008: This function is only available for non page mode!*/ int writeFlashVerified(unsigned int address, unsigned int codeWord, int optimizeFlag); /* Expects flashBuf[] to be filled with data. */ /* If a (page) write fails, 1 is returned, else 0. */ /* Power bits prior state assumed on; left on at return. */ /* SCK prior state assumed lo; left lo at return. */ int writeFlashArea(unsigned int flashBuf[], long bufLimit, int optimizeFlag); /* Assume the device connected to the Centronics port is powered, */ /* but that device sck was not held low during power-up, so a */ /* reset pulse is needed before the SPI can be enabled. */ /* Assume also that power has yet to be switched on (for separate */ /* programmer powered by parallel port, instead of in-circuit */ /* programming. */ /* If uC is 1200, emit just one PROGRAM_ENABLE command. */ /* Else retry until the third byte read back by clockOutCommand() */ /* is 0x53, or at least 32 retries have been unsuccessful. */ int enableSPI(int uC); /* Adapt Sck timing to user's clock speed setting */ /* (Init sets the timing equal to sck0.5M, and the flag will be */ /* zero unless altered by the command line.) */ float setSckTiming(float clkSpeed); /* Before writing to the flash area, the device has to be erased. */ /* Note: This command also erases the eeprom area (all to 0xFF). */ /* There is no need for general erase before writing to the */ /* eeprom area, since the device has an auto-erase built into */ /* the eeprom write cycle. Thus you can alter one or more eeprom */ /* addresses without disturbing the rest of the device. */ void eraseDevice(void); /* A routine to switch off the powerbits; useful only when the */ /* separate programmer is used instead of in-circuit programming. */ void portControl(int portFlag, int exitFlag); /* Sends a lock or fuses string to the microcontroller. */ /* Returns 9 if the writeCommand is zero (not available according */ /* to _sp12dev). */ /* The lock or fuses string may represent a binary or hex number. */ /* If it's binary, the length of the string is compared with */ /* W_FUSESLEN; a useful sanity check. The function returns 2 if */ /* the length is wrong. A hex number is not checked, as there is no */ /* way to know how many leading zeroes are intended. */ /* Next, the block is ored into the writeCommand and uploaded to */ /* the device. */ /* Since (re)enabling brown-out detection usually causes the */ /* AT90(L)S2333/4433 to hang, the fuses are only written, not */ /* verified. */ int writeFuses(unsigned long commandHM, unsigned long commandLM, \ char *fuses, int WfusesLsb, int WfusesLen); /* Reads the lock or fuse bit block from the microcontroller. */ /* Returns 9 if the readCommand is zero (not available according */ /* to _sp12dev). */ int readFuses(unsigned long readCommand, char *fuses, \ int RfusesLsb, int RfusesLen); void readDeviceCode(void); /* Converts address or data string to number, automatically */ /* selecting hex (0xNNN), oct (0NNN), binary (BNNN) or */ /* dec (NNN) input. */ unsigned int str2num(char *addressOrData); /* convert unsigned int to a string-representation of the */ /* binary number (ascii `0' is 48, ascii `1' is 49) */ void num2bin(unsigned char buffer, char *binary); /* Reads program file in format address:data, stores data into */ /* flashBuf by address. The two numbers must be hex without `0x' */ /* for example: 00000c:99e1 */ int readFlashFile(char flashPath[], unsigned int flashBuf[], long bufLimit); /* Reads program file in Atmel generic format (address:data) or */ /* Intel HEX format; stores data into into flashBuf by address. */ /* flashBuf by address. The two numbers in the generic format are */ /* hex without `0x'. For example: 00000c:99e1 */ int readEepromFile(char eepromPath[], unsigned int eepromBuf[], long bufLimit); /* Calculate checksum over buffer[]; bufLimit is number of */ /* elements in buffer. */ unsigned int checksum(unsigned int buffer[], long bufLimit); /* (expects flashBuf[] to be filled with 0xFFFF) */ /* Loops readCodeWord into flashBuf[] */ /* Power bits prior state assumed on; left on at return. */ /* SCK prior state assumed lo; left lo at return. */ void readFlashArea(unsigned int flashBuf[], long bufLimit); /* Writes flashBuf[] into FILE *flashBufPtr; */ /* If write to file fails, return(1), else return(0) */ int fileFlashBuf(unsigned int flashBuf[], long bufLimit, char flashPath[], int intel_flag, int hex_ascii_flag); /* Reads flash and eeprom area's. Return 1 if a flash address does */ /* not contain 0xFFFF, or 3 if an eeprom address also isn't blank; */ /* return 2 if the flash is blank, but the eeprom isn't; */ /* return 0 is both area's are blank. */ /* Power bits prior state assumed on; left on at return. */ /* SCK prior state assumed lo; left lo at return. */ int blankCheck(long flashLimit, long eepromLimit); /* Accepts a dataByte and a 16-bit address. Writes the byte into */ /* the device connected to the Centronics port and verifies arrival. */ /* Returns 1 if verify fails three times, else 0. */ /* The time constant byteWrite is adjusted dynamically, */ /* if the device is not a 1200(A) and/or optimizeFlag allows. */ /* Power bits prior state assumed on; left on at return. */ /* SCK prior state assumed lo; left lo at return. */ int writeByteVerified(unsigned long writeCommand, unsigned long readCommand, int optimizeFlag); /* Writes eepromBuf[] into FILE *eepromBufPtr; */ /* If write to file fails, return(1), else return(0) */ int fileEepromBuf(unsigned int eepromBuf[], long bufLimit, char eepromPath[], int intel_flag, int hex_ascii_flag); /* Accepts a 16-bit address. Reads the dataByte in two steps */ /* from the device connected to the Centronics port. */ /* Power bits prior state assumed on; left on at return. */ /* SCK prior state assumed lo; left lo at return. */ unsigned char readDataByte(unsigned int address); /* Writes buffer[] to stdout as a hex dump with ascii translation */ void printBuffer(unsigned int buffer[], long bufLimit, int twoByteFlag); /* Add a line to the log about a write command */ int logWrites(char *commandStr, unsigned int address, int data, char *path, unsigned int buffer[], int overlayFlag, int *error); /* Add a line to the log about a lock command */ int logLocks(unsigned int buffer[], char *lockBits); /* Accepts a dataByte and a 16-bit address. Writes the code in two */ /* steps into the device connected to the Centronics port and */ /* verifies arrival. Returns 1 if verify fails three times, else 0. */ /* The time constant byteWrite is adjusted dynamically, */ /* if the device is not a 1200(A) and optimizeFlag allows. */ /* Power bits prior state assumed on; left on at return. */ /* SCK prior state assumed lo; left lo at return. */ int writeEepromVerified(unsigned int address, unsigned char dataByte, int optimizeFlag); /* Expects eepromBuf[] to be filled with data. */ /* executes writeEepromVerified() address by address; */ /* if verify fails, stops and returns 1, else returns 0. */ /* Power bits prior state assumed on; left on at return. */ /* SCK prior state assumed lo; left lo at return. */ int writeEepromArea(unsigned int eepromBuf[], long bufLimit, int optimizeFlag, int overlayFlag); /* (expects eepromBuf[] to be filled with 0xFF) */ /* Loops readDataByte into eepromBuf[] */ /* Power bits prior state assumed on; left on at return. */ /* SCK prior state assumed lo; left lo at return. */ void readEepromArea(unsigned int EepromBuf[], long bufLimit); #endif /* not _SP12_H */