/* * progAVR.c - algorithms to program the Atmel AVR family of microcontrollers * Copyright (C) 2009-2021 Alberto Maccioni * * 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 USA * or see */ #include "common.h" #define LOCK 1 #define FUSE 2 #define FUSE_H 4 #define FUSE_X 8 #define CAL 16 #define SLOW 256 #define RST 0x40 struct AVRID{ int id; char *device; } AVRLIST[]={ //1K {0x9001,"AT90S1200"}, {0x9004,"ATtiny11"}, {0x9005,"ATtiny12"}, {0x9007,"ATtiny13"}, //2K {0x9101,"AT90S2313"}, {0x9109,"ATtiny26"}, {0x910A,"ATtiny2313"}, {0x910B,"ATtiny24"}, {0x910C,"ATtiny261"}, //4K {0x9205,"ATmega48"}, {0x920A,"ATmega48PA"}, {0x9207,"ATtiny44"}, {0x9208,"ATtiny461"}, {0x9209,"ATtiny48"}, {0x920D,"ATtiny4313"}, //8K {0x9301,"AT90S8515"}, {0x9303,"AT90S8535"}, {0x9306,"ATmega8515"}, {0x9307,"ATmega8"}, {0x9308,"ATmega8535"}, {0x930A,"ATmega88"}, {0x930C,"ATtiny84"}, {0x930D,"ATtiny861"}, {0x930F,"ATmega88PA"}, {0x9311,"ATtiny88"}, //16K {0x9403,"ATmega16"}, {0x9406,"ATmega168"}, {0x940A,"ATmega164PA"}, {0x940B,"ATmega168PA"}, {0x940F,"ATmega164A"}, //32K {0x950F,"ATmega328P"}, {0x9511,"ATmega324PA"}, {0x9514,"ATmega328"}, {0x9515,"ATmega324A"}, //64K {0x9602,"ATmega64"}, {0x9609,"ATmega644A"}, {0x960A,"ATmega644PA"}, //128K {0x9705,"ATmega1284P"}, {0x9706,"ATmega1284"}, }; void AtmelID(BYTE id[]) { char str[128]=""; int i,idw=(id[1]<<8)+id[2]; if(id[0]==0&&id[1]==1&&id[2]==2){ PrintMessage(strings[S_Protected]); //"Device protected" return; } if(id[0]==0x1E) strcat(str,"Atmel "); for(i=0;i500){ //limit number of lines printed strcat(aux,"(...)\r\n"); i=(dim>8; bufferU[j++]=(int)(Tbit/2)&0xff; bufferU[j++]=SET_PORT_DIR; bufferU[j++]=0xF5; //TRISB bufferU[j++]=0x3F; //TRISA-C (RC7:RC6:RA5:RA4:RA3:X:X:X) for(i=0;i<4;i++){ //first nibble bufferU[j++]=EXT_PORT; bufferU[j++]=0; //PORTB CLK=0 bufferU[j++]=data&0x80; //PORTA-C bufferU[j++]=WAIT_T3; //half bit delay bufferU[j++]=EXT_PORT; bufferU[j++]=2; //PORTB CLK=1 bufferU[j++]=data&0x80; //PORTA-C bufferU[j++]=READ_B; bufferU[j++]=WAIT_T3; //half bit delay data<<=1; } bufferU[j++]=FLUSH; for(;j10) i++; if(i>20) i+=2; if(i>40) i+=4; if(i>80) i+=4; if(i>160) i+=8; Tbyte=(20+i*4)/1000.0; //from firmware simulation j=0; bufferU[j++]=CLOCK_GEN; //reset with clock at 0 bufferU[j++]=0xFF; bufferU[j++]=EN_VPP_VCC; //VDD=0 bufferU[j++]=0x0; bufferU[j++]=EXT_PORT; bufferU[j++]=0; bufferU[j++]=0; bufferU[j++]=WAIT_T3; bufferU[j++]=EN_VPP_VCC; //VDD bufferU[j++]=0x1; bufferU[j++]=WAIT_T3; bufferU[j++]=SET_PARAMETER; bufferU[j++]=SET_T1T2; bufferU[j++]=i; //force T bufferU[j++]=0; bufferU[j++]=EXT_PORT; bufferU[j++]=0; bufferU[j++]=RST; bufferU[j++]=WAIT_T3; bufferU[j++]=EXT_PORT; bufferU[j++]=0; bufferU[j++]=0; bufferU[j++]=CLOCK_GEN; bufferU[j++]=5; //0=100k,200k,500k,1M,2M,3M bufferU[j++]=FLUSH; for(;j256){ PrintMessage(strings[S_SyncErr]); //"Synchronization error\r\n" if(saveLog) fprintf(logfile,strings[S_SyncErr]); return 0; } //Add some margin i++; i+=i/10; if(i>255) i=255; Tbyte=(20+i*4)/1000.0; //from firmware simulation j=0; bufferU[j++]=SET_PARAMETER; bufferU[j++]=SET_T1T2; bufferU[j++]=i; //force T bufferU[j++]=0; bufferU[j++]=FLUSH; for(;j0x20000||dim<0){ PrintMessage(strings[S_CodeLim]); //"Code size out of limits\r\n" return; } if(dim2>0x1000||dim2<0){ PrintMessage(strings[S_EELim]); //"EEPROM size out of limits\r\n" return; } if(saveLog){ OpenLogFile(); //"Log.txt" fprintf(logfile,"ReadAT(0x%X,0x%X,0x%X)\n",dim,dim2,options); } size=dim; sizeEE=dim2; if(memCODE) free(memCODE); memCODE=(unsigned char*)malloc(dim); //CODE if(memEE) free(memEE); memEE=(unsigned char*)malloc(dim2); //EEPROM for(j=0;j>8; bufferU[j++]=2000&0xff; bufferU[j++]=VREG_DIS; //Disable HV reg bufferU[j++]=EN_VPP_VCC; //VDD bufferU[j++]=0x0; bufferU[j++]=FLUSH; for(;j>9; bufferU[j++]=i>>1; bufferU[j++]=FLUSH; for(;j>8; bufferU[j++]=i; bufferU[j++]=SPI_READ; bufferU[j++]=1; n++; if(j>DIMBUF-9||i==dim-1){ bufferU[j++]=FLUSH; for(;j0x20000||dim<0){ PrintMessage(strings[S_CodeLim]); //"Code size out of limits\r\n" return; } if(dim2>0x800||dim2<0){ PrintMessage(strings[S_EELim]); //"EEPROM size out of limits\r\n" return; } if(saveLog){ OpenLogFile(); //"Log.txt" fprintf(logfile,"ReadAT_HV(0x%X,0x%X,0x%X)\n",dim,dim2,options); } size=dim; sizeEE=dim2; if(memCODE) free(memCODE); memCODE=(unsigned char*)malloc(dim); //CODE if(memEE) free(memEE); memEE=(unsigned char*)malloc(dim2); //EEPROM for(j=0;j>9; bufferU[j++]=FLUSH; for(;j>1)&0xFF; bufferU[j++]=0x68; bufferU[j++]=0x00; bufferU[j++]=0x6C; bufferU[j++]=0x00; bufferU[j++]=AT_HV_RTX; bufferU[j++]=2; bufferU[j++]=0x78; bufferU[j++]=0x00; bufferU[j++]=0x7C; bufferU[j++]=0x00; i+=2; if(j>DIMBUF-14||i>=dim-2){ bufferU[j++]=FLUSH; for(;j>8; bufferU[j++]=FLUSH; for(;jDIMBUF-8||i>=dim2-2){ bufferU[j++]=FLUSH; for(;j0x8000||dim<0){ PrintMessage(strings[S_CodeLim]); //"Code size out of limits\r\n" return; } if(dim2>0x800||dim2<0){ PrintMessage(strings[S_EELim]); //"EEPROM size out of limits\r\n" return; } if(saveLog){ OpenLogFile(); //"Log.txt" fprintf(logfile,"WriteAT(0x%X,0x%X)\n",dim,dim2); } if(dim>size) dim=size; if(dim2>sizeEE) dim2=sizeEE; if(dim<1){ PrintMessage(strings[S_NoCode]); //"Data area is empty\r\n" return; } unsigned int start=GetTickCount(); j=0; bufferU[j++]=SET_PARAMETER; bufferU[j++]=SET_T3; bufferU[j++]=2000>>8; bufferU[j++]=2000&0xff; bufferU[j++]=VREG_DIS; //Disable HV reg bufferU[j++]=EN_VPP_VCC; //VDD bufferU[j++]=0x0; bufferU[j++]=FLUSH; for(;j>8; bufferU[j++]=20000&0xff; bufferU[j++]=VREG_DIS; //Disable HV reg bufferU[j++]=EN_VPP_VCC; //VDD bufferU[j++]=0x0; bufferU[j++]=SPI_INIT; bufferU[j++]=1; bufferU[j++]=CLOCK_GEN; bufferU[j++]=5; bufferU[j++]=CLOCK_GEN; bufferU[j++]=0xFF; bufferU[j++]=EXT_PORT; bufferU[j++]=0; bufferU[j++]=0; bufferU[j++]=WAIT_T3; //20ms bufferU[j++]=EN_VPP_VCC; //VDD bufferU[j++]=0x1; bufferU[j++]=WAIT_T3; //20ms bufferU[j++]=FLUSH; for(;j>8; bufferU[j++]=2000&0xff; bufferU[j++]=FLUSH; for(;j>9; bufferU[j++]=i>>1; bufferU[j++]=memCODE[i]; bufferU[j++]=WAIT_T3; //6ms bufferU[j++]=WAIT_T3; bufferU[j++]=WAIT_T3; bufferU[j++]=SPI_WRITE; //Read program memory bufferU[j++]=3; bufferU[j++]=0x20+(i&1?8:0); bufferU[j++]=i>>9; bufferU[j++]=i>>1; bufferU[j++]=SPI_READ; bufferU[j++]=1; bufferU[j++]=FLUSH; for(;jmax_err){ PrintMessage1(strings[S_MaxErr],err); //"Exceeded maximum number of errors (%d), write interrupted\r\n" PrintMessage(strings[S_IntW]); //"Write interrupted" i=dim; } if(saveLog){ fprintf(logfile,strings[S_Log8],i,i,k,k,err); //"i=%d, k=%d, err=%d\n" } } } PrintStatusEnd(); PrintMessage1(strings[S_ComplErr],err); //"completed, %d errors\r\n" //****************** write eeprom ******************** if(dim2){ PrintMessage(strings[S_EEAreaW]); //"Write EEPROM ... " if(saveLog) fprintf(logfile,"%s\n",strings[S_EEAreaW]); PrintStatusSetup(); int errEE=0; for(i=0,j=0;i>8; bufferU[j++]=i; bufferU[j++]=memEE[i]; bufferU[j++]=WAIT_T3; //6ms bufferU[j++]=WAIT_T3; bufferU[j++]=WAIT_T3; bufferU[j++]=SPI_WRITE; //Read EEPROM memory bufferU[j++]=3; bufferU[j++]=0xA0; bufferU[j++]=i>>8; bufferU[j++]=i; bufferU[j++]=SPI_READ; bufferU[j++]=1; bufferU[j++]=FLUSH; for(;jmax_err){ PrintMessage1(strings[S_MaxErr],err+errEE); //"Exceeded maximum number of errors (%d), write interrupted\r\n" PrintMessage(strings[S_IntW]); //"Write interrupted" i=dim2; } if(saveLog){ fprintf(logfile,strings[S_Log8],i,i,k,k,errEE); //"i=%d, k=%d, err=%d\n" } } } PrintStatusEnd(); PrintMessage1(strings[S_ComplErr],errEE); //"completed, %d errors\r\n" err+=errEE; } // if(maxTry) PrintMessage1(strings[S_MaxRetry],maxTry); //"Max retries in writing: %d\r\n" //****************** write FUSE ******************** if(AVRlock<0x100){ PrintMessage(strings[S_FuseAreaW]); //"Write Fuse ... " if(saveLog) fprintf(logfile,"%s\n",strings[S_FuseAreaW]); bufferU[j++]=SPI_WRITE; //Write lock bufferU[j++]=4; bufferU[j++]=0xAC; bufferU[j++]=0xF9+(AVRlock&0x06); bufferU[j++]=0; bufferU[j++]=0; bufferU[j++]=WAIT_T3; //9ms bufferU[j++]=FLUSH; for(;j0x20000||dim<0){ PrintMessage(strings[S_CodeLim]); //"Code size out of limits\r\n" return; } if(dim2>0x1000||dim2<0){ PrintMessage(strings[S_EELim]); //"EEPROM size out of limits\r\n" return; } if(saveLog){ OpenLogFile(); //"Log.txt" fprintf(logfile,"WriteATmega(0x%X,0x%X,0x%X,0x%X)\n",dim,dim2,page,options); } if(dim>size) dim=size; else{ size=dim; memCODE=(unsigned char*)realloc(memCODE,dim); } if(size%(page*2)){ //grow to an integer number of pages j=size; dim=(j/(page*2)+1)*page*2; memCODE=(unsigned char*)realloc(memCODE,dim); for(;jsizeEE) dim2=sizeEE; if(dim<1){ PrintMessage(strings[S_NoCode]); //"Data area is empty\r\n" return; } unsigned int start=GetTickCount(); j=0; bufferU[j++]=SET_PARAMETER; bufferU[j++]=SET_T3; bufferU[j++]=2000>>8; bufferU[j++]=2000&0xff; bufferU[j++]=VREG_DIS; //Disable HV reg bufferU[j++]=EN_VPP_VCC; //VDD bufferU[j++]=0x0; bufferU[j++]=FLUSH; for(;j>8; bufferU[j++]=5000&0xff; bufferU[j++]=FLUSH; for(;j>8; bufferU[j++]=k; for(z=0;z>9; bufferU[j++]=i>>1; bufferU[j++]=0; bufferU[j++]=WAIT_T3; //5ms bufferU[j++]=FLUSH; for(;j>9; bufferU[j++]=(i+k*2)>>1; bufferU[j++]=FLUSH; for(;jmax_err){ PrintMessage1(strings[S_MaxErr],err); //"Exceeded maximum number of errors (%d), write interrupted\r\n" PrintMessage(strings[S_IntW]); //"Write interrupted" i=dim; } } } PrintStatusEnd(); PrintMessage1(strings[S_ComplErr],err); //"completed, %d errors\r\n" //****************** write eeprom ******************** if(dim2){ PrintMessage(strings[S_EEAreaW]); //"Write EEPROM ... " if(saveLog) fprintf(logfile,"%s\n",strings[S_EEAreaW]); PrintStatusSetup(); int errEE=0; for(i=0,j=0;i>8; bufferU[j++]=i; bufferU[j++]=memEE[i]; bufferU[j++]=WAIT_T3; //5ms bufferU[j++]=WAIT_T3; //5ms bufferU[j++]=SPI_WRITE; //Read EEPROM memory bufferU[j++]=3; bufferU[j++]=0xA0; bufferU[j++]=i>>8; bufferU[j++]=i; bufferU[j++]=SPI_READ; bufferU[j++]=1; bufferU[j++]=FLUSH; for(;jmaxTry) maxTry=Rtry; i--; } else{ errEE++; Rtry=0; } } if(max_err&&err+errEE>max_err){ PrintMessage1(strings[S_MaxErr],err+errEE); //"Exceeded maximum number of errors (%d), write interrupted\r\n" PrintMessage(strings[S_IntW]); //"Write interrupted" i=dim2; } if(saveLog){ fprintf(logfile,strings[S_Log8],i,i,k,k,errEE); //"i=%d, k=%d, err=%d\n" } } } PrintStatusEnd(); PrintMessage1(strings[S_ComplErr],errEE); //"completed, %d errors\r\n" err+=errEE; } //****************** write FUSE ******************** int err_f=0; if(AVRlock<0x100||AVRfuse<0x100||AVRfuse_h<0x100||AVRfuse_x<0x100){ PrintMessage(strings[S_FuseAreaW]); //"Write Fuse ... " if(saveLog) fprintf(logfile,"%s\n",strings[S_FuseAreaW]); } if(AVRfuse<0x100){ bufferU[j++]=SPI_WRITE; //Write fuse bufferU[j++]=4; bufferU[j++]=0xAC; bufferU[j++]=0xA0; bufferU[j++]=0; bufferU[j++]=AVRfuse; bufferU[j++]=WAIT_T3; //5ms bufferU[j++]=SPI_WRITE; bufferU[j++]=3; bufferU[j++]=0x50; bufferU[j++]=0; bufferU[j++]=0; bufferU[j++]=SPI_READ; bufferU[j++]=1; bufferU[j++]=FLUSH; for(;j0x10000||dim<0){ PrintMessage(strings[S_CodeLim]); //"Code size out of limits\r\n" return; } if(dim2>0x800||dim2<0){ PrintMessage(strings[S_EELim]); //"EEPROM size out of limits\r\n" return; } if(saveLog){ OpenLogFile(); //"Log.txt" fprintf(logfile,"WriteAT_HV(0x%X,0x%X,0x%X,0x%X)\n",dim,dim2,page,options); } if(dim>size) dim=size; else{ size=dim; memCODE=(unsigned char*)realloc(memCODE,dim); } if(page&&(size%(page*2))){ //grow to an integer number of pages j=size; dim=(j/(page*2)+1)*page*2; memCODE=(unsigned char*)realloc(memCODE,dim); for(;jsizeEE) dim2=sizeEE; if(dim<1){ PrintMessage(strings[S_NoCode]); //"Data area is empty\r\n" return; } if(!StartHVReg(12)){ PrintMessage(strings[S_HVregErr]); //"HV regulator error\r\n" return; } unsigned int start=GetTickCount(); j=0; bufferU[j++]=EN_VPP_VCC; //VDD bufferU[j++]=0x0; bufferU[j++]=EXT_PORT; bufferU[j++]=0; bufferU[j++]=0; bufferU[j++]=SET_PORT_DIR; bufferU[j++]=0xFC; bufferU[j++]=0x7; bufferU[j++]=EN_VPP_VCC; //VDD bufferU[j++]=0x1; bufferU[j++]=EXT_PORT; bufferU[j++]=0; bufferU[j++]=SCI; bufferU[j++]=EXT_PORT; bufferU[j++]=0; bufferU[j++]=0; bufferU[j++]=EXT_PORT; bufferU[j++]=0; bufferU[j++]=SCI; bufferU[j++]=EXT_PORT; bufferU[j++]=0; bufferU[j++]=0; bufferU[j++]=EXT_PORT; bufferU[j++]=0; bufferU[j++]=SCI; bufferU[j++]=EXT_PORT; bufferU[j++]=0; bufferU[j++]=0; bufferU[j++]=EXT_PORT; bufferU[j++]=0; bufferU[j++]=SCI; bufferU[j++]=EXT_PORT; bufferU[j++]=0; bufferU[j++]=0; bufferU[j++]=EXT_PORT; bufferU[j++]=0; bufferU[j++]=SCI; bufferU[j++]=EXT_PORT; bufferU[j++]=0; bufferU[j++]=0; bufferU[j++]=EXT_PORT; bufferU[j++]=0; bufferU[j++]=SCI; bufferU[j++]=EXT_PORT; bufferU[j++]=0; bufferU[j++]=0; bufferU[j++]=EN_VPP_VCC; //VDD + VPP bufferU[j++]=0x5; bufferU[j++]=SET_PORT_DIR; //RELEASE SDO bufferU[j++]=0xFE; bufferU[j++]=0x7; bufferU[j++]=FLUSH; for(;j>9; bufferU[j++]=0x0C; bufferU[j++]=(i/2)&0xFF; bufferU[j++]=0x2C; bufferU[j++]=memCODE[i]; bufferU[j++]=0x64; //write data low bufferU[j++]=0x00; bufferU[j++]=0x6C; bufferU[j++]=0x00; bufferU[j++]=READ_B; //check SDO bufferU[j++]=FLUSH; for(;jmax_err){ PrintMessage1(strings[S_MaxErr],err); //"Exceeded maximum number of errors (%d), write interrupted\r\n" PrintMessage(strings[S_IntW]); //"Write interrupted" i=dim; } } } } else{ //page write for(i=0;ipage){ //only pages with data!=0xFF bufferU[j++]=AT_HV_RTX; bufferU[j++]=1; bufferU[j++]=0x4C; //Write FLASH bufferU[j++]=0x10; for(k=0;kDIMBUF-13||k>=page||i>=dim-2){ bufferU[j++]=FLUSH; for(;j>9)!=currPage){ //change high address if changed bufferU[j++]=AT_HV_RTX; bufferU[j++]=1; bufferU[j++]=0x1C; bufferU[j++]=i>>9; currPage=i>>9; } bufferU[j++]=AT_HV_RTX; //write page bufferU[j++]=2; bufferU[j++]=0x64; bufferU[j++]=0x00; bufferU[j++]=0x6C; bufferU[j++]=0x00; bufferU[j++]=READ_B; //check SDO bufferU[j++]=FLUSH; for(;jDIMBUF-14||k>=page||i>=dim-2){ bufferU[j++]=FLUSH; for(;jmax_err){ PrintMessage1(strings[S_MaxErr],err); //"Exceeded maximum number of errors (%d), write interrupted\r\n" PrintMessage(strings[S_IntW]); //"Write interrupted" i=dim; } } } } } } PrintStatusEnd(); PrintMessage1(strings[S_ComplErr],err); //"completed, %d errors\r\n" //****************** write eeprom ******************** if(dim2){ int errEE=0; PrintMessage(strings[S_EEAreaW]); //"Write EEPROM ... " PrintStatusSetup(); if(saveLog)fprintf(logfile,"WRITE EEPROM\n"); j=0; for(i=0;i>8; bufferU[j++]=0x2C; bufferU[j++]=memEE[i]; bufferU[j++]=0x6D; bufferU[j++]=0x00; bufferU[j++]=0x64; bufferU[j++]=0x00; bufferU[j++]=0x6C; bufferU[j++]=0x00; bufferU[j++]=READ_B; //check SDO bufferU[j++]=FLUSH; for(;j>8; bufferU[j++]=0x0C; bufferU[j++]=i&0xFF; bufferU[j++]=0x68; bufferU[j++]=0x00; bufferU[j++]=0x6C; bufferU[j++]=0x00; bufferU[j++]=FLUSH; for(;j=max_err) break; } } PrintStatusEnd(); err+=errEE; if(err>=max_err){ PrintMessage("\r\n"); PrintMessage1(strings[S_MaxErr],err); //"Exceeded maximum number of errors (%d), write interrupted\r\n" } PrintMessage1(strings[S_ComplErr],errEE); //"completed: %d errors\r\n" } //****************** write FUSE ******************** int err_f=0; if(AVRlock<0x100||AVRfuse<0x100||AVRfuse_h<0x100||AVRfuse_x<0x100)PrintMessage(strings[S_FuseAreaW]); //"Write Fuse ... " if(AVRfuse<0x100){ if(saveLog)fprintf(logfile,"WRITE FUSE\n"); bufferU[j++]=AT_HV_RTX; bufferU[j++]=4; bufferU[j++]=0x4C; bufferU[j++]=0x40; bufferU[j++]=0x2C; bufferU[j++]=AVRfuse; bufferU[j++]=0x64; bufferU[j++]=0x00; bufferU[j++]=0x6C; bufferU[j++]=0x00; bufferU[j++]=READ_B; //check SDO bufferU[j++]=FLUSH; for(;j