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: |
| |
| [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.
}
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:
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.
}