Fuse Rescue for ATmega328p: reading error [SOLVED] - Page 1
Forum section: electronics / general

author: Datman
author_rank: Regular Contributor
timestamp: May 28, 2024, 03:17:18 pm
content: Hi allI'm building a fuse rescue for ATmega328p:The Nano is working at 8MHz by the internal RC oscillator, to gain 2 I/O pins. Nevertheless, I've had to share two pins between programming signals and I2C bus for the OLED, but I solved the problem adding a CD4053 and stopping and restarting I2C bus with the help of ChatGPT :slight_smile: .Now fuse programming is OK, but I still can't read fuses. After writing, AVRDUDESS reads the right values, but my device reads wrong values: FF FF FF.Can you help me?Thanks!This is the schematic diagram:

author: Datman
author_rank: Regular Contributor
timestamp: May 28, 2024, 03:27:01 pm
content: This is the code:Code:const char *percorso=__FILE__; // Dalla macro __FILE__ prende il percorso del file in uso. Questa parte di programma,char ver; // però, si trova nel file/cartella dell'IDE c_setup, in cui non è scritta la versione// del programma. La versione è scritta nel file principale, che ha lo stesso nome della// cartella che contiene tutti i file del programma. Questa riga, quindi, non può stare// nel setup./*-----------------------------------------------------------------------------| GIANLUCA GIANGRECO 2023 || Partendo da: || || https://github.com/lsahidin/HVSP-HVPP/blob/master/HVPP-Atmega.ino || || HVFuse - Use High Voltage Programming Mode to Set Fuses on ATmega328 || 09/23/08 Jeff Keyzer http://mightyohm.com || The HV programming routines are based on those described in the ATmega || 48/88/168 datasheet 2545M-AVR-09/07, pg. 290-297. || This program should work for other members of the AVR family, but has || only been verified to work with the ATmega168. If it works for you, || please let me know! http://mightyohm.com/blog/contact || https://mightyohm.com/blog/products/hv-rescue-shield-2-x/source-code || || https://www.instructables.com/HV-Rescue-Simple || || e aggiungendo il display, il menu e la lettura dei fuse, dei lock bits e || dei signature bytes, secondo il datasheet. || || CLOCK: 8MHz RC INTERNO per lasciare liberi PB6 e PB7 || (ATmega328P nuovo di fabbrica senza DIV8: E2, D9, FF). || Naturalmente va programmato tramite ICSP! |-----------------------------------------------------------------------------*** EEPROM ***0: lfuse manuale1: hfuse manuale2: efuse manuale*/#include <U8g2lib.h>#include <Wire.h>#include <EEPROM.h>U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);uint32_t t_press_lunga; // millis() aggiornato finché è premuto il pulsante.uint32_t t_clic; // millis() alla pressione del pulsante.bool clic=false; // Pressione breve dell'encoder.bool esce_da_impostazioni_manuali=false;uint8_t prg=1; // Numero del programma selezionato.uint8_t stato=1;uint8_t inizio=1;bool nessuna_risposta=LOW;int8_t E; // Risultato della routine encoder(): 1, -1, 0.uint8_t S; // Lettura dei due valori dell'encoder.uint8_t So;// Lettura precedente dell'encoder.int8_t X; // Usato in encoder() per evitare letture multiple.uint8_t lfuse;uint8_t hfuse;uint8_t efuse;uint8_t lbits;uint8_t lfuse_letto;uint8_t hfuse_letto;uint8_t efuse_letto;uint8_t lbits_letto; // Lock bits.uint8_t sbyte_1_letto; // Signature byte 1.uint8_t sbyte_2_letto; // Signature byte 2.uint8_t sbyte_3_letto; // Signature byte 3.bool fare_programmazione=false;#define ENC_PREMUTO !(digitalRead(A1))bool ENC_PREMUTO_PREC=false;// Desired fuse configuration// HFUSE 0xD9 // Default for ATmega328, for others see // ELECTROPEPPER CHANGED THIS LINES// LFUSE 0x62 // http://www.engbedded.com/cgi-bin/fc.cgi ///*Pin PinIC Nano I/O Porta Segnale VaVerso Pin -> al chip; <- dal chip.1 3 PC6 RS - -2 2 0 PD0 Data0|Rx PB0 143 1 1 PD1 Data1|Tx PB1 154 5 2 PD2 Data2 PB2 165 6 3 PD3 Data3 PB3 176 7 4 PD4 Data4 PB4 188+22 4 GND - GND GND 8+229 25 XTL1|PB6 EncA Encoder-A10 26 XTL2|PB7 EncB Encoder-B11 8 5 PD5 Data5 PB5 1912 9 6 PD6 Data6 PC0 2313 10 7 PD7 Data7 PC1 2414 11 8 PB0 Vcc Vcc 7+2015 12 9 PB1 BS1 PD4 6 -> Byte Select 116 13 10 PB2 WR/ PD3 5 -> WRite pulse/17 14 11 PB3 OE/ PD2 4 -> Output Enable/18 15 12 PB4 RDY PD1 3 <- Ready19 16 13 PB5 XA0 PD5 11 -> XTAL Action bit 023 19 14=A0 PC0 /RST|HVon RST 124 20 15=A1 PC1 Sw|Buz 100 Ohm in serie e poi *cicalino*, *pulsante dell'encoder* e *1k+100nF* in parallelo25 21 16=A2 PC2 BS2 PC2 24 -> Byte Select 226 22 17=A3 PC3 XTAL1 XTAL1 927 23 18=A4 PC4 SDA|XA1 PD6 12 -> XTAL Action bit 128 24 19=A5 PC5 SCL|PAGEL PD7 13 -> data Page Load- 27 Vcc- 28 RS- 29 GND- 30 Vin*/// Segnale I/O Porta#define VCC 8 // PB0#define BS1 9 // PB1#define WR 10 // PB2#define OE 11 // PB3#define RDY 12 // PB4 RDY/!BSY signal from target#define XA0 13 // PB5 XA0#define RST 14 // PC0 A0 // Output to level shifter for !RESET#define BS2 16 // PC2 A2#define XTAL1 17 // PC3 A3#define XA1 18 // PC4 A4 SDA#define PAGEL 19 // PC5 A5 SCLvoid Bip(){pinMode(A1, OUTPUT);tone(A1, 4000, 100);delay(120);pinMode(A1, INPUT_PULLUP);}void Biip(){pinMode(A1, OUTPUT);tone(A1, 2000, 500);delay(550);pinMode(A1, INPUT_PULLUP);}void encoder(){// PD 76543210// S=3- PIND&B00000011 ; // Uso PD1 e PD0, perciò non devo scorrere a destra.// S=3-( PIND>>3)&B00000011 ; // Uso PD4 e PD3, quindi scorro a destra di 3 bit per farli diventare 1 e 0.// S=3-((PIND>>2)&B00000011); // Uso PD3 e PD2, quindi scorro a destra di 2 bit per farli diventare 1 e 0.// S=3-((PINC>>1)&B00000011); // Uso PC2 e PC1 (A2 e A1), quindi scorro a destra di 1 bit per farli diventare 1 e 0.// S=3-((PIND>>4)&B00000011); // Uso PD5 e PD4, quindi scorro a destra di 4 bit per farli diventare 1 e 0.// S=3-((PINB>>6)&B00000011); // Uso PB7 e PB6, quindi scorro a destra di 6 bit per farli diventare 1 e 0.S=((PINB^0xFF)>>6 &0b00000011); // Inverto i bit, perché l'encoder chiude a massa, faccio scorrere a destra di 6 e considero solo PB6 e PB7 facendo &0b11.// Con "3-" occupa circa 8 byte in meno di memoria rispetto a "PINB^=xFF", ma è più brutto...// Il valore binario di S rappresenta A e B. Il centrale dell'encoder è a massa, quindi faccio complemento a 3 (11).S^=S>>1; // Faccio XOR (^) fra S (gray) e il suo bit 1, facendolo scorrere a Dx: AB XOR A,// ottenendo un binario che per ogni scatto fa 0-1-2-3-0 oppure 0-3-2-1-0.E=0;if (S!=So && S==0) X=0;if (X==0){if (So==1&&S==2){E=1; X=1;}if (So==3&&S==2){E=-1; X=1;}So=S;}}void setup(){char *ver_ext=strrchr(percorso,'v'); // Va a cercare l'ultima 'v' nel percorso.byte n_car=strlen(ver_ext)-4; // Calcola la lunghezza escludendo .ino.// (Perché in questo programma se metto 4 appare v0.1\a???...)strncpy(ver, ver_ext, n_car); // Copia i primi n_car caratteri da ver_ext a ver.ver='\0'; // Mette il terminatore in fondo.pinMode(A1, INPUT_PULLUP); // Pulsante e Cicalino piezo (le funzioni Bip e Biip commutano automaticamente In/Out/In).PORTB |= 0b11000000; // PB7 e PB6 INPUT_PULLUP: Encoder A e B.pinMode(VCC, OUTPUT);pinMode(RDY, INPUT);pinMode(OE, OUTPUT);pinMode(WR, OUTPUT);pinMode(BS1, OUTPUT);pinMode(XA0, OUTPUT);pinMode(XA1, OUTPUT);pinMode(PAGEL, OUTPUT);pinMode(RST, OUTPUT); // HIGH => RESET: +12VpinMode(BS2, OUTPUT);pinMode(XTAL1, OUTPUT);Wire.setClock(1000000); // Imposta la velocità dell'I2C a 1MHz anziché a 100kHz (default).u8g2.begin();u8g2.clearBuffer();u8g2.setFontMode(2);u8g2.setFont(u8g2_font_cu12_tr);u8g2.setCursor(10,11); u8g2.print("Fuse Rescue GG");u8g2.setCursor(7,25); u8g2.print(F("per ATmega328P"));u8g2.setFont(u8g2_font_ncenB08_tr);u8g2.setCursor((128-6*strlen(ver))/2, 39); u8g2.print(ver);u8g2.setFont(u8g2_font_cu12_tr);u8g2.setCursor(10,63); u8g2.print(F(" LF HF EF "));u8g2.sendBuffer();delay(1500);while(ENC_PREMUTO); // Blocca la visualizzazione se desiderato.u8g2.clear();u8g2.setCursor(11,15); u8g2.print(F("Pressione breve:"));u8g2.setCursor(22,31); u8g2.print(F("SELEZIONE"));u8g2.setCursor(11,47); u8g2.print(F("Pressione lunga:"));u8g2.setCursor(33,63); u8g2.print(F("ESEGUI"));u8g2.sendBuffer();delay(700);while(ENC_PREMUTO); // Blocca la visualizzazione se desiderato.u8g2.clear();u8g2.setFont(u8g2_font_ncenB08_tr);visual_menu();}#define PRG_MAX 7void loop(){encoder();if(E) // Se è stato mosso l'encoder:{prg+=E; if(prg>PRG_MAX) prg=1; else if(prg<1) prg=PRG_MAX;visual_menu();}if(clic && prg==7){clic=false;impostazioni_manuali();t_press_lunga=millis(); // Prende il tempo.while(ENC_PREMUTO) {if(millis()-t_press_lunga>2000) esegui(); ENC_PREMUTO_PREC=false;}t_press_lunga=millis(); // Prende il tempo.}if(!ENC_PREMUTO){if(ENC_PREMUTO_PREC){ENC_PREMUTO_PREC=false;t_clic=millis();}if(millis()-t_clic<300 && millis()>300) clic=true;t_press_lunga=millis();}else ENC_PREMUTO_PREC=true;if(millis()-t_press_lunga>2000) {esegui(); ENC_PREMUTO_PREC=false;} // Pressione lunga: esegue.u8g2.setFont(u8g2_font_ncenB08_tr);} // END loop.void esegui(){u8g2.clear();//u8g2.setFont(u8g2_font_cu9_tr);u8g2.setFont(u8g2_font_fancypixels_tr); // *** Ha le dimensioni giuste! ***if(prg==1){u8g2.setCursor(33,15); u8g2.print(F("LETTURA")); u8g2.sendBuffer();legge(); // Riscrive dopo la lettura, che ha bloccato l'OLED:u8g2.setCursor(33,15); u8g2.print(F("LETTURA")); u8g2.sendBuffer();Biip();u8g2.setCursor(13,31); u8g2.print(F(" *** FATTO! *** "));display_fuse_letti(); u8g2.sendBuffer(); Biip();delay(1000);}else{u8g2.setCursor(3,15); u8g2.print(F("PROGRAMMAZIONE")); u8g2.sendBuffer();programma();u8g2.setCursor(3,15); u8g2.print(F("PROGRAMMAZIONE")); // Riscrive dopo la programmazione, che ha bloccato l'OLED.Biip();if(nessuna_risposta) // Non è arrivato il RDY (Ready)!{u8g2.setCursor(0,36); u8g2.print(F("NESSUNA RISPOSTA!"));u8g2.setCursor(57,51); u8g2.print(F("! ! !")); u8g2.sendBuffer();delay(150);Biip();delay(150);Biip();nessuna_risposta=LOW;}else // La programmazione è stata completata.{u8g2.setCursor(13,31); u8g2.print(F(" *** FATTO! *** ")); u8g2.sendBuffer();Biip();}}delay(2000);digitalWrite(VCC, LOW);u8g2.setFont(u8g2_font_ncenB08_tr);visual_menu();return;}void visual_menu(){u8g2.clear();u8g2.setCursor(0,15);if(prg<10) u8g2.print(' ');u8g2.print(prg); u8g2.sendBuffer(); // Numero progressivo.u8g2.setCursor(20,15);// u8g2.setFont(u8g2_font_prospero_nbp_tr);u8g2.setFont(u8g2_font_5x7_tr);Bip();switch(prg){case 1:u8g2.setCursor(28,15); u8g2.print(F("*** LETTURA ***"));display_fuse_letti();break;case 2:u8g2.print(F("PRG con valori letti"));u8g2.setCursor(0,1);lfuse=lfuse_letto; hfuse=hfuse_letto; efuse=efuse_letto;display_fuse();break;case 3:u8g2.setCursor(30,15); u8g2.print(F("ARDUINO DEFAULT"));u8g2.setCursor(26,23); u8g2.print(F("16MHz No eesave"));u8g2.setCursor(32,31); u8g2.print(F("Con BOOTLOADER"));u8g2.setCursor(48,39); u8g2.print(F("BOD 2,7V"));lfuse=0xFF; hfuse=0xDE; efuse=0xFD;display_fuse();break;case 4:u8g2.setCursor(33,15); u8g2.print(F("ARDUINO EESAVE"));u8g2.setCursor(23,23); u8g2.print(F("16MHz Con EESAVE"));u8g2.setCursor(32,31); u8g2.print(F("Con BOOTLOADER"));u8g2.setCursor(48,39); u8g2.print(F("BOD 2,7V"));lfuse=0xFF; hfuse=0xD6; efuse=0xFD;display_fuse();break;case 5:u8g2.setCursor(38,15); u8g2.print(F("8MHz EESAVE"));u8g2.setCursor(26,23); u8g2.print(F("8MHz Con EESAVE"));u8g2.setCursor(36,31); u8g2.print(F("No bootloader"));u8g2.setCursor(48,39); u8g2.print(F("BOD 2,7V"));lfuse=0xFF; hfuse=0xD6; efuse=0xFD;display_fuse();break;case 6:u8g2.setCursor(33,15); u8g2.print(F("8MHz No EESAVE"));u8g2.setCursor(33,23); u8g2.print(F("8MHz No EESAVE"));u8g2.setCursor(36,31); u8g2.print(F("No bootloader"));u8g2.setCursor(48,39); u8g2.print(F("BOD 2,7V"));lfuse=0xFF; hfuse=0xDE; efuse=0xFD;display_fuse();break;case 7:u8g2.setCursor(47,15); u8g2.print(F("Manuale"));lfuse=EEPROM.read(0);hfuse=EEPROM.read(1);efuse=EEPROM.read(2);display_fuse();break;} // Fine switch(prg)u8g2.sendBuffer();} // Fine visual_menu()void display_fuse(){u8g2.setFont(u8g2_font_ncenB08_tr);u8g2.setDrawColor(0);// u8g2.drawBox ( 10, 53, 111, 10); // Con le 3 cancellazioni piccole mi sembra un po' più veloce...u8g2.drawBox ( 10, 53, 17, 10); // Cancella LF.u8g2.drawBox ( 57, 53, 17, 10); // Cancella HF.u8g2.drawBox (104, 53, 17, 10); // Cancella EF.u8g2.setDrawColor(1);u8g2.setCursor( 10, 63); u8g2.print(lfuse>>4, HEX); u8g2.setCursor( 19, 63); u8g2.print(lfuse&0x0F, HEX);u8g2.setCursor( 57, 63); u8g2.print(hfuse>>4, HEX); u8g2.setCursor( 66, 63); u8g2.print(hfuse&0x0F, HEX);u8g2.setCursor(104, 63); u8g2.print(efuse>>4, HEX); u8g2.setCursor(113, 63); u8g2.print(efuse&0x0F, HEX);}void display_F(uint8_t x, uint8_t y, uint8_t nibble) // Cancella e riscrive una cifra del fuse.{ // V Se qui sotto non metto x-1, con i caratteri stretti rimane un puntino in basso a sinistra!u8g2.setDrawColor(0); u8g2.drawBox ( x-1, y-10, 9, 10); // x e y del rettangolo che cancella sono a sinistra e IN ALTO.u8g2.setDrawColor(1); u8g2.setCursor( x, y); u8g2.print(nibble,HEX); // x e y di print sono a sinistra e IN BASSO!u8g2.sendBuffer();}void display_fuse_letti() // Preferisco tenere le due funzioni separate...{u8g2.setFont(u8g2_font_ncenB08_tr);u8g2.setCursor( 10, 63); u8g2.print(lfuse_letto>>4, HEX); u8g2.setCursor( 19, 63); u8g2.print(lfuse_letto&0x0F, HEX);u8g2.setCursor( 57, 63); u8g2.print(hfuse_letto>>4, HEX); u8g2.setCursor( 66, 63); u8g2.print(hfuse_letto&0x0F, HEX);u8g2.setCursor(104, 63); u8g2.print(efuse_letto>>4, HEX); u8g2.setCursor(113, 63); u8g2.print(efuse_letto&0x0F, HEX);}void impostazioni_manuali(){// *** LFUSE ***u8g2.setDrawColor(1); // Serve solo per far vedere se ritorna dalla fine, dopo l'ultima cancellazione!u8g2.setCursor(10,53); u8g2.print('v');u8g2.sendBuffer();while(ENC_PREMUTO); // Attende rilascio del pulsante.while(!ENC_PREMUTO){encoder();if(E){if (E== 1 && lfuse<240) lfuse+=16;else if (E==-1 && lfuse>15 ) lfuse-=16;display_F(10, 63, lfuse>>4); // Scrive la prima cifra Hex di lfuse.u8g2.sendBuffer();}}while(ENC_PREMUTO); // Attende rilascio del pulsante.u8g2.setDrawColor(0); u8g2.setCursor(10,53); u8g2.print('v'); // Cancella.u8g2.setDrawColor(1); u8g2.setCursor(19,53); u8g2.print('v'); // Scrive.u8g2.sendBuffer();while(!ENC_PREMUTO){encoder();if(E){if (E== 1 && (lfuse & 0x0F)<15) lfuse+=1;else if (E==-1 && (lfuse & 0x0F)>0 ) lfuse-=1;display_F(19, 63, lfuse&0x0F); // Scrive la seconda cifra Hex di lfuse.u8g2.sendBuffer();}}while(ENC_PREMUTO); // Attende rilascio del pulsante.// *** HFUSE ***u8g2.setDrawColor(0); u8g2.setCursor(19,53); u8g2.print('v'); // Cancella.u8g2.setDrawColor(1); u8g2.setCursor(57,53); u8g2.print('v'); // Scrive.u8g2.sendBuffer();while(!ENC_PREMUTO){encoder();if(E){if (E== 1 && hfuse<240) hfuse+=16;else if (E==-1 && hfuse>15 ) hfuse-=16;display_F(57, 63, hfuse>>4); // Scrive la prima cifra Hex di hfuse.u8g2.sendBuffer();}}while(ENC_PREMUTO); // Attende rilascio del pulsante.u8g2.setDrawColor(0); u8g2.setCursor(57,53); u8g2.print('v'); // Cancella.u8g2.setDrawColor(1); u8g2.setCursor(66,53); u8g2.print('v'); // Scrive.u8g2.sendBuffer();while(!ENC_PREMUTO){encoder();if(E){if (E== 1 && (hfuse & 0x0F)<15) hfuse+=1;else if (E==-1 && (hfuse & 0x0F)>0 ) hfuse-=1;display_F(66, 63, hfuse&0x0F); // Scrive la seconda cifra Hex di hfuse.u8g2.sendBuffer();}}while(ENC_PREMUTO); // Attende rilascio del pulsante.// *** EFUSE ***u8g2.setDrawColor(0); u8g2.setCursor( 66,53); u8g2.print('v'); // Cancella.u8g2.setDrawColor(1); u8g2.setCursor(104,53); u8g2.print('v'); // Scrive.u8g2.sendBuffer();while(!ENC_PREMUTO){encoder();if(E){if (E== 1 && efuse<240) efuse+=16;else if (E==-1 && efuse>15 ) efuse-=16;display_F(104, 63, efuse>>4); // Scrive la prima cifra Hex di efuse.u8g2.sendBuffer();}}while(ENC_PREMUTO); // Attende rilascio del pulsante.u8g2.setDrawColor(0); u8g2.setCursor(104,53); u8g2.print('v'); // Cancella.u8g2.setDrawColor(1); u8g2.setCursor(113,53); u8g2.print('v'); // Scrive.u8g2.sendBuffer();while(!ENC_PREMUTO){encoder();if(E){if (E== 1 && (efuse & 0x0F)<15) efuse+=1;else if (E==-1 && (efuse & 0x0F)>0 ) efuse-=1;display_F(113, 63, efuse&0x0F); // Scrive la seconda cifra Hex di efuse.u8g2.sendBuffer();}}u8g2.setDrawColor(0); u8g2.setCursor(113,53); u8g2.print('v'); // Cancella.u8g2.sendBuffer();EEPROM.update(0, lfuse);EEPROM.update(1, hfuse);EEPROM.update(2, efuse);Bip(); delay(150); Bip();u8g2.setDrawColor(1); // Ripristina la scrittura in bianco.}void disabilitaI2C(){TWCR&=~(1<<TWEN);pinMode(A4, OUTPUT);pinMode(A5, OUTPUT);}void abilitaI2C(){TWCR|=(1<<TWEN);u8g2.begin();}void enterProgrammingMode(){digitalWrite(PAGEL, LOW);digitalWrite(XA1, LOW);digitalWrite(XA0, LOW);digitalWrite(BS1, LOW);digitalWrite(BS2, LOW);// Enter programming modedigitalWrite(VCC, HIGH); // Apply VCC to start programming process.delay(500);digitalWrite(WR, HIGH); // Now we can assert !OE and !WR.digitalWrite(OE, HIGH);delay(1);digitalWrite(RST, HIGH); // Apply 12V to !RESET thru level shifter.delay(1);}void exitProgrammingMode(){digitalWrite(RST, LOW); // Esce dalla programmazione.PORTD = 0x00; // Porta a livello basso tutte le uscite.digitalWrite(OE, LOW);digitalWrite(WR, LOW);digitalWrite(PAGEL, LOW);digitalWrite(XA1, LOW);digitalWrite(XA0, LOW);digitalWrite(BS1, LOW);digitalWrite(BS2, LOW);delay(500);digitalWrite(VCC, LOW);}void loadAddressLow(uint8_t address){digitalWrite(XA1, LOW);digitalWrite(XA0, LOW);digitalWrite(BS1, LOW);PORTD = address;digitalWrite(XTAL1, HIGH);delay(1);digitalWrite(XTAL1, LOW);}void legge(){while(ENC_PREMUTO); // Si assicura che il pulsante sia stato lasciato.//Biip();disabilitaI2C();// Set up control lines for HV parallel programming.PORTD = 0x00; // Clear digital pins 0-7.DDRD = 0x00; // set digital pins 0-7 as inputs.enterProgrammingMode();// Produce lfuse_letto, hfuse_letto, efuse_letto, lbits_letto e sbyte_letto:sendCmd(0b00000100);digitalWrite( OE, HIGH);// Lettura degli lfuse:digitalWrite(BS1, LOW);digitalWrite(BS2, LOW);digitalWrite( OE, LOW);delay(1);lfuse_letto = PIND;digitalWrite( OE, HIGH);// Lettura degli hfuse:digitalWrite(BS1, HIGH);digitalWrite(BS2, HIGH);digitalWrite( OE, LOW);delay(1);hfuse_letto = PIND;digitalWrite( OE, HIGH);// Lettura degli efuse:digitalWrite(BS1, LOW);digitalWrite(BS2, HIGH);digitalWrite( OE, LOW);delay(1);efuse_letto = PIND;digitalWrite( OE, HIGH);// Lettura dei lockbits:digitalWrite(BS1, HIGH);digitalWrite(BS2, LOW);delay(1);lbits_letto = PIND;digitalWrite( OE, HIGH);delay(1);// Lettura dei Signature Bytes:sendCmd(0b00001000);loadAddressLow(0x00);digitalWrite( OE, LOW);digitalWrite(BS1, LOW);delay(1);sbyte_1_letto = PIND;digitalWrite( OE, HIGH);delay(1);loadAddressLow(0x01);digitalWrite( OE, LOW);digitalWrite(BS1, LOW);delay(1);sbyte_2_letto = PIND;digitalWrite( OE, HIGH);delay(1);loadAddressLow(0x02);digitalWrite( OE, LOW);digitalWrite(BS1, LOW);delay(1);sbyte_3_letto = PIND;digitalWrite( OE, HIGH);exitProgrammingMode();abilitaI2C();while(ENC_PREMUTO); // Si assicura che il pulsante sia stato lasciato.}void sendCmd(byte command) // Send command to target AVR.{// Set controls for command mode:digitalWrite(XA1, HIGH);digitalWrite(XA0, LOW);digitalWrite(BS1, LOW);PORTD = command;digitalWrite(XTAL1, HIGH); // pulse XTAL to send command to target.delay(1);digitalWrite(XTAL1, LOW);// delay(1);}void writeFuse(byte valore, char tipo) // Scrive (h)igh, (l)ow o (e)xtended fuse sul microcontrollore.{// Enable data loading:digitalWrite(XA1, LOW);digitalWrite(XA0, HIGH);delay(1);// Write fuse:PORTD = valore; // Carica il valore da programmare sulla porta D.digitalWrite(XTAL1, HIGH);delay(1);digitalWrite(XTAL1, LOW);if (tipo == 'l') {digitalWrite(BS1, LOW); digitalWrite(BS2, LOW); }else if(tipo == 'h') {digitalWrite(BS1, HIGH); digitalWrite(BS2, LOW); }else if(tipo == 'e') {digitalWrite(BS1, LOW); digitalWrite(BS2, HIGH);}digitalWrite(WR, LOW); // Scrive abbassando per un attimo il WR/.delay(1);digitalWrite(WR, HIGH);uint32_t t_ready=millis();while(digitalRead(RDY) == LOW)// Attende il Ready.{if(millis()-t_ready>500) // Se non arriva entro 500ms, significa che il chip non risponde:{nessuna_risposta=HIGH;return;}}// Ripristina BS1 e BS2:digitalWrite(BS1, LOW);digitalWrite(BS2, LOW);}void programma(){while(ENC_PREMUTO); // Si assicura che il pulsante sia stato lasciato.Biip();disabilitaI2C();// Set up control lines for HV parallel programming.PORTD = 0x00; // Clear digital pins 0-7.DDRD = 0xFF; // set digital pins 0-7 as outputs.// Initialize pins to enter programming mode:enterProgrammingMode();// Now we're in programming mode until RST is set HIGH again.// Scriviamo lfuse, hfuse e efuse:sendCmd(0b01000000); // Send command to enable fuse programming modewriteFuse(lfuse, 'l'); // Scrive lfuse.writeFuse(hfuse, 'h'); // Scrive hfuse.writeFuse(efuse, 'e'); // Scrive efuse.exitProgrammingMode();abilitaI2C();while(ENC_PREMUTO); // Si assicura che il pulsante sia stato lasciato.}Code:enterProgrammingMode(): enters programming mode.exitProgrammingMode(): exits.programma(): starts programming fuses.writeFuse(): writes the fuses.legge(): reads fuses (NOT WORKING).disabilitaI2C(): deactivates I2C bus.abilitaI2C(): reactivates I2C bus.This is only the reading function:Code:void legge(){while(ENC_PREMUTO); // Si assicura che il pulsante sia stato lasciato.//Biip();disabilitaI2C();// Set up control lines for HV parallel programming.PORTD = 0x00; // Clear digital pins 0-7.DDRD = 0x00; // set digital pins 0-7 as inputs.enterProgrammingMode();// Produce lfuse_letto, hfuse_letto, efuse_letto, lbits_letto e sbyte_letto:sendCmd(0b00000100);digitalWrite( OE, HIGH);// Lettura degli lfuse:digitalWrite(BS1, LOW);digitalWrite(BS2, LOW);digitalWrite( OE, LOW);delay(1);lfuse_letto = PIND;digitalWrite( OE, HIGH);// Lettura degli hfuse:digitalWrite(BS1, HIGH);digitalWrite(BS2, HIGH);digitalWrite( OE, LOW);delay(1);hfuse_letto = PIND;digitalWrite( OE, HIGH);// Lettura degli efuse:digitalWrite(BS1, LOW);digitalWrite(BS2, HIGH);digitalWrite( OE, LOW);delay(1);efuse_letto = PIND;digitalWrite( OE, HIGH);// Lettura dei lockbits:digitalWrite(BS1, HIGH);digitalWrite(BS2, LOW);delay(1);lbits_letto = PIND;digitalWrite( OE, HIGH);delay(1);// Lettura dei Signature Bytes:sendCmd(0b00001000);loadAddressLow(0x00);digitalWrite( OE, LOW);digitalWrite(BS1, LOW);delay(1);sbyte_1_letto = PIND;digitalWrite( OE, HIGH);delay(1);loadAddressLow(0x01);digitalWrite( OE, LOW);digitalWrite(BS1, LOW);delay(1);sbyte_2_letto = PIND;digitalWrite( OE, HIGH);delay(1);loadAddressLow(0x02);digitalWrite( OE, LOW);digitalWrite(BS1, LOW);delay(1);sbyte_3_letto = PIND;digitalWrite( OE, HIGH);exitProgrammingMode();abilitaI2C();while(ENC_PREMUTO); // Si assicura che il pulsante sia stato lasciato.}

author: aliarifat794
author_rank: Regular Contributor
timestamp: May 28, 2024, 06:08:26 pm
content: Please check the firmware too.

author: Datman
author_rank: Regular Contributor
timestamp: June 05, 2024, 11:43:19 am
content: IT WORKS! I only forgot to set port D as output before sending the first command! I thought I did it in setup...Code:portDoutput();sendCmd(0b00000100);portDinput();