// ReFusator V3 //====================== // pripravek pro prepisovani FUSE Bajtu v ruznych typech mikrokontroleru ATtiny // Zaroven slouzi i jako ISP programator techto mikrokontroleru // Detily, schema a plosny spoj: // http://www.astromik.org/raspi/refusatorv3 // verze SW : 5 // datum : 24.6.2016 //---------------------------------------------------------- // ArduinoISP // Upraveno z ukazkoveho prikladu "Arduino as ISP" // Copyright (c) 2008-2011 Randall Bohn // If you require a license, see // http://www.opensource.org/licenses/bsd-license.php // // This sketch turns the Arduino into a AVRISP // // puvodni priklad upraven a zjednodusen pro Arduino NANO ve funkci ISP programatoru // prirazeni pinu je na desce "ReFusator V3" pevne nastavene a neni mozno ho menit // ATtiny - Arduino NANO //---------------------------------------------------------------------------- // reset [PB5] - A0 (spinano pres invertujici FET) // MOSI [PB0] - D9 // MISO [PB1] - D10 // SCK [PB2] - A2 // VCC - D8 // GND - GND // PB3 - A1 // PB4 - nezapojeno // informacni LED SMD (THT) // RUDA - D3 (D4) // ZELENA - D2 (D3) // MODRA - D4 (D2) // DIL prepinace volby obvodu // prep1 - A7 // prep2 - A6 // tlacitko pro spusteni prepisovani FUSE bajtu // tlac - D7 // kontrola napeti na 12V DC-DC regulatoru // test12v - A3 // signalizace komunikace mezi PC a Arduinem NANO (pri ISP programovani) // LED Tx a Rx primo na desce Arduino NANO (piny D0 a D1) #include "Arduino.h" #undef SERIAL #define PROG_FLICKER true // Configure SPI clock (in Hz). // E.g. for an attiny @128 kHz: the datasheet states that both the high // and low spi clock pulse must be > 2 cpu cycles, so take 3 cycles i.e. // divide target f_cpu by 6: // #define SPI_CLOCK (128000/6) // // A clock slow enough for an attiny85 @ 1MHz, is a reasonable default: #define SPI_CLOCK (1000000/6) // Select hardware or software SPI, depending on SPI clock. // Currently only for AVR, for other archs (Due, Zero,...), // hardware SPI is probably too fast anyway. #if defined(ARDUINO_ARCH_AVR) #if SPI_CLOCK > (F_CPU / 128) #define USE_HARDWARE_SPI #endif #endif // Configure which pins to use: // The standard pin configuration. #ifndef ARDUINO_HOODLOADER2 #define RESET A0 // A0 je reset #define LED_ERR 4 // LED pro ERR pri komunikaci je modra // Uncomment following line to use the old Uno style wiring // (using pin 11, 12 and 13 instead of the SPI header) on Leonardo, Due... #define USE_OLD_STYLE_WIRING #ifdef USE_OLD_STYLE_WIRING #define PIN_MOSI 9 #define PIN_MISO 10 #define PIN_SCK A2 #define PIN_VCC 8 #endif // HOODLOADER2 means running sketches on the atmega16u2 // serial converter chips on Uno or Mega boards. // We must use pins that are broken out: #else #define RESET A0 #define LED_ERR 4 #endif // By default, use hardware SPI pins: #ifndef PIN_MOSI #define PIN_MOSI MOSI #endif #ifndef PIN_MISO #define PIN_MISO MISO #endif #ifndef PIN_SCK #define PIN_SCK SCK #endif // Force bitbanged SPI if not using the hardware SPI pins: #if (PIN_MISO != MISO) || (PIN_MOSI != MOSI) || (PIN_SCK != SCK) #undef USE_HARDWARE_SPI #endif // Configure the serial port to use. // // Prefer the USB virtual serial port (aka. native USB port), if the Arduino has one: // - it does not autoreset (except for the magic baud rate of 1200). // - it is more reliable because of USB handshaking. // // Leonardo and similar have an USB virtual serial port: 'Serial'. // Due and Zero have an USB virtual serial port: 'SerialUSB'. // // On the Due and Zero, 'Serial' can be used too, provided you disable autoreset. // To use 'Serial': #define SERIAL Serial #ifdef SERIAL_PORT_USBVIRTUAL #define SERIAL SERIAL_PORT_USBVIRTUAL #else #define SERIAL Serial #endif // Configure the baud rate: #define BAUDRATE 19200 // #define BAUDRATE 115200 // #define BAUDRATE 1000000 #define HWVER 2 #define SWMAJ 1 #define SWMIN 18 // STK Definitions #define STK_OK 0x10 #define STK_FAILED 0x11 #define STK_UNKNOWN 0x12 #define STK_INSYNC 0x14 #define STK_NOSYNC 0x15 #define CRC_EOP 0x20 //ok it is a space... // tady se definuji FUSE pro 4 kombinace poloh dvou DIL prepinacu // DIL 0 .... prepinace v poloze ON-ON // DIL 1 .... prepinace v poloze 1-ON // DIL 2 .... prepinace v poloze ON- 2 // DIL 3 .... prepinace v poloze 1- 2 // DIL 4 .... nepouzita definice fuse bajtu // zpusob signalizace zvoleneho obvodu // LED 0 .... pri prepnuti na tuto sadu fuse bajtu LED nesviti // LED 1 .... pri prepnuti na tuto sadu fuse bajtu sviti zelena LED // LED 2 .... pri prepnuti na tuto sadu fuse bajtu sviti cervena LED // LED 3 .... pri prepnuti na tuto sadu fuse bajtu sviti zelena i cervena LED // LED 4 .... pri prepnuti na tuto sadu fuse bajtu blika zelena LED // LED 5 .... pri prepnuti na tuto sadu fuse bajtu blika cervena LED // LED 6 .... pri prepnuti na tuto sadu fuse bajtu stridave blikaji cervena a zelena LED int deffuse [10][5] = {//DIL LFUSE HFUSE EFUSE LED // Lfus Hfus Efus Popis { 4 , 0b01101010 , 0b11111111 , -1 , 3}, // [0x6A] [0xFF] neupraveny original ATtiny13 (nastaveno deleni frekvence 8 -> CKDIV8) { 0 , 0b01111010 , 0b11111111 , -1 , 1}, // [0x7A] [0xFF] ATtiny13 bez CKDIV8 { 1 , 0b01111010 , 0b11111110 , -1 , 4}, // [0x7A] [0xFE] ATtiny13 bez CKDIV8 s moznosti pouziti pinu RESET jako obycejneho PB5 (RSTDSBL) { 4 , 0b01100010 , 0b11011111 , 0b11111111 , 6}, // [0x62] [0xDF] [0xFF] neupraveny original ATtiny25 (..45 / ..85) (nastaveno deleni frekvence 8 -> CKDIV8) { 2 , 0b11100010 , 0b11011111 , 0b11111111 , 2}, // [0xE2] [0xDF] [0xFF] ATtiny25 (..45 / ..85) bez CKDIV8 { 3 , 0b11100010 , 0b01011111 , 0b11111111 , 5}, // [0xE2] [0x5F] [0xFF] ATtiny25 (..45 / ..85) bez CKDIV8 s moznosti pouziti pinu RESET jako obycejneho PB5 (RSTDSBL) { 4 , 0b11111111 , 0b11111111 , 0b11111111 , 0}, // [0xFF] [0xFF] [0xFF] pripraveno pro vlastni definici fuse bajtu { 4 , 0b11111111 , 0b11111111 , 0b11111111 , 0}, // [0xFF] [0xFF] [0xFF] pripraveno pro vlastni definici fuse bajtu { 4 , 0b11111111 , 0b11111110 , 0b11111111 , 0}, // [0xFF] [0xFF] [0xFF] pripraveno pro vlastni definici fuse bajtu { 4 , 0b11111111 , 0b11111111 , 0b11111111 , 0}, // [0xFF] [0xFF] [0xFF] pripraveno pro vlastni definici fuse bajtu }; // (kdyz neni pro obvod definovana EFUSE, nastavi se na -1) // deklarace promennych pro ReFusator #define HFUSE 0x747C #define LFUSE 0x646C #define EFUSE 0x666E #define RST A0 #define SCI A1 #define SDO A2 #define SII 10 #define SDI 9 #define tlac 7 // tlacitko pro vypaleni FUSE #define prep1 A7 // vstupy pro DIL prepinace #define prep2 A6 // zamerne zvoleny analogove vstupy, aby bylo mozne v pripade potreby pouzit vic kontaktu na jeden vstup (prepinane delice napeti) // varianta s SMD trojbarevnou LED #define LEDR 3 #define LEDG 2 #define LEDB 4 // pri variante s trojbarevnou THT LED zrusit komentare // v nasledujicich 3 radkach // a zakomentovat predchozi 3 radky // (kvuli omylem prohozenym pinum na plosnaku) // #define LEDR 4 // #define LEDG 3 // #define LEDB 2 #define test12v A3 // vstup pro kontrolu nastaveni 12V byte prepnuto; // aktualni stav DIL prepinacu (pouzito pro vyber bloku fuse bajtu z pole deffuse[]) byte index_bloku; // index bloku 'deffuse[]', ktery byl vybrany DIL prepinaci boolean stat_led; // pamet posledniho stavu LED (kvuli blikani) boolean isp_bezi = false; // znacka, ktera signalizuje, jestli je ReFusator v rezimu ISP programatoru //(vyuziva se k preskakovani pauzy pro blikani LEDek) //=========================================================== #ifdef USE_HARDWARE_SPI #include "SPI.h" #else #define SPI_MODE0 0x00 class SPISettings { public: // clock is in Hz SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) : clock(clock){ (void) bitOrder; (void) dataMode; }; private: uint32_t clock; friend class BitBangedSPI; }; class BitBangedSPI { public: void begin() { digitalWrite(PIN_SCK, LOW); digitalWrite(PIN_MOSI, LOW); pinMode(PIN_SCK, OUTPUT); pinMode(PIN_MOSI, OUTPUT); pinMode(PIN_MISO, INPUT); } void beginTransaction(SPISettings settings) { pulseWidth = (500000 + settings.clock - 1) / settings.clock; if (pulseWidth == 0) pulseWidth = 1; } void end() {} uint8_t transfer (uint8_t b) { for (unsigned int i = 0; i < 8; ++i) { digitalWrite(PIN_MOSI, (b & 0x80) ? HIGH : LOW); digitalWrite(PIN_SCK, HIGH); delayMicroseconds(pulseWidth); b = (b << 1) | digitalRead(PIN_MISO); digitalWrite(PIN_SCK, LOW); // slow pulse delayMicroseconds(pulseWidth); } return b; } private: unsigned long pulseWidth; // in microseconds }; static BitBangedSPI SPI; #endif //=========================================================== // blikani nebo sviceni LED podle vybraneho obvodu urceneho k preprogramovani FUSE void blik_refuse(byte styl) { switch (styl) { case 1: digitalWrite(LEDR, HIGH); // sviti jen zelena LED digitalWrite(LEDG, LOW); break; case 2: digitalWrite(LEDR, LOW); // sviti jen cervena LED digitalWrite(LEDG, HIGH); break; case 3: digitalWrite(LEDR, LOW); // sviti obe LED (zluta barva) digitalWrite(LEDG, LOW); break; case 4: digitalWrite(LEDR, HIGH); // cervena LED je trvale zhasla if (stat_led == HIGH) { stat_led = LOW; digitalWrite(LEDG, LOW);; // zelena LED blika } else { stat_led = HIGH; digitalWrite(LEDG, HIGH); } break; case 5: digitalWrite(LEDG, HIGH); // zelena LED je trvale zhasla if (stat_led == HIGH) { stat_led = LOW; digitalWrite(LEDR, LOW); // cervena LED blika } else { stat_led = HIGH; digitalWrite(LEDR, HIGH); } break; case 6: if (stat_led == HIGH) { stat_led = LOW; digitalWrite(LEDG, LOW); // obe LED stridave blikaji digitalWrite(LEDR, HIGH); } else { stat_led = HIGH; digitalWrite(LEDG, HIGH); digitalWrite(LEDR, LOW); } break; default: digitalWrite(LEDR, HIGH); // pro vsechny ostatni hodnoty obe LED zhasnout digitalWrite(LEDG, HIGH); break; } } void setup() { SERIAL.begin(BAUDRATE); pinMode(LEDR, OUTPUT); // cervena LED pinMode(LEDG, OUTPUT); // zelena LED pinMode(LED_ERR, OUTPUT); // modra LED pinMode(PIN_VCC, OUTPUT); // napajeci pin pro ATtiny digitalWrite(PIN_VCC, LOW); // vypnout napajeni ATtiny delay(500); // 0.5 sekundy pauza digitalWrite(PIN_VCC, HIGH); // zapnout napajeni ATtiny // nastaveni smeru portu pro DIL prepinace a pripojeni Pull-Up odporu (jsou to analogove vstupy) pinMode(prep1, INPUT_PULLUP); pinMode(prep2, INPUT_PULLUP); // nastaveni smeru portu pro spousteci tlacitko a pripojeni Pull-Up odporu pinMode(tlac, INPUT_PULLUP); // nastaveni smeru portu pro kontrolu napeti 12V pinMode(test12v, INPUT); analogReference(INTERNAL); // nastaveni reference na 1,1V (pri testovani 12V je pouzita zenerova dioda a delic napeti) digitalWrite(LEDR, HIGH); // zhasne cervenou LED digitalWrite(LEDG, HIGH); // zhasne zelenou LED // hned pri startu se provadi testovani 12V. Pokud napeti nevyhovuje, prejde se do nastavovaci smycky // Pomoci trimru se v teto smycce nastavuje na DC-DC napeti 12V // Z nastavovaci smycky je mozne odejit jen resetem int napeti = analogRead(test12v); // kvuli analogovemu multiplexeru v ATmega328 je prvni mereni okamzite po prepnuti nepresne delay(50); // a je treba chvili pockat, nez se hodnota ustali napeti = analogRead(test12v); // druhe a vsechny dalsi mereni na vybranem analogovem kanalu jsou uz v poradku if ((napeti < 420) || (napeti > 480 )) // napeti na 12V zdroji mimo rozsah 11.7V az 12.3V { while (true) { napeti = analogRead(test12v); if ((napeti < 440) || (napeti > 460 )) // kdyz je napeti mimo prisnejsi toleranci 11.9V az 12.1V { digitalWrite(LEDB, LOW); // rozsviti modrou LED (spolecna anoda je na +5V) } else { digitalWrite(LEDB, HIGH); // zhasne modrou LED } Serial.print ("Pozadovana hodnota : 450 (+/- 10) skutecna hodnota : "); Serial.println (napeti); delay(200); } // z tehle smycky se da vyskocit jen resetem } } int error = 0; int pmode = 0; // address for reading and writing, set by 'U' command unsigned int here; uint8_t buff[256]; // global block storage #define beget16(addr) (*addr * 256 + *(addr+1) ) typedef struct param { uint8_t devicecode; uint8_t revision; uint8_t progtype; uint8_t parmode; uint8_t polling; uint8_t selftimed; uint8_t lockbytes; uint8_t fusebytes; uint8_t flashpoll; uint16_t eeprompoll; uint16_t pagesize; uint16_t eepromsize; uint32_t flashsize; } parameter; parameter param; static bool rst_active_high; void reset_target(bool reset) { reset = !reset; // reset je kvuli FETu negovany digitalWrite(RESET, ((reset && rst_active_high) || (!reset && !rst_active_high)) ? HIGH : LOW); } void loop(void) { // is there an error? if (error) { digitalWrite(LED_ERR, LOW); // pri spolecne ANODE se LED rozsveci pri LOW } else { digitalWrite(LED_ERR, HIGH); // a zhasina pri HIGH } // zjisteni aktualniho stavu DIL prepinacu int DIL1 = analogRead(prep1); // v pripade potreby je mozne analogovymi vstupy testovat nekolik hodnot, takze dva DIL prepinace je mozne int DIL2 = analogRead(prep2); // nahradit napriklad otocnym prepinacem s prepinanym delicem napeti if ((DIL1 < 500) && (DIL2 < 500)) prepnuto = 0 ; // prepnuto do polohy ON - ON if ((DIL1 > 500) && (DIL2 < 500)) prepnuto = 1 ; // prepnuto do polohy 1 - ON if ((DIL1 < 500) && (DIL2 > 500)) prepnuto = 2 ; // prepnuto do polohy ON - 2 if ((DIL1 > 500) && (DIL2 > 500)) prepnuto = 3 ; // prepnuto do polohy 1 - 2 for (byte i = 0 ; i< 10 ; i++) // nalezeni prislusneho indexu bloku definic fuse bajtu { if (deffuse[i][0] == prepnuto) index_bloku = i; } blik_refuse(deffuse[index_bloku][4]); // rozblikani LED podle promenne deffuse[] if (isp_bezi == false) // v reimu ISP programatoru neni mozne cekat 0.2 sekundy kvuli blikani LED { delay(200); // jinak tu ale musi byt nejaka pauza, aby bylo videt blikani LED podle nastavenych prepinacu } //pri stisknuti tlacitka se zacnou vypalovat FUSE bajty if (digitalRead(tlac) == LOW) { pinMode(PIN_MOSI, INPUT); pinMode(PIN_MISO, INPUT); pinMode(SCI, INPUT); digitalWrite(LEDR, HIGH); // obe LED zhasnout digitalWrite(LEDG, HIGH); ReFuse(); // podprogram pro prepaleni vsech FUSE bajtu // cekat na uvolneni tlacitka po skonceni vypalovani FUSE bajtu // po ukonceni vypalovani se rozsviti modra LED while (digitalRead(tlac) == LOW) { digitalWrite(LEDB, LOW); delay(100); } delay(500); // pul sekundy po uvolneni tlacitka se resetovaci pin pripne k 5V (zrusi se resetovaci stav) digitalWrite(RST, LOW); // FET se rozepne, takze na pinu RST u ATtiny se objevi 5V delay(500); // dalsi prepis Fuse bajtu je mozny az 1 sekundu po uvolneni tlacitka // sekundu po uvolneni tlacitka modra LED zhasne digitalWrite(LEDB, HIGH); } if (SERIAL.available()) { avrisp(); } } uint8_t getch() { while (!SERIAL.available()); return SERIAL.read(); } void fill(int n) { for (int x = 0; x < n; x++) { buff[x] = getch(); } } #define PTIME 30 void prog_lamp(int state) { if (PROG_FLICKER) { // digitalWrite(LED_PMODE, state); } } uint8_t spi_transaction(uint8_t a, uint8_t b, uint8_t c, uint8_t d) { SPI.transfer(a); SPI.transfer(b); SPI.transfer(c); return SPI.transfer(d); } void empty_reply() { if (CRC_EOP == getch()) { SERIAL.print((char)STK_INSYNC); SERIAL.print((char)STK_OK); } else { error++; SERIAL.print((char)STK_NOSYNC); } } void breply(uint8_t b) { if (CRC_EOP == getch()) { SERIAL.print((char)STK_INSYNC); SERIAL.print((char)b); SERIAL.print((char)STK_OK); } else { error++; SERIAL.print((char)STK_NOSYNC); } } void get_version(uint8_t c) { switch (c) { case 0x80: breply(HWVER); break; case 0x81: breply(SWMAJ); break; case 0x82: breply(SWMIN); break; case 0x93: breply('S'); // serial programmer break; default: breply(0); } } void set_parameters() { // call this after reading paramter packet into buff[] param.devicecode = buff[0]; param.revision = buff[1]; param.progtype = buff[2]; param.parmode = buff[3]; param.polling = buff[4]; param.selftimed = buff[5]; param.lockbytes = buff[6]; param.fusebytes = buff[7]; param.flashpoll = buff[8]; // ignore buff[9] (= buff[8]) // following are 16 bits (big endian) param.eeprompoll = beget16(&buff[10]); param.pagesize = beget16(&buff[12]); param.eepromsize = beget16(&buff[14]); // 32 bits flashsize (big endian) param.flashsize = buff[16] * 0x01000000 + buff[17] * 0x00010000 + buff[18] * 0x00000100 + buff[19]; // avr devices have active low reset, at89sx are active high rst_active_high = (param.devicecode >= 0xe0); } void start_pmode() { // Reset target before driving PIN_SCK or PIN_MOSI // SPI.begin() will configure SS as output, // so SPI master mode is selected. // We have defined RESET as pin 10, // which for many arduino's is not the SS pin. // So we have to configure RESET as output here, // (reset_target() first sets the correct level) isp_bezi = true; // znacka, ze se zacalo programovat reset_target(true); pinMode(RESET, OUTPUT); SPI.begin(); SPI.beginTransaction(SPISettings(SPI_CLOCK, MSBFIRST, SPI_MODE0)); // See avr datasheets, chapter "SERIAL_PRG Programming Algorithm": // Pulse RESET after PIN_SCK is low: digitalWrite(PIN_SCK, LOW); delay(20); // discharge PIN_SCK, value arbitrally chosen reset_target(false); // Pulse must be minimum 2 target CPU clock cycles // so 100 usec is ok for CPU speeds above 20KHz delayMicroseconds(100); reset_target(true); // Send the enable programming command: delay(50); // datasheet: must be > 20 msec spi_transaction(0xAC, 0x53, 0x00, 0x00); pmode = 1; } void end_pmode() { SPI.end(); // We're about to take the target out of reset // so configure SPI pins as input pinMode(PIN_MOSI, INPUT); pinMode(PIN_SCK, INPUT); reset_target(false); pinMode(RESET, INPUT); pmode = 0; isp_bezi = false; // znacka, ze programovani skoncilo } void universal() { uint8_t ch; fill(4); ch = spi_transaction(buff[0], buff[1], buff[2], buff[3]); breply(ch); } void flash(uint8_t hilo, unsigned int addr, uint8_t data) { spi_transaction(0x40 + 8 * hilo, addr >> 8 & 0xFF, addr & 0xFF, data); } void commit(unsigned int addr) { if (PROG_FLICKER) { prog_lamp(LOW); } spi_transaction(0x4C, (addr >> 8) & 0xFF, addr & 0xFF, 0); if (PROG_FLICKER) { delay(PTIME); prog_lamp(HIGH); } } unsigned int current_page() { if (param.pagesize == 32) { return here & 0xFFFFFFF0; } if (param.pagesize == 64) { return here & 0xFFFFFFE0; } if (param.pagesize == 128) { return here & 0xFFFFFFC0; } if (param.pagesize == 256) { return here & 0xFFFFFF80; } return here; } void write_flash(int length) { fill(length); if (CRC_EOP == getch()) { SERIAL.print((char) STK_INSYNC); SERIAL.print((char) write_flash_pages(length)); } else { error++; SERIAL.print((char) STK_NOSYNC); } } uint8_t write_flash_pages(int length) { int x = 0; unsigned int page = current_page(); while (x < length) { if (page != current_page()) { commit(page); page = current_page(); } flash(LOW, here, buff[x++]); flash(HIGH, here, buff[x++]); here++; } commit(page); return STK_OK; } #define EECHUNK (32) uint8_t write_eeprom(unsigned int length) { // here is a word address, get the byte address unsigned int start = here * 2; unsigned int remaining = length; if (length > param.eepromsize) { error++; return STK_FAILED; } while (remaining > EECHUNK) { write_eeprom_chunk(start, EECHUNK); start += EECHUNK; remaining -= EECHUNK; } write_eeprom_chunk(start, remaining); return STK_OK; } // write (length) bytes, (start) is a byte address uint8_t write_eeprom_chunk(unsigned int start, unsigned int length) { // this writes byte-by-byte, // page writing may be faster (4 bytes at a time) fill(length); prog_lamp(LOW); for (unsigned int x = 0; x < length; x++) { unsigned int addr = start + x; spi_transaction(0xC0, (addr >> 8) & 0xFF, addr & 0xFF, buff[x]); delay(45); } prog_lamp(HIGH); return STK_OK; } void program_page() { char result = (char) STK_FAILED; unsigned int length = 256 * getch(); length += getch(); char memtype = getch(); // flash memory @here, (length) bytes if (memtype == 'F') { write_flash(length); return; } if (memtype == 'E') { result = (char)write_eeprom(length); if (CRC_EOP == getch()) { SERIAL.print((char) STK_INSYNC); SERIAL.print(result); } else { error++; SERIAL.print((char) STK_NOSYNC); } return; } SERIAL.print((char)STK_FAILED); return; } uint8_t flash_read(uint8_t hilo, unsigned int addr) { return spi_transaction(0x20 + hilo * 8, (addr >> 8) & 0xFF, addr & 0xFF, 0); } char flash_read_page(int length) { for (int x = 0; x < length; x += 2) { uint8_t low = flash_read(LOW, here); SERIAL.print((char) low); uint8_t high = flash_read(HIGH, here); SERIAL.print((char) high); here++; } return STK_OK; } char eeprom_read_page(int length) { // here again we have a word address int start = here * 2; for (int x = 0; x < length; x++) { int addr = start + x; uint8_t ee = spi_transaction(0xA0, (addr >> 8) & 0xFF, addr & 0xFF, 0xFF); SERIAL.print((char) ee); } return STK_OK; } void read_page() { char result = (char)STK_FAILED; int length = 256 * getch(); length += getch(); char memtype = getch(); if (CRC_EOP != getch()) { error++; SERIAL.print((char) STK_NOSYNC); return; } SERIAL.print((char) STK_INSYNC); if (memtype == 'F') result = flash_read_page(length); if (memtype == 'E') result = eeprom_read_page(length); SERIAL.print(result); } void read_signature() { if (CRC_EOP != getch()) { error++; SERIAL.print((char) STK_NOSYNC); return; } SERIAL.print((char) STK_INSYNC); uint8_t high = spi_transaction(0x30, 0x00, 0x00, 0x00); SERIAL.print((char) high); uint8_t middle = spi_transaction(0x30, 0x00, 0x01, 0x00); SERIAL.print((char) middle); uint8_t low = spi_transaction(0x30, 0x00, 0x02, 0x00); SERIAL.print((char) low); SERIAL.print((char) STK_OK); } ////////////////////////////////////////// ////////////////////////////////////////// //////////////////////////////////// //////////////////////////////////// void avrisp() { uint8_t ch = getch(); // isp_bezi = true; // znacka, ze se zacalo programovat switch (ch) { case '0': // signon error = 0; empty_reply(); break; case '1': if (getch() == CRC_EOP) { SERIAL.print((char) STK_INSYNC); SERIAL.print("AVR ISP"); SERIAL.print((char) STK_OK); } else { error++; SERIAL.print((char) STK_NOSYNC); } break; case 'A': get_version(getch()); break; case 'B': fill(20); set_parameters(); empty_reply(); break; case 'E': // extended parameters - ignore for now fill(5); empty_reply(); break; case 'P': if (!pmode) start_pmode(); empty_reply(); break; case 'U': // set address (word) here = getch(); here += 256 * getch(); empty_reply(); break; case 0x60: //STK_PROG_FLASH getch(); // low addr getch(); // high addr empty_reply(); break; case 0x61: //STK_PROG_DATA getch(); // data empty_reply(); break; case 0x64: //STK_PROG_PAGE program_page(); break; case 0x74: //STK_READ_PAGE 't' read_page(); break; case 'V': //0x56 universal(); break; case 'Q': //0x51 error = 0; end_pmode(); empty_reply(); break; case 0x75: //STK_READ_SIGN 'u' read_signature(); break; // expecting a command, not CRC_EOP // this is how we can get back in sync case CRC_EOP: error++; SERIAL.print((char) STK_NOSYNC); break; // anything else we will return STK_UNKNOWN default: error++; if (CRC_EOP == getch()) SERIAL.print((char)STK_UNKNOWN); else SERIAL.print((char)STK_NOSYNC); } // isp_bezi = false; // znacka, ze programovani skoncilo } //============================================ // Podprogram pro preprogramovani Fuse bajtu po stisku tlacitka // Prevzato a upraveno z: // AVR High-voltage Serial Fuse Reprogrammer // Adapted from code and design by Paul Willoughby 03/20/2010 // http://www.rickety.us/2010/03/arduino-avr-high-voltage-serial-programmer/ void ReFuse() { pinMode(SDI, OUTPUT); pinMode(SII, OUTPUT); pinMode(SCI, OUTPUT); pinMode(SDO, OUTPUT); delay(200); digitalWrite(RST, HIGH); // 12v Off (RST do "0") digitalWrite(PIN_VCC, LOW); // Vcc OFF delay(200); digitalWrite(SDI, LOW); digitalWrite(SII, LOW); digitalWrite(SDO, LOW); digitalWrite(PIN_VCC, HIGH); // Vcc On delayMicroseconds(40); digitalWrite(RST, LOW); // 12v On delayMicroseconds(20); pinMode(SDO, INPUT); // Set SDO to input delayMicroseconds(300); writeFuse(HFUSE, deffuse[index_bloku][2]); // zapise HFUSE podle vybraneho bloku delay(10); writeFuse(LFUSE, deffuse[index_bloku][1]); // zapise LFUSE podle vybraneho bloku delay(10); if (deffuse[index_bloku][3] != -1); // kdyz je ve vybranem bloku nadefinovana "Extend Fuse", tak ji taky zapise { writeFuse(EFUSE, deffuse[index_bloku][3]); } // po ukonceni zapisu FUSE bajtu prepne piny do rezimu ISP programatoru digitalWrite(SCI, LOW); digitalWrite(RST, HIGH); // 12v Off digitalWrite(PIN_VCC, LOW); // Vcc Off delay(500); digitalWrite(PIN_VCC, HIGH); // Vcc On // po uvolneni tlacitka se pak nastavi "digitalWrite(RST, LOW)", cimz se pripne 5V na resetovaci pin ATtiny } 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); digitalWrite(SCI, HIGH); digitalWrite(SCI, LOW); } return inBits >> 2; } void writeFuse (unsigned int fuse, byte val) { shiftOut(0x40, 0x4C); shiftOut( val, 0x2C); shiftOut(0x00, (byte) (fuse >> 8)); shiftOut(0x00, (byte) fuse); }