/*
* 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"},
};
static bool 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 false;
}
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