You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

894 lines
24 KiB

4 years ago
  1. /**************************************************
  2. * TPI programmer for ATtiny4/5/9/10/20/40
  3. *
  4. * Make the connections as shown below.
  5. *
  6. * To use:
  7. ***** Buad rate must be set to 9600 ****
  8. *
  9. * - Upload to arduino and power off
  10. * - Connect ATtiny10 as shown
  11. * - Power on and open the serial monitor
  12. * - If things are working so far you should
  13. * see "NVM enabled" and "ATtiny10/20/40 connected".
  14. * - Input one-letter commands via serial monitor:
  15. *
  16. * D = dump memory. Displays all current memory
  17. * on the chip
  18. *
  19. * E = erase chip. Erases all program memory
  20. * automatically done at time of programming
  21. *
  22. * P = write program. After sending this, paste
  23. * the program from the hex file into the
  24. * serial monitor.
  25. *
  26. * S = set fuse. follow the instructions to set
  27. * one of the three fuses.
  28. *
  29. * C = clear fuse. follow the instructions to clear
  30. * one of the three fuses.
  31. *
  32. * L = Set Lock Bits No further programming & verification
  33. * possible
  34. *
  35. * H = Toggle High Voltage Programming
  36. *
  37. * T = Toggle +12v enabled by High, or Low
  38. *
  39. * R/r = Quick reset
  40. *
  41. * - Finally, power off the arduino and remove the
  42. * Attiny10/20/40
  43. *
  44. *
  45. * Arduino ATtiny10 *
  46. * ----------+ +---------------- *
  47. * (SS#) 10 |--[R]-----| 6 (RESET#/PB3) *
  48. * | | *
  49. * (MOSI) 11 |--[R]--+--| 1 (TPIDATA/PB0) *
  50. * | | | *
  51. * (MISO) 12 |--[R]--+ | *
  52. * | | *
  53. * (SCK) 13 |--[R]-----| 3 (TPICLK/PB1) *
  54. * ----------+ +---------------- *
  55. * *
  56. * ----------+ +---------------- *
  57. * (HVP) 9 |--- | 6 (RESET#/PB3) *
  58. * | | *
  59. * *
  60. * -[R]- = a 220 - 1K Ohm resistor *
  61. * *
  62. * this picture : 2011/12/08 by pcm1723 *
  63. * modified :2015/02/27 by KD *
  64. * *
  65. * thanks to pcm1723 for tpitest.pde upon which *
  66. * this is based *
  67. **************************************************
  68. Updates:
  69. Apr 02, 2018: Ksdsksd@gmail.com
  70. * Added Lock bit setting to main menu
  71. Jan 23, 2017: Ksdsksd@gmail.com
  72. * Thanks to InoueTaichi Fixed incorrect #define Tiny40
  73. Mar 05, 2015: Ksdsksd@gamil.com
  74. * Added notifications to setting and clearing the system flags.
  75. Feb 23, 2015: Ksdsksd@gamil.com
  76. * Changed the programmer Diagram, This is the config I use, and get a sucessful programming of a tiny10 at 9600 baud.
  77. Mar 22, 2014: Ksdsksd@gmail.com
  78. * Added the quick reset to high before resetting the device.
  79. * Added code to stop the SPI and float the pins for testing the device while connected.
  80. Mar 20, 2014: Ksdsksd@gmail.com
  81. * Added a quick reset by sending 'r' or 'R' via the serial monitor.
  82. * Added a High voltage programming option from pin 9, toggled by 'H'
  83. * Added a High/low option for providing 12v to the reset pin, toggled by 'T'
  84. Mar 17, 2014: Ksdsksd@gmail.com
  85. * Had some trouble with the nibbles being swapped when programming on the 10 & 20,
  86. added b1,b2 to hold the serial data before calling byteval()
  87. * Added Nat Blundell's patch to the code
  88. Apr 10, 2013: Ksdsksd@gmail.com
  89. * Applied Fix for setting and clearing flags
  90. Feb 7, 2013: Ksdsksd@gmail.com
  91. * Fixed programming timer, had intitial start at zero instead of current time.
  92. Dec 11, 2012: Ksdsksd@gmail.com
  93. * Added detect and programming for 4/5/9
  94. Dec 5-6, 2012: Ksdsksd@gmail.com
  95. * Incorperated read, and verify into program. Now have no program size limitation by using 328p.
  96. * Changed the outHex routines consolidated them into 1, number to be printed, and number of nibbles
  97. * Added a type check to distinguish between Tiny10/20/40
  98. * Added an auto word size check to ensure that there is the proper amount of words written for a 10/20/40
  99. * Removed Read program, Verify, and Finish from options
  100. * Changed baud rate to 19200 for delay from data written to the chip, to prevent serial buffer overrun.
  101. Oct 5, 2012: Ksdsksd@gmail.com
  102. *** Noticed that when programming, the verification fails
  103. at times by last 1-2 bytes programmed, and the Tiny would act erratic.
  104. Quick fix was adding 3 NOP's to the end the Tiny's code, and ignoring the errors, the Tiny then performed as expected.
  105. Oct 4, 2012: Ksdsksd@gmail.com
  106. * Moved all Serial printed strings to program space
  107. * Added code to detect Tiny20
  108. */
  109. #include <SPI.h>
  110. #include "pins_arduino.h"
  111. // define the instruction set bytes
  112. #define SLD 0x20
  113. #define SLDp 0x24
  114. #define SST 0x60
  115. #define SSTp 0x64
  116. #define SSTPRH 0x69
  117. #define SSTPRL 0x68
  118. // see functions below ////////////////////////////////
  119. // SIN 0b0aa1aaaa replace a with 6 address bits
  120. // SOUT 0b1aa1aaaa replace a with 6 address bits
  121. // SLDCS 0b1000aaaa replace a with address bits
  122. // SSTCS 0b1100aaaa replace a with address bits
  123. ///////////////////////////////////////////////////////
  124. #define SKEY 0xE0
  125. #define NVM_PROGRAM_ENABLE 0x1289AB45CDD888FFULL // the ULL means unsigned long long
  126. #define NVMCMD 0x33
  127. #define NVMCSR 0x32
  128. #define NVM_NOP 0x00
  129. #define NVM_CHIP_ERASE 0x10
  130. #define NVM_SECTION_ERASE 0x14
  131. #define NVM_WORD_WRITE 0x1D
  132. #define HVReset 9
  133. #define Tiny4_5 10
  134. #define Tiny9 1
  135. #define Tiny10 1
  136. #define Tiny20 2
  137. #define Tiny40 4
  138. #define TimeOut 1
  139. #define HexError 2
  140. #define TooLarge 3
  141. // represents the current pointer register value
  142. unsigned short adrs = 0x0000;
  143. // used for storing a program file
  144. uint8_t data[16]; //program data
  145. unsigned int progSize = 0; //program size in bytes
  146. // used for various purposes
  147. long startTime;
  148. int timeout;
  149. uint8_t b, b1, b2, b3;
  150. boolean idChecked;
  151. boolean correct;
  152. char type; // type of chip connected 1 = Tiny10, 2 = Tiny20
  153. char HVP = 0;
  154. char HVON = 0;
  155. void setup(){
  156. // set up serial
  157. Serial.begin(9600); // you cant increase this, it'll overrun the buffer
  158. // set up SPI
  159. /* SPI.begin();
  160. SPI.setBitOrder(LSBFIRST);
  161. SPI.setDataMode(SPI_MODE0);
  162. SPI.setClockDivider(SPI_CLOCK_DIV32);
  163. */ start_tpi();
  164. pinMode(HVReset, OUTPUT);
  165. // initialize memory pointer register
  166. setPointer(0x0000);
  167. timeout = 20000;
  168. idChecked = false;
  169. } // end setup()
  170. void hvserial()
  171. {
  172. if(HVP)
  173. Serial.println(F("***High Voltage Programming Enabled***"));
  174. else
  175. Serial.println(F("High Voltage Programming Disabled"));
  176. Serial.print(F("Pin 9 "));
  177. Serial.print(HVON?F("HIGH"):F("LOW"));
  178. Serial.print(F(" supplies 12v"));
  179. }
  180. void hvReset(char highLow)
  181. {
  182. if(HVP)
  183. {
  184. if(HVON) //if high enables 12v
  185. highLow = !highLow; // invert the typical reset
  186. digitalWrite(HVReset, highLow);
  187. }
  188. else
  189. digitalWrite(SS, highLow);
  190. }
  191. void quickReset()
  192. {
  193. digitalWrite(SS,HIGH);
  194. delay(1);
  195. digitalWrite(SS,LOW);
  196. delay(10);
  197. digitalWrite(SS,HIGH);
  198. }
  199. void start_tpi() {
  200. SPI.begin();
  201. SPI.setBitOrder(LSBFIRST);
  202. SPI.setDataMode(SPI_MODE0);
  203. SPI.setClockDivider(SPI_CLOCK_DIV32);
  204. // enter TPI programming mode
  205. hvReset(LOW);
  206. // digitalWrite(SS, LOW); // assert RESET on tiny
  207. delay(1); // t_RST min = 400 ns @ Vcc = 5 V
  208. SPI.transfer(0xff); // activate TPI by emitting
  209. SPI.transfer(0xff); // 16 or more pulses on TPICLK
  210. SPI.transfer(0xff); // while holding TPIDATA to "1"
  211. writeCSS(0x02, 0x04); // TPIPCR, guard time = 8bits (default=128)
  212. send_skey(NVM_PROGRAM_ENABLE); // enable NVM interface
  213. // wait for NVM to be enabled
  214. while((readCSS(0x00) & 0x02) < 1){
  215. // wait
  216. }
  217. Serial.println(F("NVM enabled"));
  218. }
  219. void setLockBits(){
  220. Serial.print(F("Locking... Are you sure? Y/N"));
  221. while(Serial.available() < 1);
  222. char yn = Serial.read();
  223. if(yn == 'n' || yn == 'N')
  224. return;
  225. setPointer(0x3F00);
  226. writeIO(NVMCMD, NVM_WORD_WRITE);
  227. tpi_send_byte(SSTp);
  228. tpi_send_byte(0);
  229. tpi_send_byte(SSTp);
  230. tpi_send_byte(0xFF);
  231. while((readIO(NVMCSR) & (1<<7)) != 0x00);
  232. Serial.print(F("Locked..."));
  233. }
  234. void loop(){
  235. if(!idChecked){
  236. // start_tpi();
  237. checkID();
  238. idChecked = true;
  239. finish();
  240. }
  241. // when ready, send ready signal '.' and wait
  242. Serial.print(F("\n>"));
  243. while(Serial.available() < 1){
  244. // wait
  245. }
  246. start_tpi();
  247. // the first byte is a command
  248. //** 'P' = program the ATtiny using the read program
  249. //** 'D' = dump memory to serial monitor
  250. //** 'E' = erase chip. erases current program memory.(done automatically by 'P')
  251. //** 'S' = set fuse
  252. //** 'C' = clear fuse
  253. //** 'L' = Set Lock Bits
  254. char comnd = Sread();
  255. switch( comnd ){
  256. case 'r':
  257. case'R':
  258. quickReset();
  259. break;
  260. case 'D':
  261. dumpMemory();
  262. break;
  263. case 'H':
  264. HVP = !HVP;
  265. hvserial();
  266. break;
  267. case 'T':
  268. HVON = !HVON;
  269. hvserial();
  270. break;
  271. case 'P':
  272. if(!writeProgram()){
  273. startTime = millis();
  274. while(millis()-startTime < 8000)
  275. Serial.read();// if exited due to error, disregard all other serial data
  276. }
  277. break;
  278. case 'E':
  279. eraseChip();
  280. break;
  281. case 'S':
  282. setConfig(true);
  283. break;
  284. case 'C':
  285. setConfig(false);
  286. break;
  287. case 'L':
  288. setLockBits();
  289. break;
  290. default:
  291. Serial.println(F("Received unknown command"));
  292. }
  293. finish();
  294. }
  295. void ERROR_pgmSize(void)
  296. {
  297. Serial.println(F("program size is 0??"));
  298. }
  299. void ERROR_data(char i)
  300. {
  301. Serial.println(F("couldn't receive data:"));
  302. switch(i){
  303. case TimeOut:
  304. Serial.println(F("timed out"));
  305. break;
  306. case HexError:
  307. Serial.println(F("hex file format error"));
  308. break;
  309. case TooLarge:
  310. Serial.println(F("program is too large"));
  311. break;
  312. default:
  313. break;
  314. }
  315. }
  316. // print the register, SRAM, config and signature memory
  317. void dumpMemory(){
  318. unsigned int len;
  319. uint8_t i;
  320. // initialize memory pointer register
  321. setPointer(0x0000);
  322. Serial.println(F("Current memory state:"));
  323. if(type != Tiny4_5)
  324. len = 0x400 * type; //the memory length for a 10/20/40 is 1024/2048/4096
  325. else
  326. len = 0x200; //tiny 4/5 has 512 bytes
  327. len += 0x4000;
  328. while(adrs < len){
  329. // read the byte at the current pointer address
  330. // and increment address
  331. tpi_send_byte(SLDp);
  332. b = tpi_receive_byte(); // get data byte
  333. // read all the memory, but only print
  334. // the register, SRAM, config and signature memory
  335. if ((0x0000 <= adrs && adrs <= 0x005F) // register/SRAM
  336. |(0x3F00 <= adrs && adrs <= 0x3F01) // NVM lock bits
  337. |(0x3F40 <= adrs && adrs <= 0x3F41) // config
  338. |(0x3F80 <= adrs && adrs <= 0x3F81) // calibration
  339. |(0x3FC0 <= adrs && adrs <= 0x3FC3) // ID
  340. |(0x4000 <= adrs && adrs <= len-1) ) { // program
  341. // print +number along the top
  342. if ((0x00 == adrs)
  343. |(0x3f00 == adrs) // NVM lock bits
  344. |(0x3F40 == adrs) // config
  345. |(0x3F80 == adrs) // calibration
  346. |(0x3FC0 == adrs) // ID
  347. |(0x4000 == adrs) ) {
  348. Serial.println();
  349. if(adrs == 0x0000){ Serial.print(F("registers, SRAM")); }
  350. if(adrs == 0x3F00){ Serial.print(F("NVM lock")); }
  351. if(adrs == 0x3F40){ Serial.print(F("configuration")); }
  352. if(adrs == 0x3F80){ Serial.print(F("calibration")); }
  353. if(adrs == 0x3FC0){ Serial.print(F("device ID")); }
  354. if(adrs == 0x4000){ Serial.print(F("program")); }
  355. Serial.println();
  356. for (i = 0; i < 5; i++)
  357. Serial.print(F(" "));
  358. for (i = 0; i < 16; i++) {
  359. Serial.print(F(" +"));
  360. Serial.print(i, HEX);
  361. }
  362. }
  363. // print number on the left
  364. if (0 == (0x000f & adrs)) {
  365. Serial.println();
  366. outHex(adrs, 4);
  367. Serial.print(F(": ")); // delimiter
  368. }
  369. outHex(b, 2);
  370. Serial.print(F(" "));
  371. }
  372. adrs++; // increment memory address
  373. if(adrs == 0x0060){
  374. // skip reserved memory
  375. setPointer(0x3F00);
  376. }
  377. }
  378. Serial.println(F(" "));
  379. } // end dumpMemory()
  380. // receive and translate the contents of a hex file, Program and verify on the fly
  381. boolean writeProgram(){
  382. char datlength[] = "00";
  383. char addr[] = "0000";
  384. char something[] = "00";
  385. char chksm[] = "00";
  386. unsigned int currentByte = 0;
  387. progSize = 0;
  388. uint8_t linelength = 0;
  389. boolean fileEnd = false;
  390. unsigned short tadrs;
  391. tadrs = adrs = 0x4000;
  392. correct = true;
  393. unsigned long pgmStartTime = millis();
  394. eraseChip(); // erase chip
  395. char words = (type!=Tiny4_5?type:1);
  396. char b1, b2;
  397. // read in the data and
  398. while(!fileEnd){
  399. startTime = millis();
  400. while(Serial.available() < 1){
  401. if(millis()-startTime > timeout){
  402. ERROR_data(TimeOut);
  403. return false;
  404. }
  405. if(pgmStartTime == 0)
  406. pgmStartTime = millis();
  407. }
  408. if(Sread() != ':'){ // maybe it was a newline??
  409. if(Sread() != ':'){
  410. ERROR_data(HexError);
  411. return false;
  412. }
  413. }
  414. // read data length
  415. datlength[0] = Sread();
  416. datlength[1] = Sread();
  417. linelength = byteval(datlength[0], datlength[1]);
  418. // read address. if "0000" currentByte = 0
  419. addr[0] = Sread();
  420. addr[1] = Sread();
  421. addr[2] = Sread();
  422. addr[3] = Sread();
  423. if(linelength != 0x00 && addr[0]=='0' && addr[1]=='0' && addr[2]=='0' && addr[3]=='0')
  424. currentByte = 0;
  425. // read type thingy. "01" means end of file
  426. something[0] = Sread();
  427. something[1] = Sread();
  428. if(something[1] == '1'){
  429. fileEnd = true;
  430. }
  431. if(something[1] == '2'){
  432. for (int i = 0; i<=linelength; i++){
  433. Sread();
  434. Sread();
  435. }
  436. }
  437. else{
  438. // read in the data
  439. for(int k=0; k<linelength; k++){
  440. while(Serial.available() < 1){
  441. if(millis()-startTime > timeout){
  442. ERROR_data(TimeOut);
  443. return false;
  444. }
  445. }
  446. b1=Sread();
  447. b2=Sread();
  448. data[currentByte] = byteval(b1, b2);
  449. currentByte++;
  450. progSize++;
  451. if(progSize > (type!=Tiny4_5?type*1024:512)){
  452. ERROR_data(TooLarge);
  453. return 0;
  454. }
  455. if(fileEnd) //has the end of the file been reached?
  456. while(currentByte < 2 * words){// append zeros to align the word count to program
  457. data[currentByte] = 0;
  458. currentByte++;
  459. }
  460. if( currentByte == 2 * words ){// is the word/Dword/Qword here?
  461. currentByte = 0; // yes, reset counter
  462. setPointer(tadrs); // point to the address to program
  463. writeIO(NVMCMD, NVM_WORD_WRITE);
  464. for(int i = 0; i<2 * words; i+=2){// loop for each word size depending on micro
  465. // now write a word to program memory
  466. tpi_send_byte(SSTp);
  467. tpi_send_byte(data[i]); // LSB first
  468. tpi_send_byte(SSTp);
  469. tpi_send_byte(data[i+1]); // then MSB
  470. SPI.transfer(0xff); //send idle between words
  471. SPI.transfer(0xff); //send idle between words
  472. }
  473. while((readIO(NVMCSR) & (1<<7)) != 0x00){} // wait for write to finish
  474. writeIO(NVMCMD, NVM_NOP);
  475. SPI.transfer(0xff);
  476. SPI.transfer(0xff);
  477. //verify written words
  478. setPointer(tadrs);
  479. for (int c = 0; c < 2 * words; c++){
  480. tpi_send_byte(SLDp);
  481. b = tpi_receive_byte(); // get data byte
  482. if(b != data[c]){
  483. correct = false;
  484. Serial.println(F("program error:"));
  485. Serial.print(F("byte "));
  486. outHex(adrs, 4);
  487. Serial.print(F(" expected "));
  488. outHex(data[c],2);
  489. Serial.print(F(" read "));
  490. outHex(b,2);
  491. Serial.println();
  492. if(!correct)
  493. return false;
  494. }
  495. }
  496. tadrs += 2 * words;
  497. }
  498. }
  499. // read in the checksum.
  500. startTime = millis();
  501. while(Serial.available() == 0){
  502. if(millis()-startTime > timeout){
  503. ERROR_data(TimeOut);
  504. return false;
  505. }
  506. }
  507. chksm[0] = Sread();
  508. chksm[1] = Sread();
  509. }
  510. }
  511. // the program was successfully written
  512. Serial.print(F("Successfully wrote program: "));
  513. Serial.print(progSize, DEC);
  514. Serial.print(F(" of "));
  515. if(type != Tiny4_5)
  516. Serial.print(1024 * type, DEC);
  517. else
  518. Serial.print(512, DEC);
  519. Serial.print(F(" bytes\n in "));
  520. Serial.print((millis()-pgmStartTime)/1000.0,DEC);
  521. Serial.print(F(" Seconds"));
  522. // digitalWrite(SS, HIGH); // release RESET
  523. return true;
  524. }
  525. void eraseChip(){
  526. // initialize memory pointer register
  527. setPointer(0x4001); // need the +1 for chip erase
  528. // erase the chip
  529. writeIO(NVMCMD, NVM_CHIP_ERASE);
  530. tpi_send_byte(SSTp);
  531. tpi_send_byte(0xAA);
  532. tpi_send_byte(SSTp);
  533. tpi_send_byte(0xAA);
  534. tpi_send_byte(SSTp);
  535. tpi_send_byte(0xAA);
  536. tpi_send_byte(SSTp);
  537. tpi_send_byte(0xAA);
  538. while((readIO(NVMCSR) & (1<<7)) != 0x00){
  539. // wait for erasing to finish
  540. }
  541. Serial.println(F("chip erased"));
  542. }
  543. void setConfig(boolean val){
  544. // get current config byte
  545. setPointer(0x3F40);
  546. tpi_send_byte(SLD);
  547. b = tpi_receive_byte();
  548. Serial.println(F("input one of these letters"));
  549. Serial.println(F("c = system clock output"));
  550. Serial.println(F("w = watchdog timer on"));
  551. Serial.println(F("r = disable reset"));
  552. Serial.println(F("x = cancel. don't change anything"));
  553. while(Serial.available() < 1){
  554. // wait
  555. }
  556. char comnd = Serial.read();
  557. setPointer(0x3F40);
  558. writeIO(NVMCMD, (val ? NVM_WORD_WRITE : NVM_SECTION_ERASE) );
  559. if(comnd == 'c'){
  560. tpi_send_byte(SSTp);
  561. if(val){
  562. tpi_send_byte(b & 0b11111011);
  563. }else{
  564. tpi_send_byte(b | 0x04);
  565. }
  566. tpi_send_byte(SSTp);
  567. tpi_send_byte(0xFF);
  568. }else if(comnd == 'w'){
  569. tpi_send_byte(SSTp);
  570. if(val){
  571. tpi_send_byte(b & 0b11111101);
  572. }else{
  573. tpi_send_byte(b | 0x02);
  574. }
  575. tpi_send_byte(SSTp);
  576. tpi_send_byte(0xFF);
  577. }else if(comnd == 'r'){
  578. tpi_send_byte(SSTp);
  579. if(val){
  580. tpi_send_byte(b & 0b11111110);
  581. }else{
  582. tpi_send_byte(b | 0x01);
  583. }
  584. tpi_send_byte(SSTp);
  585. tpi_send_byte(0xFF);
  586. }else if(comnd == 'x'){
  587. // do nothing
  588. }else{
  589. Serial.println(F("received unknown command. Cancelling"));
  590. }
  591. while((readIO(NVMCSR) & (1<<7)) != 0x00){
  592. // wait for write to finish
  593. }
  594. writeIO(NVMCMD, NVM_NOP);
  595. SPI.transfer(0xff);
  596. SPI.transfer(0xff);
  597. if(comnd != 'x'){
  598. Serial.print(F("\n\nSuccessfully "));
  599. if(val)
  600. Serial.print(F("Set "));
  601. else
  602. Serial.print(F("Cleared "));
  603. Serial.print(F("\""));
  604. if(comnd == 'w')
  605. Serial.print(F("Watchdog"));
  606. else if(comnd == 'c')
  607. Serial.print(F("Clock Output"));
  608. else if(comnd == 'r')
  609. Serial.print(F("Reset"));
  610. Serial.println(F("\" Flag\n"));
  611. }
  612. }
  613. void finish(){
  614. writeCSS(0x00, 0x00);
  615. SPI.transfer(0xff);
  616. SPI.transfer(0xff);
  617. hvReset(HIGH);
  618. // digitalWrite(SS, HIGH); // release RESET
  619. delay(1); // t_RST min = 400 ns @ Vcc = 5 V
  620. SPI.end();
  621. DDRB &= 0b11000011; //tri-state spi so target can be tested
  622. PORTB &= 0b11000011;
  623. }
  624. void checkID(){
  625. // check the device ID
  626. uint8_t id1, id2, id3;
  627. setPointer(0x3FC0);
  628. tpi_send_byte(SLDp);
  629. id1 = tpi_receive_byte();
  630. tpi_send_byte(SLDp);
  631. id2 = tpi_receive_byte();
  632. tpi_send_byte(SLDp);
  633. id3 = tpi_receive_byte();
  634. if(id1==0x1E && id2==0x8F && id3==0x0A){
  635. Serial.print(F("ATtiny4"));
  636. type = Tiny4_5;
  637. }else if(id1==0x1E && id2==0x8F && id3==0x09){
  638. Serial.print(F("ATtiny5"));
  639. type = Tiny4_5;
  640. }else if(id1==0x1E && id2==0x90 && id3==0x08){
  641. Serial.print(F("ATtiny9"));
  642. type = Tiny9;
  643. }else if(id1==0x1E && id2==0x90 && id3==0x03){
  644. Serial.print(F("ATtiny10"));
  645. type = Tiny10;
  646. }else if(id1==0x1E && id2==0x91 && id3==0x0f){
  647. Serial.print(F("ATtiny20"));
  648. type = Tiny20;
  649. }else if(id1==0x1E && id2==0x92 && id3==0x0e){
  650. Serial.print(F("ATtiny40"));
  651. type = Tiny40;
  652. }else{
  653. Serial.print(F("Unknown chip"));
  654. }
  655. Serial.println(F(" connected"));
  656. }
  657. /*
  658. * send a byte in one TPI frame (12 bits)
  659. * (1 start + 8 data + 1 parity + 2 stop)
  660. * using 2 SPI data bytes (2 x 8 = 16 clocks)
  661. * (with 4 extra idle bits)
  662. */
  663. void tpi_send_byte( uint8_t data ){
  664. // compute partiy bit
  665. uint8_t par = data;
  666. par ^= (par >> 4); // b[7:4] (+) b[3:0]
  667. par ^= (par >> 2); // b[3:2] (+) b[1:0]
  668. par ^= (par >> 1); // b[1] (+) b[0]
  669. // REMEMBER: this is in LSBfirst mode and idle is high
  670. // (2 idle) + (1 start bit) + (data[4:0])
  671. SPI.transfer(0x03 | (data << 3));
  672. // (data[7:5]) + (1 parity) + (2 stop bits) + (2 idle)
  673. SPI.transfer(0xf0 | (par << 3) | (data >> 5));
  674. } // end tpi_send_byte()
  675. /*
  676. * receive TPI 12-bit format byte data
  677. * via SPI 2 bytes (16 clocks) or 3 bytes (24 clocks)
  678. */
  679. uint8_t tpi_receive_byte( void ){
  680. //uint8_t b1, b2, b3;
  681. // keep transmitting high(idle) while waiting for a start bit
  682. do {
  683. b1 = SPI.transfer(0xff);
  684. } while (0xff == b1);
  685. // get (partial) data bits
  686. b2 = SPI.transfer(0xff);
  687. // if the first byte(b1) contains less than 4 data bits
  688. // we need to get a third byte to get the parity and stop bits
  689. if (0x0f == (0x0f & b1)) {
  690. b3 = SPI.transfer(0xff);
  691. }
  692. // now shift the bits into the right positions
  693. // b1 should hold only idle and start bits = 0b01111111
  694. while (0x7f != b1) { // data not aligned
  695. b2 <<= 1; // shift left data bits
  696. if (0x80 & b1) { // carry from 1st byte
  697. b2 |= 1; // set bit
  698. }
  699. b1 <<= 1;
  700. b1 |= 0x01; // fill with idle bit (1)
  701. }
  702. // now the data byte is stored in b2
  703. return( b2 );
  704. } // end tpi_receive_byte()
  705. // send the 64 bit NVM key
  706. void send_skey(uint64_t nvm_key){
  707. tpi_send_byte(SKEY);
  708. while(nvm_key){
  709. tpi_send_byte(nvm_key & 0xFF);
  710. nvm_key >>= 8;
  711. }
  712. } // end send_skey()
  713. // sets the pointer address
  714. void setPointer(unsigned short address){
  715. adrs = address;
  716. tpi_send_byte(SSTPRL);
  717. tpi_send_byte(address & 0xff);
  718. tpi_send_byte(SSTPRH);
  719. tpi_send_byte((address>>8) & 0xff);
  720. }
  721. // writes using SOUT
  722. void writeIO(uint8_t address, uint8_t value){
  723. // SOUT 0b1aa1aaaa replace a with 6 address bits
  724. tpi_send_byte(0x90 | (address & 0x0F) | ((address & 0x30) << 1));
  725. tpi_send_byte(value);
  726. }
  727. // reads using SIN
  728. uint8_t readIO(uint8_t address){
  729. // SIN 0b0aa1aaaa replace a with 6 address bits
  730. tpi_send_byte(0x10 | (address & 0x0F) | ((address & 0x30) << 1));
  731. return tpi_receive_byte();
  732. }
  733. // writes to CSS
  734. void writeCSS(uint8_t address, uint8_t value){
  735. tpi_send_byte(0xC0 | address);
  736. tpi_send_byte(value);
  737. }
  738. // reads from CSS
  739. uint8_t readCSS(uint8_t address){
  740. tpi_send_byte(0x80 | address);
  741. return tpi_receive_byte();
  742. }
  743. // converts two chars to one byte
  744. // c1 is MS, c2 is LS
  745. uint8_t byteval(char c1, char c2){
  746. uint8_t by;
  747. if(c1 <= '9'){
  748. by = c1-'0';
  749. }else{
  750. by = c1-'A'+10;
  751. }
  752. by = by << 4;
  753. if(c2 <= '9'){
  754. by += c2-'0';
  755. }else{
  756. by += c2-'A'+10;
  757. }
  758. return by;
  759. }
  760. char Sread(void){
  761. while(Serial.available()<1){}
  762. return Serial.read();
  763. }
  764. void outHex(unsigned int n, char l){ // call with the number to be printed, and # of nibbles expected.
  765. for(char count = l-1; count > 0;count--){ // quick and dirty to add zeros to the hex value
  766. if(((n >> (count*4)) & 0x0f) == 0) // if MSB is 0
  767. Serial.print(F("0")); //prepend a 0
  768. else
  769. break; //exit the for loop
  770. }
  771. Serial.print(n, HEX);
  772. }
  773. // end of file