TinyHVSP.ino 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. //Tiny HVSP V1.4
  2. //Platine arduino uno (mini pro flashé en uno)
  3. //validé pour T13 , T25 , T45 , T84 , T85 , T24
  4. // ===================================================================================
  5. // Libraries and Definitions
  6. // ===================================================================================
  7. // Libraries
  8. #include <avr/io.h> // for GPIO
  9. #include <avr/pgmspace.h> // to store data in programm memory
  10. #include <util/delay.h> // for delays
  11. // Pin definitions
  12. #define RST_PIN PB5 //13 // 12V !RESET Pin 1 of target device
  13. #define SCI_PIN PB4 //12 // Serial Clock Input (SCI) Pin 2 of target device
  14. #define SDO_PIN PB3 //11 // Serial Data Output (SDO) Pin 7 of target device
  15. #define SII_PIN PB2 //10 // Serial Instruction Input (SII) Pin 6 of target device
  16. #define SDI_PIN PB1 //9 // Serial Data Input (SDI) Pin 5 of target device
  17. #define VCC_PIN PB0 //8 // Target VCC Pin 8 of target device
  18. #define I2C_SCL PC5 // I2C Serial Clock (SCK)
  19. #define I2C_SDA PC4 // I2C Serial Data (SDA)
  20. #define BUTTON PD7 // OK-Button
  21. #define ERRORLED PD4 //4 led rouge
  22. #define GOODLED PD3 //3 led verte
  23. // Global variables
  24. uint8_t inLFUSE, inHFUSE, inEFUSE; // for reading fuses
  25. uint8_t outLFUSE, outHFUSE, outEFUSE; // for writing fuses
  26. uint8_t inLOCK; // for reading lock bits
  27. uint16_t signature; // for reading signature
  28. // ===================================================================================
  29. // I2C Implementation
  30. // ===================================================================================
  31. // I2C macros
  32. #define I2C_SDA_HIGH() DDRC &= ~(1<<I2C_SDA) // release SDA -> pulled HIGH by resistor
  33. #define I2C_SDA_LOW() DDRC |= (1<<I2C_SDA) // SDA as output -> pulled LOW by MCU
  34. #define I2C_SCL_HIGH() DDRC &= ~(1<<I2C_SCL) // release SCL -> pulled HIGH by resistor
  35. #define I2C_SCL_LOW() DDRC |= (1<<I2C_SCL) // SCL as output -> pulled LOW by MCU
  36. #define I2C_DELAY() asm("lpm") // delay 3 clock cycles
  37. #define I2C_CLOCKOUT() I2C_SCL_HIGH();I2C_DELAY();I2C_SCL_LOW() // clock out
  38. // I2C init function
  39. void I2C_init(void) {
  40. DDRC &= ~((1<<I2C_SDA)|(1<<I2C_SCL)); // pins as input (HIGH-Z) -> lines released
  41. PORTC &= ~((1<<I2C_SDA)|(1<<I2C_SCL)); // should be LOW when as ouput
  42. }
  43. // I2C transmit one data byte to the slave, ignore ACK bit, no clock stretching allowed
  44. void I2C_write(uint8_t data) {
  45. for(uint8_t i = 8; i; i--, data<<=1) { // transmit 8 bits, MSB first
  46. (data & 0x80) ? (I2C_SDA_HIGH()) : (I2C_SDA_LOW()); // SDA HIGH if bit is 1
  47. I2C_CLOCKOUT(); // clock out -> slave reads the bit
  48. }
  49. I2C_DELAY(); // delay 3 clock cycles
  50. I2C_SDA_HIGH(); // release SDA for ACK bit of slave
  51. I2C_CLOCKOUT(); // 9th clock pulse is for the ignored ACK bit
  52. }
  53. // I2C start transmission
  54. void I2C_start(uint8_t addr) {
  55. I2C_SDA_LOW(); // start condition: SDA goes LOW first
  56. I2C_SCL_LOW(); // start condition: SCL goes LOW second
  57. I2C_write(addr); // send slave address
  58. }
  59. // I2C stop transmission
  60. void I2C_stop(void) {
  61. I2C_SDA_LOW(); // prepare SDA for LOW to HIGH transition
  62. I2C_SCL_HIGH(); // stop condition: SCL goes HIGH first
  63. I2C_SDA_HIGH(); // stop condition: SDA goes HIGH second
  64. }
  65. // ===================================================================================
  66. // OLED Implementation
  67. // ===================================================================================
  68. // OLED definitions
  69. #define OLED_ADDR 0x78 // OLED write address
  70. #define OLED_CMD_MODE 0x00 // set command mode
  71. #define OLED_DAT_MODE 0x40 // set data mode
  72. #define OLED_INIT_LEN 9 // length of init command array
  73. // OLED 5x8 pixels character set
  74. const uint8_t OLED_FONT[] PROGMEM = {
  75. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x07, 0x00, 0x07, 0x00,
  76. 0x14, 0x7F, 0x14, 0x7F, 0x14, 0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x23, 0x13, 0x08, 0x64, 0x62,
  77. 0x36, 0x49, 0x55, 0x22, 0x50, 0x00, 0x05, 0x03, 0x00, 0x00, 0x00, 0x1C, 0x22, 0x41, 0x00,
  78. 0x00, 0x41, 0x22, 0x1C, 0x00, 0x14, 0x08, 0x3E, 0x08, 0x14, 0x08, 0x08, 0x3E, 0x08, 0x08,
  79. 0x00, 0x00, 0xA0, 0x60, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x60, 0x60, 0x00, 0x00,
  80. 0x20, 0x10, 0x08, 0x04, 0x02, 0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, 0x42, 0x7F, 0x40, 0x00,
  81. 0x42, 0x61, 0x51, 0x49, 0x46, 0x21, 0x41, 0x45, 0x4B, 0x31, 0x18, 0x14, 0x12, 0x7F, 0x10,
  82. 0x27, 0x45, 0x45, 0x45, 0x39, 0x3C, 0x4A, 0x49, 0x49, 0x30, 0x01, 0x71, 0x09, 0x05, 0x03,
  83. 0x36, 0x49, 0x49, 0x49, 0x36, 0x06, 0x49, 0x49, 0x29, 0x1E, 0x00, 0x36, 0x36, 0x00, 0x00,
  84. 0x00, 0x56, 0x36, 0x00, 0x00, 0x08, 0x14, 0x22, 0x41, 0x00, 0x14, 0x14, 0x14, 0x14, 0x14,
  85. 0x00, 0x41, 0x22, 0x14, 0x08, 0x02, 0x01, 0x51, 0x09, 0x06, 0x32, 0x49, 0x59, 0x51, 0x3E,
  86. 0x7C, 0x12, 0x11, 0x12, 0x7C, 0x7F, 0x49, 0x49, 0x49, 0x36, 0x3E, 0x41, 0x41, 0x41, 0x22,
  87. 0x7F, 0x41, 0x41, 0x22, 0x1C, 0x7F, 0x49, 0x49, 0x49, 0x41, 0x7F, 0x09, 0x09, 0x09, 0x01,
  88. 0x3E, 0x41, 0x49, 0x49, 0x7A, 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00, 0x41, 0x7F, 0x41, 0x00,
  89. 0x20, 0x40, 0x41, 0x3F, 0x01, 0x7F, 0x08, 0x14, 0x22, 0x41, 0x7F, 0x40, 0x40, 0x40, 0x40,
  90. 0x7F, 0x02, 0x0C, 0x02, 0x7F, 0x7F, 0x04, 0x08, 0x10, 0x7F, 0x3E, 0x41, 0x41, 0x41, 0x3E,
  91. 0x7F, 0x09, 0x09, 0x09, 0x06, 0x3E, 0x41, 0x51, 0x21, 0x5E, 0x7F, 0x09, 0x19, 0x29, 0x46,
  92. 0x46, 0x49, 0x49, 0x49, 0x31, 0x01, 0x01, 0x7F, 0x01, 0x01, 0x3F, 0x40, 0x40, 0x40, 0x3F,
  93. 0x1F, 0x20, 0x40, 0x20, 0x1F, 0x3F, 0x40, 0x38, 0x40, 0x3F, 0x63, 0x14, 0x08, 0x14, 0x63,
  94. 0x07, 0x08, 0x70, 0x08, 0x07, 0x61, 0x51, 0x49, 0x45, 0x43, 0x00, 0x7F, 0x41, 0x41, 0x00,
  95. 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x41, 0x41, 0x7F, 0x00, 0x04, 0x02, 0x01, 0x02, 0x04,
  96. 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x01, 0x02, 0x04, 0x00, 0x20, 0x54, 0x54, 0x54, 0x78,
  97. 0x7F, 0x48, 0x44, 0x44, 0x38, 0x38, 0x44, 0x44, 0x44, 0x20, 0x38, 0x44, 0x44, 0x48, 0x7F,
  98. 0x38, 0x54, 0x54, 0x54, 0x18, 0x08, 0x7E, 0x09, 0x01, 0x02, 0x18, 0xA4, 0xA4, 0xA4, 0x7C,
  99. 0x7F, 0x08, 0x04, 0x04, 0x78, 0x00, 0x44, 0x7D, 0x40, 0x00, 0x40, 0x80, 0x84, 0x7D, 0x00,
  100. 0x7F, 0x10, 0x28, 0x44, 0x00, 0x00, 0x41, 0x7F, 0x40, 0x00, 0x7C, 0x04, 0x18, 0x04, 0x78,
  101. 0x7C, 0x08, 0x04, 0x04, 0x78, 0x38, 0x44, 0x44, 0x44, 0x38, 0xFC, 0x24, 0x24, 0x24, 0x18,
  102. 0x18, 0x24, 0x24, 0x18, 0xFC, 0x7C, 0x08, 0x04, 0x04, 0x08, 0x48, 0x54, 0x54, 0x54, 0x20,
  103. 0x04, 0x3F, 0x44, 0x40, 0x20, 0x3C, 0x40, 0x40, 0x20, 0x7C, 0x1C, 0x20, 0x40, 0x20, 0x1C,
  104. 0x3C, 0x40, 0x30, 0x40, 0x3C, 0x44, 0x28, 0x10, 0x28, 0x44, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C,
  105. 0x44, 0x64, 0x54, 0x4C, 0x44, 0x08, 0x36, 0x41, 0x41, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00,
  106. 0x00, 0x41, 0x41, 0x36, 0x08, 0x08, 0x04, 0x08, 0x10, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
  107. };
  108. // OLED init settings
  109. const uint8_t OLED_INIT_CMD[] PROGMEM = {
  110. 0xC8, 0xA1, // flip screen
  111. 0xA8, 0x1F, // set multiplex ratio
  112. 0xDA, 0x02, // set com pins hardware configuration
  113. 0x8D, 0x14, // set DC-DC enable
  114. 0xAF // display on
  115. };
  116. // OLED variables
  117. uint8_t OLED_x, OLED_y; // current cursor position
  118. // OLED init function
  119. void OLED_init(void) {
  120. I2C_init(); // initialize I2C first
  121. I2C_start(OLED_ADDR); // start transmission to OLED
  122. I2C_write(OLED_CMD_MODE); // set command mode
  123. for(uint8_t i = 0; i < OLED_INIT_LEN; i++)
  124. I2C_write(pgm_read_byte(&OLED_INIT_CMD[i])); // send the command bytes
  125. I2C_stop(); // stop transmission
  126. }
  127. // OLED set the cursor
  128. void OLED_setCursor(uint8_t xpos, uint8_t ypos) {
  129. I2C_start(OLED_ADDR); // start transmission to OLED
  130. I2C_write(OLED_CMD_MODE); // set command mode
  131. I2C_write(xpos & 0x0F); // set low nibble of start column
  132. I2C_write(0x10 | (xpos >> 4)); // set high nibble of start column
  133. I2C_write(0xB0 | (ypos & 0x07)); // set start page
  134. I2C_stop(); // stop transmission
  135. OLED_x = xpos; OLED_y = ypos; // set the cursor variables
  136. }
  137. // OLED clear line
  138. void OLED_clearLine(uint8_t line) {
  139. OLED_setCursor(0, line); // set cursor to line start
  140. I2C_start(OLED_ADDR); // start transmission to OLED
  141. I2C_write(OLED_DAT_MODE); // set data mode
  142. for(uint8_t i=128; i; i--) I2C_write(0x00); // clear the line
  143. I2C_stop(); // stop transmission
  144. }
  145. // OLED clear screen
  146. void OLED_clearScreen(void) {
  147. for(uint8_t i=0; i<4; i++) // 4 lines
  148. OLED_clearLine(i); // clear line
  149. }
  150. // OLED print a single character
  151. void OLED_printChar(char c) {
  152. uint16_t ptr = c - 32; // character pointer
  153. ptr += ptr << 2; // -> ptr = (ch - 32) * 5;
  154. I2C_write(0x00); // write space between characters
  155. for(uint8_t i=5 ; i; i--) I2C_write(pgm_read_byte(&OLED_FONT[ptr++]));
  156. OLED_x += 6; // update cursor
  157. if(OLED_x > 122) { // line end ?
  158. I2C_stop(); // stop data transmission
  159. OLED_setCursor(0,++OLED_y); // set next line start
  160. I2C_start(OLED_ADDR); // start transmission to OLED
  161. I2C_write(OLED_DAT_MODE); // set data mode
  162. }
  163. }
  164. // OLED print a string from program memory
  165. void OLED_printPrg(const char* p) {
  166. I2C_start(OLED_ADDR); // start transmission to OLED
  167. I2C_write(OLED_DAT_MODE); // set data mode
  168. char ch = pgm_read_byte(p); // read first character from program memory
  169. while(ch) { // repeat until string terminator
  170. OLED_printChar(ch); // print character on OLED
  171. ch = pgm_read_byte(++p); // read next character
  172. }
  173. I2C_stop(); // stop transmission
  174. }
  175. // OLED convert byte nibble into hex character and prints it
  176. void OLED_printNibble(uint8_t nibble) {
  177. char c;
  178. if(nibble <= 9) c = '0' + nibble;
  179. else c = 'A' + nibble - 10;
  180. OLED_printChar(c);
  181. }
  182. // OLED print byte as hex
  183. void OLED_printHex(uint8_t value) {
  184. I2C_start(OLED_ADDR); // start transmission to OLED
  185. I2C_write(OLED_DAT_MODE); // set data mode
  186. OLED_printNibble(value >> 4); // print high nibble
  187. OLED_printNibble(value & 0x0F); // print low nibble
  188. I2C_stop(); // stop transmission
  189. }
  190. // ===================================================================================
  191. // High-Voltage Serial Programmer Implementation
  192. // ===================================================================================
  193. // Desired fuse configuration (defaults) for ATtiny13
  194. #define T13_LFUSE 0x6A
  195. #define T13_HFUSE 0xFF
  196. // Desired fuse configuration (defaults) for ATtiny25/45/85
  197. #define Tx5_LFUSE 0x62
  198. #define Tx5_HFUSE 0xDF
  199. // Desired fuse configuration (defaults) for ATtiny24/44/84
  200. #define Tx4_LFUSE 0xE2
  201. #define Tx4_HFUSE 0xDF
  202. // Signatures
  203. #define T13_SIG 0x9007
  204. #define T15_SIG 0x9006
  205. #define T24_SIG 0x910b
  206. #define T25_SIG 0x9108
  207. #define T44_SIG 0x9207
  208. #define T45_SIG 0x9206
  209. #define T84_SIG 0x930c
  210. #define T85_SIG 0x930b
  211. // HVSP macros
  212. #define HVSP_RST_12V() PORTB &= ~(1<<RST_PIN)
  213. #define HVSP_RST_LOW() PORTB |= (1<<RST_PIN)
  214. #define HVSP_VCC_ON() PORTB |= (1<<VCC_PIN)
  215. #define HVSP_VCC_OFF() PORTB &= ~(1<<VCC_PIN)
  216. #define HVSP_SCI_HIGH() PORTB |= (1<<SCI_PIN)
  217. #define HVSP_SCI_LOW() PORTB &= ~(1<<SCI_PIN)
  218. #define HVSP_SII_HIGH() PORTB |= (1<<SII_PIN)
  219. #define HVSP_SII_LOW() PORTB &= ~(1<<SII_PIN)
  220. #define HVSP_SDI_HIGH() PORTB |= (1<<SDI_PIN)
  221. #define HVSP_SDI_LOW() PORTB &= ~(1<<SDI_PIN)
  222. #define HVSP_SDO_REL() DDRB &= ~(1<<SDO_PIN)
  223. #define HVSP_SDO_BIT (PINB & (1<<SDO_PIN))
  224. #define HVSP_CLOCKOUT() {HVSP_SCI_HIGH(); HVSP_SCI_LOW();}
  225. //LEDs
  226. void error_led(void) {
  227. PORTD |= (1<<ERRORLED);
  228. }
  229. void good_led(void) {
  230. PORTD |= (1<<GOODLED);
  231. }
  232. void off_led(void) {
  233. PORTD &= ~(1<<ERRORLED);
  234. PORTD &= ~(1<<GOODLED);
  235. }
  236. // HVSP set up all control lines
  237. void HVSP_init(void) {
  238. PORTB &= ~((1<<SCI_PIN) | (1<<SDO_PIN) | (1<<SII_PIN) | (1<<SDI_PIN) | (1<<VCC_PIN));
  239. PORTB |= (1<<RST_PIN);
  240. DDRB |= (1<<SCI_PIN) | (1<<SDO_PIN) | (1<<SII_PIN) | (1<<SDI_PIN) | (1<<VCC_PIN) | (1<<RST_PIN);
  241. }
  242. // HVSP release all control lines (except RST)
  243. void HVSP_release(void) {
  244. PORTB &= ~((1<<SCI_PIN) | (1<<SDO_PIN) | (1<<SII_PIN) | (1<<SDI_PIN) | (1<<VCC_PIN));
  245. DDRB &= ~((1<<SCI_PIN) | (1<<SDO_PIN) | (1<<SII_PIN) | (1<<SDI_PIN) | (1<<VCC_PIN));
  246. }
  247. // HVSP enter the programming mode
  248. void HVSP_enterProgMode(void) {
  249. HVSP_init(); // initialize control lines
  250. HVSP_VCC_ON(); // apply VCC to target
  251. _delay_us(20); // wait 20us
  252. HVSP_RST_12V(); // apply 12V to RESET pin of target
  253. _delay_us(10); // wait 10us
  254. HVSP_SDO_REL(); // release SDO line
  255. _delay_us(300); // delay 300us
  256. }
  257. // HVSP exit the programming mode
  258. void HVSP_exitProgMode(void) {
  259. HVSP_SCI_LOW(); // set SCI line LOW
  260. HVSP_RST_LOW(); // RESET to 0V
  261. HVSP_VCC_OFF(); // power down the target
  262. HVSP_release(); // release all control lines
  263. }
  264. // HVSP send instruction and receive reply
  265. uint8_t HVSP_sendInstr(uint8_t SDI_BYTE, uint8_t SII_BYTE) {
  266. uint8_t SDO_BYTE = 0; // received byte from target
  267. // wait until SDO_PIN goes high (target ready) or 10ms time-out
  268. for(uint8_t i=10; i; i--) { // 10 x 1ms
  269. if(HVSP_SDO_BIT) break; // check SDO line
  270. _delay_ms(1); // delay 1ms
  271. }
  272. // send start bit (SDI/SII = '0')
  273. HVSP_SDI_LOW(); // SDI = '0'
  274. HVSP_SII_LOW(); // SII = '0'
  275. HVSP_CLOCKOUT(); // SCI HIGH, SCI LOW
  276. // send instruction bytes, MSB first; receive reply
  277. for(uint8_t i=8; i; i--) {
  278. (SDI_BYTE & 0x80) ? (HVSP_SDI_HIGH()) : (HVSP_SDI_LOW());
  279. (SII_BYTE & 0x80) ? (HVSP_SII_HIGH()) : (HVSP_SII_LOW());
  280. SDI_BYTE <<= 1;
  281. SII_BYTE <<= 1;
  282. SDO_BYTE <<= 1;
  283. if(HVSP_SDO_BIT) SDO_BYTE |= 1;
  284. HVSP_CLOCKOUT();
  285. }
  286. // send end bits (two times SDI/SII = '0')
  287. HVSP_SDI_LOW(); // SDI = '0'
  288. HVSP_SII_LOW(); // SII = '0'
  289. HVSP_CLOCKOUT(); // SCI HIGH, SCI LOW
  290. HVSP_CLOCKOUT(); // SCI HIGH, SCI LOW
  291. return SDO_BYTE; // return read SDO byte
  292. }
  293. // HVSP read signature of target device
  294. void HVSP_readSignature(void) {
  295. HVSP_sendInstr(0x08, 0x4C); // Instr1: read sig/calib command
  296. HVSP_sendInstr(0x01, 0x0C); // Instr2: select signature byte 1
  297. HVSP_sendInstr(0x00, 0x68); // Instr3: signature, not calibration
  298. signature = HVSP_sendInstr(0x00, 0x6C); // Instr4: read the signature byte
  299. signature <<= 8; // shift left 8 bits
  300. HVSP_sendInstr(0x02, 0x0C); // Instr2: select signature byte 2
  301. HVSP_sendInstr(0x00, 0x68); // Instr3: signature, not calibration
  302. signature |= HVSP_sendInstr(0x00, 0x6C);// Instr4: read the signature byte
  303. }
  304. // HVSP read lock bits
  305. void HVSP_readLock(void) {
  306. HVSP_sendInstr(0x04, 0x4C); // Instr1: read fuses/lock command
  307. HVSP_sendInstr(0x00, 0x78); // Instr2: select lock bits
  308. inLOCK = HVSP_sendInstr(0x00, 0x7C); // Instr3: read lock bits
  309. inLOCK &= 0x03; // mask the lock bits
  310. }
  311. // HVSP read current fuse settings from target device
  312. void HVSP_readFuses(void) {
  313. HVSP_sendInstr(0x04, 0x4C); // Instr1: read fuses/lock command
  314. HVSP_sendInstr(0x00, 0x68); // Instr2: select low fuse
  315. inLFUSE = HVSP_sendInstr(0x00, 0x6C); // Instr3: read low fuse
  316. HVSP_sendInstr(0x00, 0x7A); // Instr2: select high fuse
  317. inHFUSE = HVSP_sendInstr(0x00, 0x7E); // Instr3: read high fuse
  318. HVSP_sendInstr(0x00, 0x6A); // Instr2: select extended fuse
  319. inEFUSE = HVSP_sendInstr(0x00, 0x6E); // Instr3: read extended fuse
  320. }
  321. // HVSP write fuse settings to target device
  322. void HVSP_writeFuses(void) {
  323. HVSP_sendInstr(0x40, 0x4C); // Instr1: write fuses/lock command
  324. HVSP_sendInstr(outLFUSE, 0x2C); // Instr2: write low fuse
  325. HVSP_sendInstr(0x00, 0x64); // Instr3: select low fuse
  326. HVSP_sendInstr(0x00, 0x6C); // Instr4: select low fuse
  327. HVSP_sendInstr(outHFUSE, 0x2C); // Instr2: write high fuse
  328. HVSP_sendInstr(0x00, 0x74); // Instr3: select high fuse
  329. HVSP_sendInstr(0x00, 0x7C); // Instr4: select high fuse
  330. HVSP_sendInstr(outEFUSE & 0x01, 0x2C); // Instr2: write extended fuse
  331. HVSP_sendInstr(0x00, 0x66); // Instr3: select extended fuse
  332. HVSP_sendInstr(0x00, 0x6E); // Instr4: select extended fuse
  333. while(!HVSP_SDO_BIT); // wait for write cycle to finish
  334. }
  335. // HVSP perform chip erase
  336. void HVSP_eraseChip(void) {
  337. HVSP_sendInstr(0x80, 0x4C); // Instr1: chip erase command
  338. HVSP_sendInstr(0x00, 0x64); // Instr2
  339. HVSP_sendInstr(0x00, 0x6C); // Instr3
  340. while(!HVSP_SDO_BIT); // wait for the chip erase cycle to finish
  341. HVSP_sendInstr(0x00, 0x4C); // no operation command to finish chip erase
  342. }
  343. // ===================================================================================
  344. // Additional Functions
  345. // ===================================================================================
  346. // Text strings stored in program memory
  347. const char CurrentFuseStr[] PROGMEM = "Current fuse settings";
  348. const char LowStr[] PROGMEM = "l: ";
  349. const char HighStr[] PROGMEM = " - h: ";
  350. const char ExtendedStr[] PROGMEM = " - e: ";
  351. // Print current fuse settings on the OLED
  352. void printFuses() {
  353. OLED_setCursor(0,1); OLED_printPrg(CurrentFuseStr);
  354. OLED_printPrg(LowStr); OLED_printHex(inLFUSE);
  355. OLED_printPrg(HighStr); OLED_printHex(inHFUSE);
  356. OLED_printPrg(ExtendedStr); OLED_printHex(inEFUSE);
  357. }
  358. // Wait until OK-Button was pressed
  359. void waitButton() {
  360. while(~PIND & (1<<BUTTON)); // wait for button released
  361. _delay_ms(10); // debounce
  362. while( PIND & (1<<BUTTON)); // wait for button pressed
  363. }
  364. // ===================================================================================
  365. // Main Function
  366. // ===================================================================================
  367. // Text strings stored in program memory
  368. const char TitleScreen[] PROGMEM =
  369. "Tiny HVSP Version 1.5"
  370. "Insert ATtiny into "
  371. "the socket and press "
  372. "OK-Button to continue";
  373. const char ErrorScreen[] PROGMEM =
  374. "Check correct place- "
  375. "ment of the chip and "
  376. "press <OK> to retry. ";
  377. const char EraseScreen[] PROGMEM =
  378. "Error burning fuses !"
  379. "Press <OK> to perform"
  380. "a chip erase and "
  381. "retry burning fuses. ";
  382. const char DetectedStr[] PROGMEM = "Detected: ";
  383. const char ATtinyStr[] PROGMEM = "ATtiny";
  384. const char ErrorStr[] PROGMEM = " Error !";
  385. const char DefaultStr[] PROGMEM = "<OK> to burn defaults";
  386. const char BurnedStr[] PROGMEM = "Fuses burned ";
  387. const char QuitStr[] PROGMEM = "Press <OK> to quit. ";
  388. int main(void) {
  389. // Setup
  390. DDRB |= (1<<RST_PIN); // RST pin as ouput
  391. PORTB |= (1<<RST_PIN); // RST HIGH -> shut off 12V
  392. PORTD |= (1<<BUTTON); // pullup on button pin
  393. DDRD |= (1<<ERRORLED); // errorled as output
  394. DDRD |= (1<<GOODLED); // goodled as outpu
  395. PORTD &= ~(1<<ERRORLED);
  396. outEFUSE = 0xFF; // extended fuse default
  397. OLED_init(); // setup I2C OLED
  398. OLED_clearScreen(); // clear screen
  399. off_led();
  400. // Loop
  401. while(1) {
  402. // Print title screen
  403. OLED_setCursor(0,0);
  404. OLED_printPrg(TitleScreen);
  405. // Start detection of device and repeat until positive detection
  406. uint8_t chipDetected = 0; // assume negative detection by now
  407. while(!chipDetected) { // repeat until a valid chip was detected
  408. waitButton(); // wait for OK-Button pressed
  409. chipDetected = 1; // assume positive detection by now
  410. HVSP_enterProgMode(); // start programming mode
  411. HVSP_readSignature(); // read device signature
  412. // Prepare to show information on OLED
  413. OLED_setCursor(0,0);
  414. OLED_printPrg(DetectedStr);
  415. // Make settings depending on detected device
  416. switch(signature) {
  417. case T13_SIG: OLED_printPrg(ATtinyStr);
  418. OLED_printHex(0x13);
  419. outLFUSE=T13_LFUSE;
  420. outHFUSE=T13_HFUSE;
  421. //good_led();
  422. break;
  423. case T24_SIG: OLED_printPrg(ATtinyStr);
  424. OLED_printHex(0x24);
  425. outLFUSE=Tx4_LFUSE;
  426. outHFUSE=Tx4_HFUSE;
  427. //good_led();
  428. break;
  429. case T25_SIG: OLED_printPrg(ATtinyStr);
  430. OLED_printHex(0x25);
  431. outLFUSE=Tx5_LFUSE;
  432. outHFUSE=Tx5_HFUSE;
  433. //good_led();
  434. break;
  435. case T44_SIG: OLED_printPrg(ATtinyStr);
  436. OLED_printHex(0x44);
  437. outLFUSE=Tx5_LFUSE;
  438. outHFUSE=Tx5_HFUSE;
  439. //good_led();
  440. break;
  441. case T45_SIG: OLED_printPrg(ATtinyStr);
  442. OLED_printHex(0x45);
  443. outLFUSE=Tx5_LFUSE;
  444. outHFUSE=Tx5_HFUSE;
  445. //good_led();
  446. break;
  447. case T84_SIG: OLED_printPrg(ATtinyStr);
  448. OLED_printHex(0x84);
  449. outLFUSE=Tx4_LFUSE;
  450. outHFUSE=Tx4_HFUSE;
  451. //good_led();
  452. break;
  453. case T85_SIG: OLED_printPrg(ATtinyStr);
  454. OLED_printHex(0x85);
  455. outLFUSE=Tx5_LFUSE;
  456. outHFUSE=Tx5_HFUSE;
  457. //good_led();
  458. break;
  459. default: OLED_printPrg(ErrorStr);
  460. OLED_setCursor(0,1);
  461. OLED_printPrg(ErrorScreen);
  462. HVSP_exitProgMode();
  463. chipDetected = 0;
  464. error_led();
  465. break;
  466. }
  467. }
  468. // Read and show detected fuse settings on OLED
  469. HVSP_readFuses(); // read current fuse setting
  470. printFuses(); // show detected fuse settings
  471. OLED_printPrg(DefaultStr);
  472. // Write and read back fuses
  473. waitButton(); // wait for OK-Button pressed
  474. HVSP_writeFuses(); // write default fuse settings
  475. HVSP_readFuses(); // read back fuse settings
  476. // Check if fuses were burned correctly
  477. if( (inLFUSE != outLFUSE) | (inHFUSE != outHFUSE) ) {
  478. OLED_setCursor(0,0);
  479. OLED_printPrg(EraseScreen);
  480. waitButton(); // wait for OK-Button pressed
  481. HVSP_eraseChip(); // perform chip erase
  482. HVSP_writeFuses(); // write default fuse settings
  483. HVSP_readFuses(); // read back fuse settings
  484. }
  485. HVSP_exitProgMode(); // exit programming mode
  486. // Write information on OLED
  487. OLED_setCursor(0,0);
  488. OLED_printPrg(BurnedStr);
  489. printFuses();
  490. OLED_printPrg(QuitStr);
  491. good_led();
  492. waitButton(); // wait for OK-Button pressed
  493. off_led();
  494. }
  495. }