Current c1960 designs
Wednesday, August 19, 2020
Monday, August 17, 2020
ATTINY85 Unbrick DIY hardware
ATTINY85 Unbrick Arduino shield.
I have been using these ATTINY85 8bit AVR capable MCUs in my projects for some time now because they are really easy to integrate on circuit boards and can run up to 16 MHz without the need to include an external crystal. They have 8k program storage which is quite a bit to work with.
IDE example stats:
Sketch uses 944 bytes (11%) of program storage space. Maximum is 8192 bytes.
Global variables use 29 bytes (5%) of dynamic memory, leaving 483 bytes for local variables. Maximum is 512 bytes.
It is very often that I do not need a lot of IOs to do what I want and need to get done. These devices also use very little power so they are ideal for a low power low IO count design.
They are available through Digikey for example in low quantities for only about a dollar and 20 cents each. However when they arrive in the mail they are most often configured by manufacturer with internal fuses set to an internal rc oscillator that is 8 MHz with the divide by 8 fuse set "0" is a set in this case. The divide by 8 fuse effectively makes these devices 1 MHz parts which I find extremely slow.
Therefore I need to write the fuses to allow the device to run at 16 MHz. Note that 20 MHz is possible for these devices with external crystals but they are already extremely IO limited and so that additional 4 MHz of speed will cost you 2 of your total 6 available IOs.
Sometimes as you program the devices it is also possible for glitches to cause the devices to "brick" meaning that the fuses need to be re-written to acceptable levels for your particular configuration needs so that once in a while you will need to un-brick them by writing the fuses.
If you do not have a method to write the fuses there a number of people on the internet that have shown how this can be done by some code and DIY hardware.
Here is an example:
http://wildlab.org/index.php/2016/11/30/bricked-attiny85-no-problem/
I found these useful but also found that they were kind of dodgy to use because they did not always work reliably. One reason I think is that they require a Host Arduino to power up the DUT tiny85 using pin 8 of the host. I found that doing this in some cases is not very reliable and it can seem to power up the DUT to less than the 1.8v which is required by the ATTINY85 databook.for High Voltage programming. High voltage because it is greater than 5 volts (12 volts)
From ATMEL device Databook: p155
Therefore I felt like a better more reliable option was needed. So I added a pfet to the design to control the bringing of pwr from Arduino host board to ATTiny85 power pin. See video:
So as I said in the video I have needed to change the state value of the D8 pin from the original code and I have changed some few other details.
Arduino code to load into UNO host device:
/*
AVR High-voltage Serial Fuse Reprogrammer by Paul Willoughby (03/20/2010) and modified by William Andersen
06/28/2020. http://www.rickety.us./2010/10/arduino-avr-hich-voltage-serial-programmer/
Fuse Calc:
http://www.engbedded.com/fusecalc/
*/
#define RST 13 // Output to level shifter for !RESET from transistor
#define SCI 12 // Target Clock Input
#define SDO 11 // Target Data Output ........................connected to tiny85 SCK/PB2 pin7
#define SII 10 // Target Instruction Input ...................connected to tiny85 MISO/PB1 pin6
#define SDI 9 // Target Data Input ..........................connected to tiny85 MOSI/PB0 pin5
#define VCC 8 // Target VCC
#define TRG 7 // trigger signal for scope to debug communications... adding Will Andersen
#define HFUSE 0x747C
#define LFUSE 0x646C
#define EFUSE 0x666E
// Define ATTiny series signatures
#define ATTINY13 0x9007 // L: 0x6A, H: 0xFF 8 pin
#define ATTINY24 0x910B // L: 0x62, H: 0xDF, E: 0xFF 14 pin
#define ATTINY25 0x9108 // L: 0x62, H: 0xDF, E: 0xFF 8 pin
#define ATTINY44 0x9207 // L: 0x62, H: 0xDF, E: 0xFFF 14 pin
#define ATTINY45 0x9206 // L: 0x62, H: 0xDF, E: 0xFF 8 pin
#define ATTINY84 0x930C // L: 0x62, H: 0xDF, E: 0xFFF 14 pin
#define ATTINY85 0x930B // L: 0x62, H: 0xDF, E: 0xFF 8 pin
byte checkIt = 0;
byte cval;
int menuselect;
unsigned int sig = 0;
void setup() {
pinMode(VCC, OUTPUT);
pinMode(RST, OUTPUT);
pinMode(SDI, OUTPUT);
pinMode(SII, OUTPUT);
pinMode(SCI, OUTPUT);
pinMode(SDO, OUTPUT); // Configured as input when in programming mode
pinMode(TRG, OUTPUT); // Adding for debug SPI communications
digitalWrite(TRG, LOW ); // will use positive pulese to trigger scope.
digitalWrite(RST, HIGH ); // Level shifter is inverting, this shuts off 12V
digitalWrite(VCC, HIGH); // Vcc off per modified circuit WA 7/11/20
Serial.begin(19200);
Serial.println("Code is modified by Rik. Visit riktronics.wordpress.com and electronics-lab.com for more projects");
Serial.println("-------------------------------------------------------------------------------------------------");
//Serial.println("Enter any character to start process..");
//checkIt = Serial.available();
//Serial.print("Serial.available returns: ");
//Serial.println(cval,checkIt);
//Serial.println("");
//delay(1000);
//if (Serial.available() ) {
// Serial.read();
delay(100);
pinMode(SDO, OUTPUT); // Set SDO to output
//trigger();
//for(;;) {
digitalWrite(SDI, LOW);
digitalWrite(SII, LOW);
digitalWrite(SDO, LOW);
digitalWrite(RST, HIGH); // 12v Off
digitalWrite(VCC, HIGH); // Vcc off per modified circuit WA 7/11/
digitalWrite(VCC, LOW); // Vcc ON per modified circuit WA 7/11/
delayMicroseconds(20);
digitalWrite(RST, LOW); // 12v On
delayMicroseconds(10);
pinMode(SDO, INPUT); // Set SDO to input
//MCUCR |= bit (PUD);
delayMicroseconds(300);
sig = readSignature();
// Serial.println(sig, HEX);
//sei();
Serial.println("Reading signature from connected ATtiny......");
Serial.println("Reading complete..");
Serial.print("Signature is: ");
Serial.println(sig, HEX);
readFuses();
// Do not want to write fuses at this point will perform that function in Loop if desired,
if (sig == ATTINY13) {
Serial.println("The ATtiny is detected as ATtiny13/ATtiny13A..");
Serial.print("LFUSE: ");
writeFuse(LFUSE, 0x6A);
Serial.print("HFUSE: ");
writeFuse(HFUSE, 0xFF);
Serial.println("");
} else if (sig == ATTINY24 || sig == ATTINY44 || sig == ATTINY84 || sig == ATTINY25 || sig == ATTINY45 || sig == ATTINY85) { {
Serial.println("The ATtiny is detected as ");
if(sig == ATTINY24) Serial.println("ATTINY24..");
else if(sig == ATTINY44) Serial.println("ATTINY44..");
else if(sig == ATTINY84) Serial.println("ATTINY84..");
else if(sig == ATTINY25) Serial.println("ATTINY25..");
else if(sig == ATTINY45) Serial.println("ATTINY45..");
else if(sig == ATTINY85) Serial.println("ATTINY85..");
writeFuse(LFUSE, 0xF1); // 62 = 1MHZ clk EZ = 8MHz F1 = 16 MHz internal RC
writeFuse(HFUSE, 0xDF);
writeFuse(EFUSE, 0xFF);
}}
Serial.println("Fuses will be read again to check if it's changed successfully..");
readFuses();
digitalWrite(SCI, LOW);
digitalWrite(VCC, HIGH); // Vcc Off active low pin per modifiedd circuit WA 7/11/20
//Serial.println("VCC: Low");
digitalWrite(RST, HIGH); // 12v Off
}
void loop() {
}
void trigger() {
digitalWrite(TRG, HIGH);
digitalWrite(TRG, LOW);
}
byte shiftOut (byte val1, byte val2) {
int inBits = 0;
//Wait until SDO goes high
while (!digitalRead(SDO));
unsigned int dout = (unsigned int) val1 << 2;
unsigned int iout = (unsigned int) val2 << 2;
for (int ii = 10; ii >= 0; ii--) {
digitalWrite(SDI, !!(dout & (1 << ii)));
digitalWrite(SII, !!(iout & (1 << ii)));
inBits <<= 1; inBits |= digitalRead(SDO);
delayMicroseconds(4);
digitalWrite(SCI, HIGH);
delayMicroseconds(2);
digitalWrite(SCI, LOW);
}
return inBits >> 2;
}
void writeFuse (unsigned int fuse, byte val) {
Serial.println("Writing correct fuse settings to ATtiny.......");
shiftOut(0x40, 0x4C);
shiftOut( val, 0x2C);
shiftOut(0x00, (byte) (fuse >> 8));
shiftOut(0x00, (byte) fuse);
Serial.println("Writing complete..");
}
void readFuses () {
byte val;
Serial.println("Reading fuse settings from connected ATtiny.......");
shiftOut(0x04, 0x4C); // LFuse
shiftOut(0x00, 0x68);
val = shiftOut(0x00, 0x6C);
Serial.print("LFuse: ");
Serial.print(val, HEX);
shiftOut(0x04, 0x4C); // HFuse
shiftOut(0x00, 0x7A);
val = shiftOut(0x00, 0x7E);
Serial.print(", HFuse: ");
Serial.print(val, HEX);
shiftOut(0x04, 0x4C); // EFuse
shiftOut(0x00, 0x6A);
val = shiftOut(0x00, 0x6E);
Serial.print(", EFuse: ");
Serial.println(val, HEX);
Serial.println("Reading complete..");
}
unsigned int readSignature() {
unsigned int sig = 0;
byte val;
//trigger();
for (int ii = 1; ii < 3; ii++) {
shiftOut(0x08, 0x4C);
shiftOut( ii, 0x0C);
shiftOut(0x00, 0x68);
val = shiftOut(0x00, 0x6C);
sig = (sig << 8) + val;
}
return sig;
}
unsigned int readLockbits() {
unsigned int LB = 0;
//byte val;
//trigger();
for (int ii = 0; ii < 1; ii++) {
shiftOut(0x04, 0x4C);
shiftOut( 0x00, 0x38);
LB = shiftOut(0x00, 0x7C);
}
return LB;
}
void eraseChip() {
for (int ii = 0; ii < 1; ii++) {
shiftOut(0x80, 0x4C);
shiftOut(0x00, 0x64);
shiftOut(0x00, 0x6C);
}
}
unsigned int readSignatureLV() {
unsigned int sig = 0;
//byte val;
pinMode(SII, OUTPUT);
pinMode(SDO, OUTPUT);
delayMicroseconds(300);
digitalWrite(SDO, LOW);
digitalWrite( VCC,LOW); // power up tiny86 chip through PNP device connected from power to PWR on attiny85
digitalWrite( RST,HIGH); // pulls 12v to 0v on reset pin through npn transistor
delayMicroseconds(20);
// digitalWrite(SDI,HIGH); // MOSI Per tBLE 20-10 PAGE 151 Program enable instruction
// digitalWrite(SII,LOW); // MISO (same)
// digitalWrite(SDO, HIGH) // SCK (same)
pinMode(SII, INPUT);
pinMode(SDO, OUTPUT);
delayMicroseconds(300);
trigger();
//done power down chip
digitalWrite( VCC,HIGH); // power down tiny85 chip through PNP device connected from power to PWR on attiny85
digitalWrite( RST,LOW); // pulls 12v to 12v on reset pin through npn transistor
digitalWrite( RST,HIGH); // pulls 12v to 0v on reset pin through npn transistor
delayMicroseconds(20);
return sig;
}
Hope you find this useful. I will make this board kit available on ebay.com soon and make it available through seed studio as well.