Author Topic: Fuse Rescue for ATmega328p: reading error [SOLVED]  (Read 882 times)

0 Members and 1 Guest are viewing this topic.

Offline DatmanTopic starter

  • Regular Contributor
  • *
  • Posts: 114
  • Country: it
Fuse Rescue for ATmega328p: reading error [SOLVED]
« on: May 28, 2024, 03:17:18 pm »
Hi all
I'm building a fuse rescue for ATmega328p:
2252983-0

2253013-1
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:
2253001-2
« Last Edit: June 07, 2024, 12:45:18 pm by Datman »
 

Offline DatmanTopic starter

  • Regular Contributor
  • *
  • Posts: 114
  • Country: it
Re: Fuse Rescue for ATmega328p: reading error
« Reply #1 on: May 28, 2024, 03:27:01 pm »
This is the code:
Code: [Select]
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:                                                              |
|                                                                           |
|   [url]https://github.com/lsahidin/HVSP-HVPP/blob/master/HVPP-Atmega.ino[/url]       |
|                                                                           |
|   HVFuse - Use  High Voltage Programming Mode  to Set Fuses on ATmega328  |
|   09/23/08  Jeff Keyzer  [url]http://mightyohm.com[/url]                             |
|   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!  [url]http://mightyohm.com/blog/contact[/url]                 |
|   [url]https://mightyohm.com/blog/products/hv-rescue-shield-2-x/source-code[/url]   |
|                                                                           |
|   [url]https://www.instructables.com/HV-Rescue-Simple[/url]                         |
|                                                                           |
| 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 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   // [url]http://www.engbedded.com/cgi-bin/fc.cgi[/url] //
 
/*
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=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[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 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);
  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 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.
  }

Code: [Select]
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: [Select]
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.
  }
« Last Edit: May 28, 2024, 03:45:17 pm by Datman »
 

Offline aliarifat794

  • Regular Contributor
  • *
  • !
  • Posts: 138
  • Country: bd
Re: Fuse Rescue for ATmega328p: reading error
« Reply #2 on: May 28, 2024, 06:08:26 pm »
Please check the firmware too.
 

Offline DatmanTopic starter

  • Regular Contributor
  • *
  • Posts: 114
  • Country: it
Re: Fuse Rescue for ATmega328p: reading error
« Reply #3 on: June 05, 2024, 11:43:19 am »
IT WORKS! I only forgot to set port D as output before sending the first command! I thought I did it in setup...

Code: [Select]
portDoutput();
sendCmd(0b00000100);
portDinput();
« Last Edit: June 17, 2024, 09:17:26 pm by Datman »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf