Fuse Rescue: reading issue [SOLVED]

Hi all!

I'm building a fuse rescue for ATmega328p:


Back

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.
I asked for help in the italian section, but it seems no one ever tried it. Can you help me?
Thanks!

This is the italian thread for reference:

This is the schematic diagram:

and this is the code:

const char *percorso=__FILE__; // Dalla macro __FILE__  prende il percorso del file in uso. Questa parte  di programma,
      char ver[12];            // 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).                  |
|   Con MiniCore si può comunque programmare tramite USB.                   |
-----------------------------------------------------------------------------
  *** EEPROM ***
 0: lfuse manuale
 1: hfuse manuale
 2: 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  Pin
IC   Nano I/O Porta Segnale VaVerso Pin  -> al chip; <- dal chip.
 1    3       PC6   RS         -     -
 2    2   0   PD0   Data0|Rx  PB0   14
 3    1   1   PD1   Data1|Tx  PB1   15
 4    5   2   PD2   Data2     PB2   16
 5    6   3   PD3   Data3     PB3   17
 6    7   4   PD4   Data4     PB4   18
 8+22 4  GND   -    GND       GND   8+22
 9   25  XTL1|PB6   EncA      Encoder-A
10   26  XTL2|PB7   EncB      Encoder-B
11    8   5   PD5   Data5     PB5   19
12    9   6   PD6   Data6     PC0   23
13   10   7   PD7   Data7     PC1   24
14   11   8   PB0   Vcc       Vcc   7+20
15   12   9   PB1   BS1       PD4    6   -> Byte Select 1
16   13  10   PB2   WR/       PD3    5   -> WRite pulse/
17   14  11   PB3   OE/       PD2    4   -> Output Enable/
18   15  12   PB4   RDY       PD1    3   <- Ready
19   16  13   PB5   XA0       PD5   11   -> XTAL Action bit 0
23   19 14=A0 PC0   /RST|HVon RST    1
24   20 15=A1 PC1   Sw|Buz    100 Ohm in serie e poi *cicalino*, *pulsante dell'encoder* e *1k+100nF* in parallelo 
25   21 16=A2 PC2   BS2       PC2   24   -> Byte Select 2
26   22 17=A3 PC3   XTAL1     XTAL1  9
27   23 18=A4 PC4   SDA|XA1   PD6   12   -> XTAL Action bit 1
28   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 SCL



void 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=((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[n_car]='\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: +12V
pinMode(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 7

void 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 display_fuse_letti() // MODIFICATO PER SIGNATURE BYTES - Preferisco tenere le due funzioni separate...
  {
  u8g2.setFont(u8g2_font_ncenB08_tr);
  u8g2.setCursor( 10, 63); u8g2.print(sbyte_1_letto>>4, HEX); u8g2.setCursor( 19, 63); u8g2.print(sbyte_1_letto&0x0F, HEX);
  u8g2.setCursor( 57, 63); u8g2.print(sbyte_2_letto>>4, HEX); u8g2.setCursor( 66, 63); u8g2.print(sbyte_2_letto&0x0F, HEX);
  u8g2.setCursor(104, 63); u8g2.print(sbyte_3_letto>>4, HEX); u8g2.setCursor(113, 63); u8g2.print(sbyte_3_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 mode
  digitalWrite(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);

  // 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);
  lbits_letto = PIND;
  digitalWrite( OE, HIGH);
  delay(1);
  
  // Lettura dei Signature Bytes:
  sendCmd(0b00001000);
  loadAddressLow(0x00);
  digitalWrite( OE, LOW);
  digitalWrite(BS1, LOW);
  sbyte_1_letto = PIND;
  digitalWrite( OE, HIGH);
  delay(1);
  loadAddressLow(0x01);
  digitalWrite( OE, LOW);
  digitalWrite(BS1, LOW);
  sbyte_2_letto = PIND;
  digitalWrite( OE, HIGH);
  delay(1);
  loadAddressLow(0x02);
  digitalWrite( OE, LOW);
  digitalWrite(BS1, LOW);
  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 mode
  writeFuse(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.
  }
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.

I double-checked all the connections: all OK... >:(

You want to read fuse bit values (EF, HF, LF) from a ATmega328P and show it on a local I2COLED.

1. Are you giving the read commands from the Serial Monitor of IDE?

2. Are you seeing the returned values on the Serial Monitor and record them manually?

3. Have you installed the necessary Control Program (user defined/developed) into the flash of Arduino NANO?

Hi, GolamMostafa

Options in the menu are selected by the rotary encoder: if I select 3. Arduino default and I keep pressed the encoder for 2s, programming starts and it works, because if I move the 328p to an Arduino board I can read the right fuse values by AVRDUDESS and USBASP.

If I try reading on the Fuse Rescue, instead, I read FF FF FF on the OLED.

The USB cable is only for powering.

IT WORKS! I only forgot to set port D as output before sending the first command!

portDoutput();
sendCmd(0b00000100);
portDinput();