├── .gitignore ├── README.md ├── LICENSE.md ├── avrboy.go ├── ATtiny4_5_9_10_20_40Programmer_2 └── ATtiny4_5_9_10_20_40Programmer_2.ino └── ArduinoISP_ATtiny10TPI └── ArduinoISP_ATtiny10TPI.ino /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | ._* 3 | ._*.txt 4 | .smb* 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # avrboy 2 | 3 | # What is this? 4 | 5 | The avrboy is command line control software for ATtiny4_5_9_10_20_40Programmer_2.ino 6 | 7 | original [ATtiny4_5_9_10_20_40Programmer.ino](https://drive.google.com/file/d/0B--e8M84W8o8UjJsSnI0bkVFT0U) is distributed by Keri DuPrey 8 | 9 | The avrboy can be incorporated into Arduino IDE and used. 10 | 11 | more info. https://make.kosakalab.com/make/electronic-work/arduino_tpi_en/ 12 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Kimio Kosaka 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /avrboy.go: -------------------------------------------------------------------------------- 1 | /* 2 | avrboy by kimio kosaka (kimio.kosaka@gmail.com) 3 | 4 | 2018.05.02 ver. 1.0.2 5 | 2018.05.02 ver. 1.0.1 6 | 2018.05.02 ver. 1.0.0 7 | */ 8 | 9 | package main 10 | 11 | import ( 12 | "bufio" 13 | "errors" 14 | "flag" 15 | "fmt" 16 | "log" 17 | "os" 18 | "strings" 19 | "strconv" 20 | "time" 21 | 22 | "github.com/goburrow/serial" 23 | ) 24 | 25 | func getArgv() (port string, bps int, device string, file string, err error) { 26 | flag.StringVar(&port, "P", "noPort", "string flag") 27 | flag.IntVar(&bps, "b", 19200, "int flag") 28 | flag.StringVar(&device, "p", "noDevice", "string flag") 29 | flag.StringVar(&file, "U", "noFile", "string flag") 30 | flag.Parse() 31 | 32 | device = strings.ToLower(device) 33 | 34 | switch device { 35 | case "attiny4": 36 | device = "ATtiny4" 37 | case "attiny5": 38 | device = "ATtiny5" 39 | case "attiny9": 40 | device = "ATtiny9" 41 | case "attiny10": 42 | device = "ATtiny10" 43 | case "attiny20": 44 | device = "ATtiny20" 45 | case "attiny40": 46 | device = "ATtiny40" 47 | default: 48 | fmt.Println("not support " + device) 49 | device = "unKnown" 50 | } 51 | if port == "noPort" || file == "noFile" || device == "unKnown" { 52 | err = errors.New("Error! -P "+port+" -b "+strconv.Itoa(bps)+" -U " + file + " -p " + device ) 53 | } else { 54 | err = nil 55 | } 56 | return 57 | } 58 | 59 | var ( 60 | address string 61 | baudrate int 62 | databits int = 8 63 | stopbits int = 1 64 | parity string = "N" 65 | message string 66 | ) 67 | 68 | func main() { 69 | // get commandline argument 70 | address, baudrate, deviceName, hexFileName, errArgv := getArgv() 71 | // error argument 72 | if errArgv != nil { 73 | log.Fatal(errArgv) 74 | } 75 | 76 | // Open hex file 77 | fd, ferr := os.Open(hexFileName) 78 | if ferr != nil { 79 | log.Fatal(ferr) 80 | } 81 | // Close hex file 82 | defer fd.Close() 83 | 84 | // serial port config 85 | config := serial.Config{ 86 | Address: address, 87 | BaudRate: baudrate, 88 | DataBits: databits, 89 | StopBits: stopbits, 90 | Parity: parity, 91 | Timeout: 10 * time.Second, 92 | } 93 | 94 | // open sereialPort 95 | port, err := serial.Open(&config) 96 | if err != nil { 97 | log.Printf("open %s %v", address, err) 98 | log.Fatal() 99 | } 100 | 101 | // close serialPortdefer 102 | defer func() { 103 | err := port.Close() 104 | if err != nil { 105 | log.Fatal(err) 106 | } 107 | }() 108 | 109 | // send deviceID request to programmer 110 | time.Sleep(800 * time.Millisecond) 111 | msg := "I" 112 | if _, err = port.Write([]byte(msg)); err != nil { 113 | log.Fatal(err) 114 | } 115 | 116 | if baudrate > 9600 { 117 | time.Sleep(200 * time.Millisecond) 118 | if _, err = port.Write([]byte(msg)); err != nil { 119 | log.Fatal(err) 120 | } 121 | } 122 | 123 | // read programmer respons message 124 | oneByteBuffer := make([]byte, 1) 125 | reciveCharBuffer := make([]byte, 255) 126 | charCounter := 0 127 | for oneByteBuffer[0] != '>' { 128 | if _, err = port.Read(oneByteBuffer); err != nil { 129 | log.Fatal(err) 130 | } 131 | reciveCharBuffer[charCounter] = oneByteBuffer[0] 132 | charCounter++ 133 | } 134 | 135 | // programmers' message (byte slice) to string arry 136 | var reciveStringBuffer [255]string 137 | var lineCounter int = 0 138 | for i := 0; i < charCounter; i++ { 139 | switch { 140 | case reciveCharBuffer[i] >= ' ' && reciveCharBuffer[i] <= '~': 141 | switch { 142 | case i == 0: 143 | reciveStringBuffer[lineCounter] = string(reciveCharBuffer[i]) 144 | default: 145 | reciveStringBuffer[lineCounter] = reciveStringBuffer[lineCounter] + string(reciveCharBuffer[i]) 146 | } 147 | case reciveCharBuffer[i] == '\n': 148 | lineCounter++ 149 | default: 150 | } 151 | } 152 | 153 | // read programmer's starting message 154 | attinyConnectedPosition := 0 155 | deviceConnectedFlag := false 156 | for i := 0; i <= lineCounter; i++ { 157 | if strings.Contains(reciveStringBuffer[i], "ATtiny") { 158 | attinyConnectedPosition = i 159 | } 160 | if !deviceConnectedFlag { 161 | deviceConnectedFlag = reciveStringBuffer[i] == (deviceName + " connected") 162 | } 163 | } 164 | 165 | // check connected Attiny device 166 | if !deviceConnectedFlag { 167 | log.Fatal("Error! Your request is " + deviceName + ", but " + reciveStringBuffer[attinyConnectedPosition]) 168 | } 169 | fmt.Printf(reciveStringBuffer[attinyConnectedPosition]) 170 | 171 | /***** programming ATtiny *****/ 172 | fmt.Println(" / Write " + hexFileName) 173 | // set scanner for hex file 174 | scanner := bufio.NewScanner(fd) 175 | // send programming command to ATtiny programmer 176 | cmd := "P " 177 | if _, err = port.Write([]byte(cmd)); err != nil { 178 | log.Fatal(err) 179 | } 180 | // send hex data to ATtiny programmer 181 | var lineBuffer string 182 | for scanner.Scan() { 183 | lineBuffer = scanner.Text() 184 | if _, err = port.Write([]byte(lineBuffer)); err != nil { 185 | log.Fatal(err) 186 | } 187 | time.Sleep(50 * time.Millisecond) 188 | } 189 | if ferr = scanner.Err(); ferr != nil { 190 | log.Fatal(ferr) 191 | } 192 | 193 | // read ATtiny programmer's respons message 194 | oneByteBuffer[0] = ' ' 195 | for oneByteBuffer[0] != '>' { 196 | if _, err = port.Read(oneByteBuffer); err != nil { 197 | log.Fatal(err) 198 | } 199 | fmt.Printf("%c", oneByteBuffer[0]) 200 | } 201 | fmt.Println() 202 | return 203 | } 204 | -------------------------------------------------------------------------------- /ATtiny4_5_9_10_20_40Programmer_2/ATtiny4_5_9_10_20_40Programmer_2.ino: -------------------------------------------------------------------------------- 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 | I = Check the device ID 42 | 43 | - Finally, power off the arduino and remove the 44 | Attiny10/20/40 45 | 46 | 47 | Arduino ATtiny10 48 | ----------+ +---------------- 49 | (SS#) 10 |--[R]-----| 6 (RESET#/PB3) 50 | | | 51 | (MOSI) 11 |--[R]--+--| 1 (TPIDATA/PB0) 52 | | | | 53 | (MISO) 12 |--[R]--+ | 54 | | | 55 | (SCK) 13 |--[R]-----| 3 (TPICLK/PB1) 56 | ----------+ +---------------- 57 | * * 58 | ----------+ +---------------- 59 | (HVP) 9 |--- | 6 (RESET#/PB3) 60 | | | 61 | * * 62 | -[R]- = a 220 - 1K Ohm resistor 63 | * * 64 | this picture : 2011/12/08 by pcm1723 65 | modified :2015/02/27 by KD 66 | * * 67 | thanks to pcm1723 for tpitest.pde upon which 68 | this is based 69 | ************************************************** 70 | Updates: 71 | 72 | May 02, 2018: kimio.kosaka@gmail.com 73 | Added 'I' command 74 | 75 | Apr 02, 2018: Ksdsksd@gmail.com 76 | Added Lock bit setting to main menu 77 | 78 | Jan 23, 2017: Ksdsksd@gmail.com 79 | Thanks to InoueTaichi Fixed incorrect #define Tiny40 80 | 81 | Mar 05, 2015: Ksdsksd@gamil.com 82 | Added notifications to setting and clearing the system flags. 83 | 84 | Feb 23, 2015: Ksdsksd@gamil.com 85 | Changed the programmer Diagram, This is the config I use, and get a sucessful programming of a tiny10 at 9600 baud. 86 | 87 | Mar 22, 2014: Ksdsksd@gmail.com 88 | Added the quick reset to high before resetting the device. 89 | Added code to stop the SPI and float the pins for testing the device while connected. 90 | 91 | Mar 20, 2014: Ksdsksd@gmail.com 92 | Added a quick reset by sending 'r' or 'R' via the serial monitor. 93 | Added a High voltage programming option from pin 9, toggled by 'H' 94 | Added a High/low option for providing 12v to the reset pin, toggled by 'T' 95 | 96 | Mar 17, 2014: Ksdsksd@gmail.com 97 | Had some trouble with the nibbles being swapped when programming on the 10 & 20, 98 | added b1,b2 to hold the serial data before calling byteval() 99 | Added Nat Blundell's patch to the code 100 | 101 | Apr 10, 2013: Ksdsksd@gmail.com 102 | Applied Fix for setting and clearing flags 103 | 104 | Feb 7, 2013: Ksdsksd@gmail.com 105 | Fixed programming timer, had intitial start at zero instead of current time. 106 | 107 | Dec 11, 2012: Ksdsksd@gmail.com 108 | Added detect and programming for 4/5/9 109 | 110 | Dec 5-6, 2012: Ksdsksd@gmail.com 111 | Incorperated read, and verify into program. Now have no program size limitation by using 328p. 112 | Changed the outHex routines consolidated them into 1, number to be printed, and number of nibbles 113 | Added a type check to distinguish between Tiny10/20/40 114 | Added an auto word size check to ensure that there is the proper amount of words written for a 10/20/40 115 | Removed Read program, Verify, and Finish from options 116 | Changed baud rate to 19200 for delay from data written to the chip, to prevent serial buffer overrun. 117 | 118 | Oct 5, 2012: Ksdsksd@gmail.com 119 | *** Noticed that when programming, the verification fails 120 | at times by last 1-2 bytes programmed, and the Tiny would act erratic. 121 | Quick fix was adding 3 NOP's to the end the Tiny's code, and ignoring the errors, the Tiny then performed as expected. 122 | 123 | Oct 4, 2012: Ksdsksd@gmail.com 124 | Moved all Serial printed strings to program space 125 | Added code to detect Tiny20 126 | */ 127 | 128 | #include 129 | #include "pins_arduino.h" 130 | 131 | // define the instruction set bytes 132 | #define SLD 0x20 133 | #define SLDp 0x24 134 | #define SST 0x60 135 | #define SSTp 0x64 136 | #define SSTPRH 0x69 137 | #define SSTPRL 0x68 138 | // see functions below //////////////////////////////// 139 | // SIN 0b0aa1aaaa replace a with 6 address bits 140 | // SOUT 0b1aa1aaaa replace a with 6 address bits 141 | // SLDCS 0b1000aaaa replace a with address bits 142 | // SSTCS 0b1100aaaa replace a with address bits 143 | /////////////////////////////////////////////////////// 144 | #define SKEY 0xE0 145 | #define NVM_PROGRAM_ENABLE 0x1289AB45CDD888FFULL // the ULL means unsigned long long 146 | 147 | #define NVMCMD 0x33 148 | #define NVMCSR 0x32 149 | #define NVM_NOP 0x00 150 | #define NVM_CHIP_ERASE 0x10 151 | #define NVM_SECTION_ERASE 0x14 152 | #define NVM_WORD_WRITE 0x1D 153 | 154 | #define HVReset 9 155 | 156 | #define Tiny4_5 10 157 | #define Tiny9 1 158 | #define Tiny10 1 159 | #define Tiny20 2 160 | #define Tiny40 4 161 | 162 | #define TimeOut 1 163 | #define HexError 2 164 | #define TooLarge 3 165 | // represents the current pointer register value 166 | unsigned short adrs = 0x0000; 167 | 168 | // used for storing a program file 169 | uint8_t data[16]; //program data 170 | unsigned int progSize = 0; //program size in bytes 171 | 172 | // used for various purposes 173 | long startTime; 174 | int timeout; 175 | uint8_t b, b1, b2, b3; 176 | boolean idChecked; 177 | boolean correct; 178 | char type; // type of chip connected 1 = Tiny10, 2 = Tiny20 179 | char HVP = 0; 180 | char HVON = 0; 181 | 182 | void setup() { 183 | // set up serial 184 | Serial.begin(9600); // you cant increase this, it'll overrun the buffer 185 | // set up SPI 186 | /* SPI.begin(); 187 | SPI.setBitOrder(LSBFIRST); 188 | SPI.setDataMode(SPI_MODE0); 189 | SPI.setClockDivider(SPI_CLOCK_DIV32); 190 | 191 | */ start_tpi(); 192 | 193 | 194 | pinMode(HVReset, OUTPUT); 195 | // initialize memory pointer register 196 | setPointer(0x0000); 197 | 198 | timeout = 20000; 199 | idChecked = false; 200 | } // end setup() 201 | 202 | 203 | void hvserial() 204 | { 205 | if (HVP) 206 | Serial.println(F("***High Voltage Programming Enabled***")); 207 | else 208 | Serial.println(F("High Voltage Programming Disabled")); 209 | 210 | Serial.print(F("Pin 9 ")); 211 | Serial.print(HVON ? F("HIGH") : F("LOW")); 212 | Serial.print(F(" supplies 12v")); 213 | 214 | } 215 | 216 | 217 | void hvReset(char highLow) 218 | { 219 | if (HVP) 220 | { 221 | if (HVON) //if high enables 12v 222 | highLow = !highLow; // invert the typical reset 223 | digitalWrite(HVReset, highLow); 224 | } 225 | else 226 | digitalWrite(SS, highLow); 227 | } 228 | 229 | void quickReset() 230 | { 231 | digitalWrite(SS, HIGH); 232 | delay(1); 233 | digitalWrite(SS, LOW); 234 | delay(10); 235 | digitalWrite(SS, HIGH); 236 | } 237 | 238 | void start_tpi() { 239 | SPI.begin(); 240 | SPI.setBitOrder(LSBFIRST); 241 | SPI.setDataMode(SPI_MODE0); 242 | SPI.setClockDivider(SPI_CLOCK_DIV32); 243 | 244 | // enter TPI programming mode 245 | hvReset(LOW); 246 | // digitalWrite(SS, LOW); // assert RESET on tiny 247 | delay(1); // t_RST min = 400 ns @ Vcc = 5 V 248 | 249 | SPI.transfer(0xff); // activate TPI by emitting 250 | SPI.transfer(0xff); // 16 or more pulses on TPICLK 251 | SPI.transfer(0xff); // while holding TPIDATA to "1" 252 | 253 | writeCSS(0x02, 0x04); // TPIPCR, guard time = 8bits (default=128) 254 | 255 | send_skey(NVM_PROGRAM_ENABLE); // enable NVM interface 256 | // wait for NVM to be enabled 257 | while ((readCSS(0x00) & 0x02) < 1) { 258 | // wait 259 | } 260 | Serial.println(F("NVM enabled")); 261 | } 262 | 263 | void setLockBits() { 264 | 265 | Serial.print(F("Locking... Are you sure? Y/N")); 266 | while (Serial.available() < 1); 267 | char yn = Serial.read(); 268 | if (yn == 'n' || yn == 'N') 269 | return; 270 | 271 | setPointer(0x3F00); 272 | writeIO(NVMCMD, NVM_WORD_WRITE); 273 | tpi_send_byte(SSTp); 274 | tpi_send_byte(0); 275 | 276 | tpi_send_byte(SSTp); 277 | tpi_send_byte(0xFF); 278 | 279 | 280 | while ((readIO(NVMCSR) & (1 << 7)) != 0x00); 281 | Serial.print(F("Locked...")); 282 | } 283 | 284 | void loop() { 285 | if (!idChecked) { 286 | // start_tpi(); 287 | checkID(); 288 | idChecked = true; 289 | finish(); 290 | } 291 | // when ready, send ready signal '.' and wait 292 | Serial.print(F("\n>")); 293 | while (Serial.available() < 1) { 294 | // wait 295 | } 296 | start_tpi(); 297 | 298 | // the first byte is a command 299 | //** 'P' = program the ATtiny using the read program 300 | //** 'D' = dump memory to serial monitor 301 | //** 'E' = erase chip. erases current program memory.(done automatically by 'P') 302 | //** 'S' = set fuse 303 | //** 'C' = clear fuse 304 | //** 'L' = Set Lock Bits 305 | //** 'I' = Check the device ID 306 | 307 | 308 | char comnd = Sread(); 309 | 310 | switch ( comnd ) { 311 | case 'r': 312 | case'R': 313 | quickReset(); 314 | break; 315 | 316 | case 'D': 317 | dumpMemory(); 318 | break; 319 | 320 | case 'H': 321 | HVP = !HVP; 322 | hvserial(); 323 | break; 324 | 325 | case 'T': 326 | HVON = !HVON; 327 | hvserial(); 328 | break; 329 | 330 | 331 | case 'P': 332 | if (!writeProgram()) { 333 | startTime = millis(); 334 | while (millis() - startTime < 8000) 335 | Serial.read();// if exited due to error, disregard all other serial data 336 | } 337 | 338 | break; 339 | 340 | case 'E': 341 | eraseChip(); 342 | break; 343 | 344 | case 'S': 345 | setConfig(true); 346 | break; 347 | 348 | case 'C': 349 | setConfig(false); 350 | break; 351 | 352 | case 'L': 353 | setLockBits(); 354 | break; 355 | 356 | case 'I': 357 | checkID(); 358 | break; 359 | 360 | default: 361 | Serial.println(F("Received unknown command")); 362 | } 363 | 364 | finish(); 365 | 366 | 367 | } 368 | void ERROR_pgmSize(void) 369 | { 370 | Serial.println(F("program size is 0??")); 371 | } 372 | 373 | void ERROR_data(char i) 374 | { 375 | Serial.println(F("couldn't receive data:")); 376 | switch (i) { 377 | case TimeOut: 378 | Serial.println(F("timed out")); 379 | break; 380 | case HexError: 381 | Serial.println(F("hex file format error")); 382 | break; 383 | case TooLarge: 384 | Serial.println(F("program is too large")); 385 | break; 386 | 387 | default: 388 | break; 389 | } 390 | 391 | } 392 | 393 | 394 | // print the register, SRAM, config and signature memory 395 | void dumpMemory() { 396 | unsigned int len; 397 | uint8_t i; 398 | // initialize memory pointer register 399 | setPointer(0x0000); 400 | 401 | Serial.println(F("Current memory state:")); 402 | if (type != Tiny4_5) 403 | len = 0x400 * type; //the memory length for a 10/20/40 is 1024/2048/4096 404 | else 405 | len = 0x200; //tiny 4/5 has 512 bytes 406 | len += 0x4000; 407 | 408 | while (adrs < len) { 409 | // read the byte at the current pointer address 410 | // and increment address 411 | tpi_send_byte(SLDp); 412 | b = tpi_receive_byte(); // get data byte 413 | 414 | // read all the memory, but only print 415 | // the register, SRAM, config and signature memory 416 | if ((0x0000 <= adrs && adrs <= 0x005F) // register/SRAM 417 | | (0x3F00 <= adrs && adrs <= 0x3F01) // NVM lock bits 418 | | (0x3F40 <= adrs && adrs <= 0x3F41) // config 419 | | (0x3F80 <= adrs && adrs <= 0x3F81) // calibration 420 | | (0x3FC0 <= adrs && adrs <= 0x3FC3) // ID 421 | | (0x4000 <= adrs && adrs <= len - 1) ) { // program 422 | // print +number along the top 423 | if ((0x00 == adrs) 424 | | (0x3f00 == adrs) // NVM lock bits 425 | | (0x3F40 == adrs) // config 426 | | (0x3F80 == adrs) // calibration 427 | | (0x3FC0 == adrs) // ID 428 | | (0x4000 == adrs) ) { 429 | Serial.println(); 430 | if (adrs == 0x0000) { 431 | Serial.print(F("registers, SRAM")); 432 | } 433 | if (adrs == 0x3F00) { 434 | Serial.print(F("NVM lock")); 435 | } 436 | if (adrs == 0x3F40) { 437 | Serial.print(F("configuration")); 438 | } 439 | if (adrs == 0x3F80) { 440 | Serial.print(F("calibration")); 441 | } 442 | if (adrs == 0x3FC0) { 443 | Serial.print(F("device ID")); 444 | } 445 | if (adrs == 0x4000) { 446 | Serial.print(F("program")); 447 | } 448 | Serial.println(); 449 | for (i = 0; i < 5; i++) 450 | Serial.print(F(" ")); 451 | for (i = 0; i < 16; i++) { 452 | Serial.print(F(" +")); 453 | Serial.print(i, HEX); 454 | } 455 | } 456 | // print number on the left 457 | if (0 == (0x000f & adrs)) { 458 | Serial.println(); 459 | outHex(adrs, 4); 460 | Serial.print(F(": ")); // delimiter 461 | } 462 | outHex(b, 2); 463 | Serial.print(F(" ")); 464 | } 465 | adrs++; // increment memory address 466 | if (adrs == 0x0060) { 467 | // skip reserved memory 468 | setPointer(0x3F00); 469 | } 470 | } 471 | Serial.println(F(" ")); 472 | } // end dumpMemory() 473 | 474 | 475 | // receive and translate the contents of a hex file, Program and verify on the fly 476 | boolean writeProgram() { 477 | char datlength[] = "00"; 478 | char addr[] = "0000"; 479 | char something[] = "00"; 480 | char chksm[] = "00"; 481 | unsigned int currentByte = 0; 482 | progSize = 0; 483 | uint8_t linelength = 0; 484 | boolean fileEnd = false; 485 | unsigned short tadrs; 486 | tadrs = adrs = 0x4000; 487 | correct = true; 488 | unsigned long pgmStartTime = millis(); 489 | eraseChip(); // erase chip 490 | char words = (type != Tiny4_5 ? type : 1); 491 | char b1, b2; 492 | // read in the data and 493 | while (!fileEnd) { 494 | startTime = millis(); 495 | while (Serial.available() < 1) { 496 | if (millis() - startTime > timeout) { 497 | ERROR_data(TimeOut); 498 | return false; 499 | } 500 | if (pgmStartTime == 0) 501 | pgmStartTime = millis(); 502 | } 503 | if (Sread() != ':') { // maybe it was a newline?? 504 | if (Sread() != ':') { 505 | ERROR_data(HexError); 506 | return false; 507 | } 508 | } 509 | // read data length 510 | 511 | datlength[0] = Sread(); 512 | datlength[1] = Sread(); 513 | linelength = byteval(datlength[0], datlength[1]); 514 | 515 | // read address. if "0000" currentByte = 0 516 | addr[0] = Sread(); 517 | addr[1] = Sread(); 518 | addr[2] = Sread(); 519 | addr[3] = Sread(); 520 | if (linelength != 0x00 && addr[0] == '0' && addr[1] == '0' && addr[2] == '0' && addr[3] == '0') 521 | currentByte = 0; 522 | 523 | // read type thingy. "01" means end of file 524 | something[0] = Sread(); 525 | something[1] = Sread(); 526 | if (something[1] == '1') { 527 | fileEnd = true; 528 | } 529 | 530 | if (something[1] == '2') { 531 | for (int i = 0; i <= linelength; i++) { 532 | Sread(); 533 | Sread(); 534 | } 535 | 536 | } 537 | else { 538 | // read in the data 539 | for (int k = 0; k < linelength; k++) { 540 | while (Serial.available() < 1) { 541 | if (millis() - startTime > timeout) { 542 | ERROR_data(TimeOut); 543 | return false; 544 | } 545 | } 546 | b1 = Sread(); 547 | b2 = Sread(); 548 | data[currentByte] = byteval(b1, b2); 549 | currentByte++; 550 | progSize++; 551 | if (progSize > (type != Tiny4_5 ? type * 1024 : 512)) { 552 | ERROR_data(TooLarge); 553 | return 0; 554 | } 555 | 556 | 557 | if (fileEnd) //has the end of the file been reached? 558 | while (currentByte < 2 * words) { // append zeros to align the word count to program 559 | data[currentByte] = 0; 560 | currentByte++; 561 | } 562 | 563 | 564 | 565 | if ( currentByte == 2 * words ) { // is the word/Dword/Qword here? 566 | 567 | currentByte = 0; // yes, reset counter 568 | setPointer(tadrs); // point to the address to program 569 | writeIO(NVMCMD, NVM_WORD_WRITE); 570 | for (int i = 0; i < 2 * words; i += 2) { // loop for each word size depending on micro 571 | 572 | // now write a word to program memory 573 | tpi_send_byte(SSTp); 574 | tpi_send_byte(data[i]); // LSB first 575 | tpi_send_byte(SSTp); 576 | tpi_send_byte(data[i + 1]); // then MSB 577 | SPI.transfer(0xff); //send idle between words 578 | SPI.transfer(0xff); //send idle between words 579 | } 580 | while ((readIO(NVMCSR) & (1 << 7)) != 0x00) {} // wait for write to finish 581 | 582 | writeIO(NVMCMD, NVM_NOP); 583 | SPI.transfer(0xff); 584 | SPI.transfer(0xff); 585 | 586 | 587 | //verify written words 588 | setPointer(tadrs); 589 | for (int c = 0; c < 2 * words; c++) { 590 | tpi_send_byte(SLDp); 591 | b = tpi_receive_byte(); // get data byte 592 | 593 | if (b != data[c]) { 594 | correct = false; 595 | Serial.println(F("program error:")); 596 | Serial.print(F("byte ")); 597 | outHex(adrs, 4); 598 | Serial.print(F(" expected ")); 599 | outHex(data[c], 2); 600 | Serial.print(F(" read ")); 601 | outHex(b, 2); 602 | Serial.println(); 603 | 604 | if (!correct) 605 | return false; 606 | } 607 | } 608 | tadrs += 2 * words; 609 | } 610 | } 611 | 612 | // read in the checksum. 613 | startTime = millis(); 614 | while (Serial.available() == 0) { 615 | if (millis() - startTime > timeout) { 616 | ERROR_data(TimeOut); 617 | return false; 618 | } 619 | } 620 | chksm[0] = Sread(); 621 | chksm[1] = Sread(); 622 | 623 | } 624 | } 625 | // the program was successfully written 626 | Serial.print(F("Successfully wrote program: ")); 627 | Serial.print(progSize, DEC); 628 | Serial.print(F(" of ")); 629 | if (type != Tiny4_5) 630 | Serial.print(1024 * type, DEC); 631 | else 632 | Serial.print(512, DEC); 633 | Serial.print(F(" bytes\n in ")); 634 | Serial.print((millis() - pgmStartTime) / 1000.0, DEC); 635 | Serial.print(F(" Seconds")); 636 | // digitalWrite(SS, HIGH); // release RESET 637 | 638 | return true; 639 | } 640 | 641 | 642 | void eraseChip() { 643 | // initialize memory pointer register 644 | setPointer(0x4001); // need the +1 for chip erase 645 | 646 | // erase the chip 647 | writeIO(NVMCMD, NVM_CHIP_ERASE); 648 | tpi_send_byte(SSTp); 649 | tpi_send_byte(0xAA); 650 | tpi_send_byte(SSTp); 651 | tpi_send_byte(0xAA); 652 | tpi_send_byte(SSTp); 653 | tpi_send_byte(0xAA); 654 | tpi_send_byte(SSTp); 655 | tpi_send_byte(0xAA); 656 | while ((readIO(NVMCSR) & (1 << 7)) != 0x00) { 657 | // wait for erasing to finish 658 | } 659 | Serial.println(F("chip erased")); 660 | } 661 | 662 | void setConfig(boolean val) { 663 | // get current config byte 664 | setPointer(0x3F40); 665 | tpi_send_byte(SLD); 666 | b = tpi_receive_byte(); 667 | 668 | Serial.println(F("input one of these letters")); 669 | Serial.println(F("c = system clock output")); 670 | Serial.println(F("w = watchdog timer on")); 671 | Serial.println(F("r = disable reset")); 672 | Serial.println(F("x = cancel. don't change anything")); 673 | 674 | while (Serial.available() < 1) { 675 | // wait 676 | } 677 | char comnd = Serial.read(); 678 | setPointer(0x3F40); 679 | writeIO(NVMCMD, (val ? NVM_WORD_WRITE : NVM_SECTION_ERASE) ); 680 | 681 | if (comnd == 'c') { 682 | tpi_send_byte(SSTp); 683 | if (val) { 684 | tpi_send_byte(b & 0b11111011); 685 | } else { 686 | tpi_send_byte(b | 0x04); 687 | } 688 | tpi_send_byte(SSTp); 689 | tpi_send_byte(0xFF); 690 | } else if (comnd == 'w') { 691 | tpi_send_byte(SSTp); 692 | if (val) { 693 | tpi_send_byte(b & 0b11111101); 694 | } else { 695 | tpi_send_byte(b | 0x02); 696 | } 697 | tpi_send_byte(SSTp); 698 | tpi_send_byte(0xFF); 699 | } else if (comnd == 'r') { 700 | tpi_send_byte(SSTp); 701 | if (val) { 702 | tpi_send_byte(b & 0b11111110); 703 | } else { 704 | tpi_send_byte(b | 0x01); 705 | } 706 | tpi_send_byte(SSTp); 707 | tpi_send_byte(0xFF); 708 | } else if (comnd == 'x') { 709 | // do nothing 710 | } else { 711 | Serial.println(F("received unknown command. Cancelling")); 712 | } 713 | while ((readIO(NVMCSR) & (1 << 7)) != 0x00) { 714 | // wait for write to finish 715 | } 716 | writeIO(NVMCMD, NVM_NOP); 717 | SPI.transfer(0xff); 718 | SPI.transfer(0xff); 719 | if (comnd != 'x') { 720 | 721 | Serial.print(F("\n\nSuccessfully ")); 722 | if (val) 723 | Serial.print(F("Set ")); 724 | else 725 | Serial.print(F("Cleared ")); 726 | 727 | Serial.print(F("\"")); 728 | if (comnd == 'w') 729 | Serial.print(F("Watchdog")); 730 | else if (comnd == 'c') 731 | Serial.print(F("Clock Output")); 732 | else if (comnd == 'r') 733 | Serial.print(F("Reset")); 734 | 735 | Serial.println(F("\" Flag\n")); 736 | 737 | } 738 | } 739 | 740 | void finish() { 741 | writeCSS(0x00, 0x00); 742 | SPI.transfer(0xff); 743 | SPI.transfer(0xff); 744 | hvReset(HIGH); 745 | // digitalWrite(SS, HIGH); // release RESET 746 | delay(1); // t_RST min = 400 ns @ Vcc = 5 V 747 | SPI.end(); 748 | DDRB &= 0b11000011; //tri-state spi so target can be tested 749 | PORTB &= 0b11000011; 750 | } 751 | 752 | void checkID() { 753 | // check the device ID 754 | uint8_t id1, id2, id3; 755 | setPointer(0x3FC0); 756 | 757 | tpi_send_byte(SLDp); 758 | id1 = tpi_receive_byte(); 759 | tpi_send_byte(SLDp); 760 | id2 = tpi_receive_byte(); 761 | tpi_send_byte(SLDp); 762 | id3 = tpi_receive_byte(); 763 | if (id1 == 0x1E && id2 == 0x8F && id3 == 0x0A) { 764 | Serial.print(F("ATtiny4")); 765 | type = Tiny4_5; 766 | } else if (id1 == 0x1E && id2 == 0x8F && id3 == 0x09) { 767 | Serial.print(F("ATtiny5")); 768 | type = Tiny4_5; 769 | } else if (id1 == 0x1E && id2 == 0x90 && id3 == 0x08) { 770 | Serial.print(F("ATtiny9")); 771 | type = Tiny9; 772 | } else if (id1 == 0x1E && id2 == 0x90 && id3 == 0x03) { 773 | Serial.print(F("ATtiny10")); 774 | type = Tiny10; 775 | } else if (id1 == 0x1E && id2 == 0x91 && id3 == 0x0f) { 776 | Serial.print(F("ATtiny20")); 777 | type = Tiny20; 778 | } else if (id1 == 0x1E && id2 == 0x92 && id3 == 0x0e) { 779 | Serial.print(F("ATtiny40")); 780 | type = Tiny40; 781 | } else { 782 | Serial.print(F("Unknown chip")); 783 | } 784 | Serial.println(F(" connected")); 785 | } 786 | 787 | /* 788 | send a byte in one TPI frame (12 bits) 789 | (1 start + 8 data + 1 parity + 2 stop) 790 | using 2 SPI data bytes (2 x 8 = 16 clocks) 791 | (with 4 extra idle bits) 792 | */ 793 | void tpi_send_byte( uint8_t data ) { 794 | // compute partiy bit 795 | uint8_t par = data; 796 | par ^= (par >> 4); // b[7:4] (+) b[3:0] 797 | par ^= (par >> 2); // b[3:2] (+) b[1:0] 798 | par ^= (par >> 1); // b[1] (+) b[0] 799 | 800 | // REMEMBER: this is in LSBfirst mode and idle is high 801 | // (2 idle) + (1 start bit) + (data[4:0]) 802 | SPI.transfer(0x03 | (data << 3)); 803 | // (data[7:5]) + (1 parity) + (2 stop bits) + (2 idle) 804 | SPI.transfer(0xf0 | (par << 3) | (data >> 5)); 805 | } // end tpi_send_byte() 806 | 807 | /* 808 | receive TPI 12-bit format byte data 809 | via SPI 2 bytes (16 clocks) or 3 bytes (24 clocks) 810 | */ 811 | uint8_t tpi_receive_byte( void ) { 812 | //uint8_t b1, b2, b3; 813 | // keep transmitting high(idle) while waiting for a start bit 814 | do { 815 | b1 = SPI.transfer(0xff); 816 | } while (0xff == b1); 817 | // get (partial) data bits 818 | b2 = SPI.transfer(0xff); 819 | // if the first byte(b1) contains less than 4 data bits 820 | // we need to get a third byte to get the parity and stop bits 821 | if (0x0f == (0x0f & b1)) { 822 | b3 = SPI.transfer(0xff); 823 | } 824 | 825 | // now shift the bits into the right positions 826 | // b1 should hold only idle and start bits = 0b01111111 827 | while (0x7f != b1) { // data not aligned 828 | b2 <<= 1; // shift left data bits 829 | if (0x80 & b1) { // carry from 1st byte 830 | b2 |= 1; // set bit 831 | } 832 | b1 <<= 1; 833 | b1 |= 0x01; // fill with idle bit (1) 834 | } 835 | // now the data byte is stored in b2 836 | return ( b2 ); 837 | } // end tpi_receive_byte() 838 | 839 | // send the 64 bit NVM key 840 | void send_skey(uint64_t nvm_key) { 841 | tpi_send_byte(SKEY); 842 | while (nvm_key) { 843 | tpi_send_byte(nvm_key & 0xFF); 844 | nvm_key >>= 8; 845 | } 846 | } // end send_skey() 847 | 848 | // sets the pointer address 849 | void setPointer(unsigned short address) { 850 | adrs = address; 851 | tpi_send_byte(SSTPRL); 852 | tpi_send_byte(address & 0xff); 853 | tpi_send_byte(SSTPRH); 854 | tpi_send_byte((address >> 8) & 0xff); 855 | } 856 | 857 | // writes using SOUT 858 | void writeIO(uint8_t address, uint8_t value) { 859 | // SOUT 0b1aa1aaaa replace a with 6 address bits 860 | tpi_send_byte(0x90 | (address & 0x0F) | ((address & 0x30) << 1)); 861 | tpi_send_byte(value); 862 | } 863 | 864 | // reads using SIN 865 | uint8_t readIO(uint8_t address) { 866 | // SIN 0b0aa1aaaa replace a with 6 address bits 867 | tpi_send_byte(0x10 | (address & 0x0F) | ((address & 0x30) << 1)); 868 | return tpi_receive_byte(); 869 | } 870 | 871 | // writes to CSS 872 | void writeCSS(uint8_t address, uint8_t value) { 873 | tpi_send_byte(0xC0 | address); 874 | tpi_send_byte(value); 875 | } 876 | 877 | // reads from CSS 878 | uint8_t readCSS(uint8_t address) { 879 | tpi_send_byte(0x80 | address); 880 | return tpi_receive_byte(); 881 | } 882 | 883 | // converts two chars to one byte 884 | // c1 is MS, c2 is LS 885 | uint8_t byteval(char c1, char c2) { 886 | uint8_t by; 887 | if (c1 <= '9') { 888 | by = c1 - '0'; 889 | } else { 890 | by = c1 - 'A' + 10; 891 | } 892 | by = by << 4; 893 | if (c2 <= '9') { 894 | by += c2 - '0'; 895 | } else { 896 | by += c2 - 'A' + 10; 897 | } 898 | return by; 899 | } 900 | 901 | char Sread(void) { 902 | while (Serial.available() < 1) {} 903 | return Serial.read(); 904 | } 905 | 906 | 907 | void outHex(unsigned int n, char l) { // call with the number to be printed, and # of nibbles expected. 908 | for (char count = l - 1; count > 0; count--) { // quick and dirty to add zeros to the hex value 909 | if (((n >> (count * 4)) & 0x0f) == 0) // if MSB is 0 910 | Serial.print(F("0")); //prepend a 0 911 | else 912 | break; //exit the for loop 913 | } 914 | Serial.print(n, HEX); 915 | } 916 | 917 | // end of file 918 | -------------------------------------------------------------------------------- /ArduinoISP_ATtiny10TPI/ArduinoISP_ATtiny10TPI.ino: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | This sketch include ArduinoISP and ATTiny_4_5_9_10_20_40Programmer. 3 | SPI mode == ArduinoISP 4 | TPI mode == ATTiny_4_5_9_10_20_40Programmer 5 | 6 | Set the SELECT_BIT(default D3) HIGH or LOW, when you run this sketch. 7 | You can select and run "SPI mode" or "TPI mode" by SELECT_BIT status. 8 | 9 | #define OUTPUT_LOW 2 10 | #define SELECT_BIT 3 11 | #define TPI_LED 4 12 | #define SPI_LED 5 13 | 14 | TPI_LED and SPI_LED are indicate TPI or SPI mode. 15 | I recommend connect LED to TPI_LED and SPI_LED port 16 | mode change: Set the SELECT_BIT H or L, push Reset button 17 | See function setup() 18 | 19 | Kimio Kosaka. (May.16.2018) 20 | */ 21 | 22 | 23 | /************************************************** 24 | TPI programmer for ATtiny4/5/9/10/20/40 25 | Make the connections as shown below. 26 | To use: 27 | ***** Buad rate must be set to 9600 **** 28 | - Upload to arduino and power off 29 | - Connect ATtiny10 as shown 30 | - Power on and open the serial monitor 31 | - If things are working so far you should 32 | see "NVM enabled" and "ATtiny10/20/40 connected". 33 | - Input one-letter commands via serial monitor: 34 | D = dump memory. Displays all current memory 35 | on the chip 36 | E = erase chip. Erases all program memory 37 | automatically done at time of programming 38 | P = write program. After sending this, paste 39 | the program from the hex file into the 40 | serial monitor. 41 | S = set fuse. follow the instructions to set 42 | one of the three fuses. 43 | C = clear fuse. follow the instructions to clear 44 | one of the three fuses. 45 | L = Set Lock Bits No further programming & verification 46 | possible 47 | H = Toggle High Voltage Programming 48 | T = Toggle +12v enabled by High, or Low 49 | R/r = Quick reset 50 | I = Check the device ID 51 | - Finally, power off the arduino and remove the 52 | Attiny10/20/40 53 | Arduino ATtiny10 54 | ----------+ +---------------- 55 | (SS#) 10 |--[R]-----| 6 (RESET#/PB3) 56 | | | 57 | (MOSI) 11 |--[R]--+--| 1 (TPIDATA/PB0) 58 | | | | 59 | (MISO) 12 |--[R]--+ | 60 | | | 61 | (SCK) 13 |--[R]-----| 3 (TPICLK/PB1) 62 | ----------+ +---------------- 63 | * * 64 | ----------+ +---------------- 65 | (HVP) 9 |--- | 6 (RESET#/PB3) 66 | | | 67 | * * 68 | -[R]- = a 220 - 1K Ohm resistor 69 | * * 70 | this picture : 2011/12/08 by pcm1723 71 | modified :2015/02/27 by KD 72 | * * 73 | thanks to pcm1723 for tpitest.pde upon which 74 | this is based 75 | ************************************************** 76 | Updates: 77 | May 02, 2018: kimio.kosaka@gmail.com 78 | Added 'I' command 79 | Apr 02, 2018: Ksdsksd@gmail.com 80 | Added Lock bit setting to main menu 81 | Jan 23, 2017: Ksdsksd@gmail.com 82 | Thanks to InoueTaichi Fixed incorrect #define Tiny40 83 | Mar 05, 2015: Ksdsksd@gamil.com 84 | Added notifications to setting and clearing the system flags. 85 | Feb 23, 2015: Ksdsksd@gamil.com 86 | Changed the programmer Diagram, This is the config I use, and get a sucessful programming of a tiny10 at 9600 baud. 87 | Mar 22, 2014: Ksdsksd@gmail.com 88 | Added the quick reset to high before resetting the device. 89 | Added code to stop the SPI and float the pins for testing the device while connected. 90 | Mar 20, 2014: Ksdsksd@gmail.com 91 | Added a quick reset by sending 'r' or 'R' via the serial monitor. 92 | Added a High voltage programming option from pin 9, toggled by 'H' 93 | Added a High/low option for providing 12v to the reset pin, toggled by 'T' 94 | Mar 17, 2014: Ksdsksd@gmail.com 95 | Had some trouble with the nibbles being swapped when programming on the 10 & 20, 96 | added b1,b2 to hold the serial data before calling byteval() 97 | Added Nat Blundell's patch to the code 98 | Apr 10, 2013: Ksdsksd@gmail.com 99 | Applied Fix for setting and clearing flags 100 | Feb 7, 2013: Ksdsksd@gmail.com 101 | Fixed programming timer, had intitial start at zero instead of current time. 102 | Dec 11, 2012: Ksdsksd@gmail.com 103 | Added detect and programming for 4/5/9 104 | Dec 5-6, 2012: Ksdsksd@gmail.com 105 | Incorperated read, and verify into program. Now have no program size limitation by using 328p. 106 | Changed the outHex routines consolidated them into 1, number to be printed, and number of nibbles 107 | Added a type check to distinguish between Tiny10/20/40 108 | Added an auto word size check to ensure that there is the proper amount of words written for a 10/20/40 109 | Removed Read program, Verify, and Finish from options 110 | Changed baud rate to 19200 for delay from data written to the chip, to prevent serial buffer overrun. 111 | Oct 5, 2012: Ksdsksd@gmail.com 112 | *** Noticed that when programming, the verification fails 113 | at times by last 1-2 bytes programmed, and the Tiny would act erratic. 114 | Quick fix was adding 3 NOP's to the end the Tiny's code, and ignoring the errors, the Tiny then performed as expected. 115 | Oct 4, 2012: Ksdsksd@gmail.com 116 | Moved all Serial printed strings to program space 117 | Added code to detect Tiny20 118 | */ 119 | 120 | 121 | 122 | 123 | 124 | 125 | #include 126 | #include "pins_arduino.h" 127 | 128 | // define the instruction set bytes 129 | #define SLD 0x20 130 | #define SLDp 0x24 131 | #define SST 0x60 132 | #define SSTp 0x64 133 | #define SSTPRH 0x69 134 | #define SSTPRL 0x68 135 | // see functions below //////////////////////////////// 136 | // SIN 0b0aa1aaaa replace a with 6 address bits 137 | // SOUT 0b1aa1aaaa replace a with 6 address bits 138 | // SLDCS 0b1000aaaa replace a with address bits 139 | // SSTCS 0b1100aaaa replace a with address bits 140 | /////////////////////////////////////////////////////// 141 | #define SKEY 0xE0 142 | #define NVM_PROGRAM_ENABLE 0x1289AB45CDD888FFULL // the ULL means unsigned long long 143 | 144 | #define NVMCMD 0x33 145 | #define NVMCSR 0x32 146 | #define NVM_NOP 0x00 147 | #define NVM_CHIP_ERASE 0x10 148 | #define NVM_SECTION_ERASE 0x14 149 | #define NVM_WORD_WRITE 0x1D 150 | 151 | #define HVReset 9 152 | 153 | #define Tiny4_5 10 154 | #define Tiny9 1 155 | #define Tiny10 1 156 | #define Tiny20 2 157 | #define Tiny40 4 158 | 159 | #define TimeOut 1 160 | #define HexError 2 161 | #define TooLarge 3 162 | 163 | #define BAUDRATE_TPI 9600 164 | 165 | // represents the current pointer register value 166 | unsigned short adrs = 0x0000; 167 | 168 | // used for storing a program file 169 | uint8_t data[16]; //program data 170 | unsigned int progSize = 0; //program size in bytes 171 | 172 | // used for various purposes 173 | long startTime; 174 | int timeout; 175 | uint8_t b, b1, b2, b3; 176 | boolean idChecked; 177 | boolean correct; 178 | char type; // type of chip connected 1 = Tiny10, 2 = Tiny20 179 | char HVP = 0; 180 | char HVON = 0; 181 | 182 | 183 | 184 | // ATTiny_4_5_9_10_20_40Programmer SETUP 185 | void tpi_setup() { 186 | // set up serial 187 | // Serial.begin(BAUDRATE_TPI); // you cant increase this, it'll overrun the buffer 188 | // set up SPI 189 | /* SPI.begin(); 190 | SPI.setBitOrder(LSBFIRST); 191 | SPI.setDataMode(SPI_MODE0); 192 | SPI.setClockDivider(SPI_CLOCK_DIV32); 193 | */ start_tpi(); 194 | 195 | pinMode(HVReset, OUTPUT); 196 | // initialize memory pointer register 197 | setPointer(0x0000); 198 | 199 | timeout = 20000; 200 | idChecked = false; 201 | tpi_loop(); 202 | } // end setup() 203 | 204 | 205 | void hvserial() 206 | { 207 | if (HVP) 208 | Serial.println(F("***High Voltage Programming Enabled***")); 209 | else 210 | Serial.println(F("High Voltage Programming Disabled")); 211 | 212 | Serial.print(F("Pin 9 ")); 213 | Serial.print(HVON ? F("HIGH") : F("LOW")); 214 | Serial.print(F(" supplies 12v")); 215 | 216 | } 217 | 218 | 219 | void hvReset(char highLow) 220 | { 221 | if (HVP) 222 | { 223 | if (HVON) //if high enables 12v 224 | highLow = !highLow; // invert the typical reset 225 | digitalWrite(HVReset, highLow); 226 | } 227 | else 228 | digitalWrite(SS, highLow); 229 | } 230 | 231 | void quickReset() 232 | { 233 | digitalWrite(SS, HIGH); 234 | delay(1); 235 | digitalWrite(SS, LOW); 236 | delay(10); 237 | digitalWrite(SS, HIGH); 238 | } 239 | 240 | void start_tpi() { 241 | SPI.begin(); 242 | SPI.setBitOrder(LSBFIRST); 243 | SPI.setDataMode(SPI_MODE0); 244 | SPI.setClockDivider(SPI_CLOCK_DIV32); 245 | 246 | // enter TPI programming mode 247 | hvReset(LOW); 248 | // digitalWrite(SS, LOW); // assert RESET on tiny 249 | delay(1); // t_RST min = 400 ns @ Vcc = 5 V 250 | 251 | SPI.transfer(0xff); // activate TPI by emitting 252 | SPI.transfer(0xff); // 16 or more pulses on TPICLK 253 | SPI.transfer(0xff); // while holding TPIDATA to "1" 254 | 255 | writeCSS(0x02, 0x04); // TPIPCR, guard time = 8bits (default=128) 256 | 257 | send_skey(NVM_PROGRAM_ENABLE); // enable NVM interface 258 | // wait for NVM to be enabled 259 | while ((readCSS(0x00) & 0x02) < 1) { 260 | // wait 261 | } 262 | Serial.println(F("NVM enabled")); 263 | } 264 | 265 | void setLockBits() { 266 | 267 | Serial.print(F("Locking... Are you sure? Y/N")); 268 | while (Serial.available() < 1); 269 | char yn = Serial.read(); 270 | if (yn == 'n' || yn == 'N') 271 | return; 272 | 273 | setPointer(0x3F00); 274 | writeIO(NVMCMD, NVM_WORD_WRITE); 275 | tpi_send_byte(SSTp); 276 | tpi_send_byte(0); 277 | 278 | tpi_send_byte(SSTp); 279 | tpi_send_byte(0xFF); 280 | 281 | 282 | while ((readIO(NVMCSR) & (1 << 7)) != 0x00); 283 | Serial.print(F("Locked...")); 284 | } 285 | 286 | 287 | 288 | // ATTiny_4_5_9_10_20_40Programmer LOOP 289 | 290 | void tpi_loop() { 291 | while(1){ 292 | if (!idChecked) { 293 | // start_tpi(); 294 | checkID(); 295 | idChecked = true; 296 | finish(); 297 | } 298 | // when ready, send ready signal '.' and wait 299 | Serial.print(F("\n>")); 300 | while (Serial.available() < 1) { 301 | // wait 302 | } 303 | start_tpi(); 304 | 305 | // the first byte is a command 306 | //** 'P' = program the ATtiny using the read program 307 | //** 'D' = dump memory to serial monitor 308 | //** 'E' = erase chip. erases current program memory.(done automatically by 'P') 309 | //** 'S' = set fuse 310 | //** 'C' = clear fuse 311 | //** 'L' = Set Lock Bits 312 | //** 'I' = Check the device ID 313 | 314 | 315 | char comnd = Sread(); 316 | 317 | switch ( comnd ) { 318 | case 'r': 319 | case'R': 320 | quickReset(); 321 | break; 322 | 323 | case 'D': 324 | dumpMemory(); 325 | break; 326 | 327 | case 'H': 328 | HVP = !HVP; 329 | hvserial(); 330 | break; 331 | 332 | case 'T': 333 | HVON = !HVON; 334 | hvserial(); 335 | break; 336 | 337 | 338 | case 'P': 339 | if (!writeProgram()) { 340 | startTime = millis(); 341 | while (millis() - startTime < 8000) 342 | Serial.read();// if exited due to error, disregard all other serial data 343 | } 344 | 345 | break; 346 | 347 | case 'E': 348 | eraseChip(); 349 | break; 350 | 351 | case 'S': 352 | setConfig(true); 353 | break; 354 | 355 | case 'C': 356 | setConfig(false); 357 | break; 358 | 359 | case 'L': 360 | setLockBits(); 361 | break; 362 | 363 | case 'I': 364 | checkID(); 365 | break; 366 | 367 | default: 368 | Serial.println(F("Received unknown command")); 369 | } 370 | 371 | finish(); 372 | } 373 | } 374 | 375 | void ERROR_pgmSize(void) 376 | { 377 | Serial.println(F("program size is 0??")); 378 | } 379 | 380 | void ERROR_data(char i) 381 | { 382 | Serial.println(F("couldn't receive data:")); 383 | switch (i) { 384 | case TimeOut: 385 | Serial.println(F("timed out")); 386 | break; 387 | case HexError: 388 | Serial.println(F("hex file format error")); 389 | break; 390 | case TooLarge: 391 | Serial.println(F("program is too large")); 392 | break; 393 | 394 | default: 395 | break; 396 | } 397 | 398 | } 399 | 400 | 401 | // print the register, SRAM, config and signature memory 402 | void dumpMemory() { 403 | unsigned int len; 404 | uint8_t i; 405 | // initialize memory pointer register 406 | setPointer(0x0000); 407 | 408 | Serial.println(F("Current memory state:")); 409 | if (type != Tiny4_5) 410 | len = 0x400 * type; //the memory length for a 10/20/40 is 1024/2048/4096 411 | else 412 | len = 0x200; //tiny 4/5 has 512 bytes 413 | len += 0x4000; 414 | 415 | while (adrs < len) { 416 | // read the byte at the current pointer address 417 | // and increment address 418 | tpi_send_byte(SLDp); 419 | b = tpi_receive_byte(); // get data byte 420 | 421 | // read all the memory, but only print 422 | // the register, SRAM, config and signature memory 423 | if ((0x0000 <= adrs && adrs <= 0x005F) // register/SRAM 424 | | (0x3F00 <= adrs && adrs <= 0x3F01) // NVM lock bits 425 | | (0x3F40 <= adrs && adrs <= 0x3F41) // config 426 | | (0x3F80 <= adrs && adrs <= 0x3F81) // calibration 427 | | (0x3FC0 <= adrs && adrs <= 0x3FC3) // ID 428 | | (0x4000 <= adrs && adrs <= len - 1) ) { // program 429 | // print +number along the top 430 | if ((0x00 == adrs) 431 | | (0x3f00 == adrs) // NVM lock bits 432 | | (0x3F40 == adrs) // config 433 | | (0x3F80 == adrs) // calibration 434 | | (0x3FC0 == adrs) // ID 435 | | (0x4000 == adrs) ) { 436 | Serial.println(); 437 | if (adrs == 0x0000) { 438 | Serial.print(F("registers, SRAM")); 439 | } 440 | if (adrs == 0x3F00) { 441 | Serial.print(F("NVM lock")); 442 | } 443 | if (adrs == 0x3F40) { 444 | Serial.print(F("configuration")); 445 | } 446 | if (adrs == 0x3F80) { 447 | Serial.print(F("calibration")); 448 | } 449 | if (adrs == 0x3FC0) { 450 | Serial.print(F("device ID")); 451 | } 452 | if (adrs == 0x4000) { 453 | Serial.print(F("program")); 454 | } 455 | Serial.println(); 456 | for (i = 0; i < 5; i++) 457 | Serial.print(F(" ")); 458 | for (i = 0; i < 16; i++) { 459 | Serial.print(F(" +")); 460 | Serial.print(i, HEX); 461 | } 462 | } 463 | // print number on the left 464 | if (0 == (0x000f & adrs)) { 465 | Serial.println(); 466 | outHex(adrs, 4); 467 | Serial.print(F(": ")); // delimiter 468 | } 469 | outHex(b, 2); 470 | Serial.print(F(" ")); 471 | } 472 | adrs++; // increment memory address 473 | if (adrs == 0x0060) { 474 | // skip reserved memory 475 | setPointer(0x3F00); 476 | } 477 | } 478 | Serial.println(F(" ")); 479 | } // end dumpMemory() 480 | 481 | 482 | // receive and translate the contents of a hex file, Program and verify on the fly 483 | boolean writeProgram() { 484 | char datlength[] = "00"; 485 | char addr[] = "0000"; 486 | char something[] = "00"; 487 | char chksm[] = "00"; 488 | unsigned int currentByte = 0; 489 | progSize = 0; 490 | uint8_t linelength = 0; 491 | boolean fileEnd = false; 492 | unsigned short tadrs; 493 | tadrs = adrs = 0x4000; 494 | correct = true; 495 | unsigned long pgmStartTime = millis(); 496 | eraseChip(); // erase chip 497 | char words = (type != Tiny4_5 ? type : 1); 498 | char b1, b2; 499 | // read in the data and 500 | while (!fileEnd) { 501 | startTime = millis(); 502 | while (Serial.available() < 1) { 503 | if (millis() - startTime > timeout) { 504 | ERROR_data(TimeOut); 505 | return false; 506 | } 507 | if (pgmStartTime == 0) 508 | pgmStartTime = millis(); 509 | } 510 | if (Sread() != ':') { // maybe it was a newline?? 511 | if (Sread() != ':') { 512 | ERROR_data(HexError); 513 | return false; 514 | } 515 | } 516 | // read data length 517 | 518 | datlength[0] = Sread(); 519 | datlength[1] = Sread(); 520 | linelength = byteval(datlength[0], datlength[1]); 521 | 522 | // read address. if "0000" currentByte = 0 523 | addr[0] = Sread(); 524 | addr[1] = Sread(); 525 | addr[2] = Sread(); 526 | addr[3] = Sread(); 527 | if (linelength != 0x00 && addr[0] == '0' && addr[1] == '0' && addr[2] == '0' && addr[3] == '0') 528 | currentByte = 0; 529 | 530 | // read type thingy. "01" means end of file 531 | something[0] = Sread(); 532 | something[1] = Sread(); 533 | if (something[1] == '1') { 534 | fileEnd = true; 535 | } 536 | 537 | if (something[1] == '2') { 538 | for (int i = 0; i <= linelength; i++) { 539 | Sread(); 540 | Sread(); 541 | } 542 | 543 | } 544 | else { 545 | // read in the data 546 | for (int k = 0; k < linelength; k++) { 547 | while (Serial.available() < 1) { 548 | if (millis() - startTime > timeout) { 549 | ERROR_data(TimeOut); 550 | return false; 551 | } 552 | } 553 | b1 = Sread(); 554 | b2 = Sread(); 555 | data[currentByte] = byteval(b1, b2); 556 | currentByte++; 557 | progSize++; 558 | if (progSize > (type != Tiny4_5 ? type * 1024 : 512)) { 559 | ERROR_data(TooLarge); 560 | return 0; 561 | } 562 | 563 | 564 | if (fileEnd) //has the end of the file been reached? 565 | while (currentByte < 2 * words) { // append zeros to align the word count to program 566 | data[currentByte] = 0; 567 | currentByte++; 568 | } 569 | 570 | 571 | 572 | if ( currentByte == 2 * words ) { // is the word/Dword/Qword here? 573 | 574 | currentByte = 0; // yes, reset counter 575 | setPointer(tadrs); // point to the address to program 576 | writeIO(NVMCMD, NVM_WORD_WRITE); 577 | for (int i = 0; i < 2 * words; i += 2) { // loop for each word size depending on micro 578 | 579 | // now write a word to program memory 580 | tpi_send_byte(SSTp); 581 | tpi_send_byte(data[i]); // LSB first 582 | tpi_send_byte(SSTp); 583 | tpi_send_byte(data[i + 1]); // then MSB 584 | SPI.transfer(0xff); //send idle between words 585 | SPI.transfer(0xff); //send idle between words 586 | } 587 | while ((readIO(NVMCSR) & (1 << 7)) != 0x00) {} // wait for write to finish 588 | 589 | writeIO(NVMCMD, NVM_NOP); 590 | SPI.transfer(0xff); 591 | SPI.transfer(0xff); 592 | 593 | 594 | //verify written words 595 | setPointer(tadrs); 596 | for (int c = 0; c < 2 * words; c++) { 597 | tpi_send_byte(SLDp); 598 | b = tpi_receive_byte(); // get data byte 599 | 600 | if (b != data[c]) { 601 | correct = false; 602 | Serial.println(F("program error:")); 603 | Serial.print(F("byte ")); 604 | outHex(adrs, 4); 605 | Serial.print(F(" expected ")); 606 | outHex(data[c], 2); 607 | Serial.print(F(" read ")); 608 | outHex(b, 2); 609 | Serial.println(); 610 | 611 | if (!correct) 612 | return false; 613 | } 614 | } 615 | tadrs += 2 * words; 616 | } 617 | } 618 | 619 | // read in the checksum. 620 | startTime = millis(); 621 | while (Serial.available() == 0) { 622 | if (millis() - startTime > timeout) { 623 | ERROR_data(TimeOut); 624 | return false; 625 | } 626 | } 627 | chksm[0] = Sread(); 628 | chksm[1] = Sread(); 629 | 630 | } 631 | } 632 | // the program was successfully written 633 | Serial.print(F("Successfully wrote program: ")); 634 | Serial.print(progSize, DEC); 635 | Serial.print(F(" of ")); 636 | if (type != Tiny4_5) 637 | Serial.print(1024 * type, DEC); 638 | else 639 | Serial.print(512, DEC); 640 | Serial.print(F(" bytes\n in ")); 641 | Serial.print((millis() - pgmStartTime) / 1000.0, DEC); 642 | Serial.print(F(" Seconds")); 643 | // digitalWrite(SS, HIGH); // release RESET 644 | 645 | return true; 646 | } 647 | 648 | 649 | void eraseChip() { 650 | // initialize memory pointer register 651 | setPointer(0x4001); // need the +1 for chip erase 652 | 653 | // erase the chip 654 | writeIO(NVMCMD, NVM_CHIP_ERASE); 655 | tpi_send_byte(SSTp); 656 | tpi_send_byte(0xAA); 657 | tpi_send_byte(SSTp); 658 | tpi_send_byte(0xAA); 659 | tpi_send_byte(SSTp); 660 | tpi_send_byte(0xAA); 661 | tpi_send_byte(SSTp); 662 | tpi_send_byte(0xAA); 663 | while ((readIO(NVMCSR) & (1 << 7)) != 0x00) { 664 | // wait for erasing to finish 665 | } 666 | Serial.println(F("chip erased")); 667 | } 668 | 669 | void setConfig(boolean val) { 670 | // get current config byte 671 | setPointer(0x3F40); 672 | tpi_send_byte(SLD); 673 | b = tpi_receive_byte(); 674 | 675 | Serial.println(F("input one of these letters")); 676 | Serial.println(F("c = system clock output")); 677 | Serial.println(F("w = watchdog timer on")); 678 | Serial.println(F("r = disable reset")); 679 | Serial.println(F("x = cancel. don't change anything")); 680 | 681 | while (Serial.available() < 1) { 682 | // wait 683 | } 684 | char comnd = Serial.read(); 685 | setPointer(0x3F40); 686 | writeIO(NVMCMD, (val ? NVM_WORD_WRITE : NVM_SECTION_ERASE) ); 687 | 688 | if (comnd == 'c') { 689 | tpi_send_byte(SSTp); 690 | if (val) { 691 | tpi_send_byte(b & 0b11111011); 692 | } else { 693 | tpi_send_byte(b | 0x04); 694 | } 695 | tpi_send_byte(SSTp); 696 | tpi_send_byte(0xFF); 697 | } else if (comnd == 'w') { 698 | tpi_send_byte(SSTp); 699 | if (val) { 700 | tpi_send_byte(b & 0b11111101); 701 | } else { 702 | tpi_send_byte(b | 0x02); 703 | } 704 | tpi_send_byte(SSTp); 705 | tpi_send_byte(0xFF); 706 | } else if (comnd == 'r') { 707 | tpi_send_byte(SSTp); 708 | if (val) { 709 | tpi_send_byte(b & 0b11111110); 710 | } else { 711 | tpi_send_byte(b | 0x01); 712 | } 713 | tpi_send_byte(SSTp); 714 | tpi_send_byte(0xFF); 715 | } else if (comnd == 'x') { 716 | // do nothing 717 | } else { 718 | Serial.println(F("received unknown command. Cancelling")); 719 | } 720 | while ((readIO(NVMCSR) & (1 << 7)) != 0x00) { 721 | // wait for write to finish 722 | } 723 | writeIO(NVMCMD, NVM_NOP); 724 | SPI.transfer(0xff); 725 | SPI.transfer(0xff); 726 | if (comnd != 'x') { 727 | 728 | Serial.print(F("\n\nSuccessfully ")); 729 | if (val) 730 | Serial.print(F("Set ")); 731 | else 732 | Serial.print(F("Cleared ")); 733 | 734 | Serial.print(F("\"")); 735 | if (comnd == 'w') 736 | Serial.print(F("Watchdog")); 737 | else if (comnd == 'c') 738 | Serial.print(F("Clock Output")); 739 | else if (comnd == 'r') 740 | Serial.print(F("Reset")); 741 | 742 | Serial.println(F("\" Flag\n")); 743 | 744 | } 745 | } 746 | 747 | void finish() { 748 | writeCSS(0x00, 0x00); 749 | SPI.transfer(0xff); 750 | SPI.transfer(0xff); 751 | hvReset(HIGH); 752 | // digitalWrite(SS, HIGH); // release RESET 753 | delay(1); // t_RST min = 400 ns @ Vcc = 5 V 754 | SPI.end(); 755 | DDRB &= 0b11000011; //tri-state spi so target can be tested 756 | PORTB &= 0b11000011; 757 | } 758 | 759 | void checkID() { 760 | // check the device ID 761 | uint8_t id1, id2, id3; 762 | setPointer(0x3FC0); 763 | 764 | tpi_send_byte(SLDp); 765 | id1 = tpi_receive_byte(); 766 | tpi_send_byte(SLDp); 767 | id2 = tpi_receive_byte(); 768 | tpi_send_byte(SLDp); 769 | id3 = tpi_receive_byte(); 770 | if (id1 == 0x1E && id2 == 0x8F && id3 == 0x0A) { 771 | Serial.print(F("ATtiny4")); 772 | type = Tiny4_5; 773 | } else if (id1 == 0x1E && id2 == 0x8F && id3 == 0x09) { 774 | Serial.print(F("ATtiny5")); 775 | type = Tiny4_5; 776 | } else if (id1 == 0x1E && id2 == 0x90 && id3 == 0x08) { 777 | Serial.print(F("ATtiny9")); 778 | type = Tiny9; 779 | } else if (id1 == 0x1E && id2 == 0x90 && id3 == 0x03) { 780 | Serial.print(F("ATtiny10")); 781 | type = Tiny10; 782 | } else if (id1 == 0x1E && id2 == 0x91 && id3 == 0x0f) { 783 | Serial.print(F("ATtiny20")); 784 | type = Tiny20; 785 | } else if (id1 == 0x1E && id2 == 0x92 && id3 == 0x0e) { 786 | Serial.print(F("ATtiny40")); 787 | type = Tiny40; 788 | } else { 789 | Serial.print(F("Unknown chip")); 790 | } 791 | Serial.println(F(" connected")); 792 | } 793 | 794 | /* 795 | send a byte in one TPI frame (12 bits) 796 | (1 start + 8 data + 1 parity + 2 stop) 797 | using 2 SPI data bytes (2 x 8 = 16 clocks) 798 | (with 4 extra idle bits) 799 | */ 800 | void tpi_send_byte( uint8_t data ) { 801 | // compute partiy bit 802 | uint8_t par = data; 803 | par ^= (par >> 4); // b[7:4] (+) b[3:0] 804 | par ^= (par >> 2); // b[3:2] (+) b[1:0] 805 | par ^= (par >> 1); // b[1] (+) b[0] 806 | 807 | // REMEMBER: this is in LSBfirst mode and idle is high 808 | // (2 idle) + (1 start bit) + (data[4:0]) 809 | SPI.transfer(0x03 | (data << 3)); 810 | // (data[7:5]) + (1 parity) + (2 stop bits) + (2 idle) 811 | SPI.transfer(0xf0 | (par << 3) | (data >> 5)); 812 | } // end tpi_send_byte() 813 | 814 | /* 815 | receive TPI 12-bit format byte data 816 | via SPI 2 bytes (16 clocks) or 3 bytes (24 clocks) 817 | */ 818 | uint8_t tpi_receive_byte( void ) { 819 | //uint8_t b1, b2, b3; 820 | // keep transmitting high(idle) while waiting for a start bit 821 | do { 822 | b1 = SPI.transfer(0xff); 823 | } while (0xff == b1); 824 | // get (partial) data bits 825 | b2 = SPI.transfer(0xff); 826 | // if the first byte(b1) contains less than 4 data bits 827 | // we need to get a third byte to get the parity and stop bits 828 | if (0x0f == (0x0f & b1)) { 829 | b3 = SPI.transfer(0xff); 830 | } 831 | 832 | // now shift the bits into the right positions 833 | // b1 should hold only idle and start bits = 0b01111111 834 | while (0x7f != b1) { // data not aligned 835 | b2 <<= 1; // shift left data bits 836 | if (0x80 & b1) { // carry from 1st byte 837 | b2 |= 1; // set bit 838 | } 839 | b1 <<= 1; 840 | b1 |= 0x01; // fill with idle bit (1) 841 | } 842 | // now the data byte is stored in b2 843 | return ( b2 ); 844 | } // end tpi_receive_byte() 845 | 846 | // send the 64 bit NVM key 847 | void send_skey(uint64_t nvm_key) { 848 | tpi_send_byte(SKEY); 849 | while (nvm_key) { 850 | tpi_send_byte(nvm_key & 0xFF); 851 | nvm_key >>= 8; 852 | } 853 | } // end send_skey() 854 | 855 | // sets the pointer address 856 | void setPointer(unsigned short address) { 857 | adrs = address; 858 | tpi_send_byte(SSTPRL); 859 | tpi_send_byte(address & 0xff); 860 | tpi_send_byte(SSTPRH); 861 | tpi_send_byte((address >> 8) & 0xff); 862 | } 863 | 864 | // writes using SOUT 865 | void writeIO(uint8_t address, uint8_t value) { 866 | // SOUT 0b1aa1aaaa replace a with 6 address bits 867 | tpi_send_byte(0x90 | (address & 0x0F) | ((address & 0x30) << 1)); 868 | tpi_send_byte(value); 869 | } 870 | 871 | // reads using SIN 872 | uint8_t readIO(uint8_t address) { 873 | // SIN 0b0aa1aaaa replace a with 6 address bits 874 | tpi_send_byte(0x10 | (address & 0x0F) | ((address & 0x30) << 1)); 875 | return tpi_receive_byte(); 876 | } 877 | 878 | // writes to CSS 879 | void writeCSS(uint8_t address, uint8_t value) { 880 | tpi_send_byte(0xC0 | address); 881 | tpi_send_byte(value); 882 | } 883 | 884 | // reads from CSS 885 | uint8_t readCSS(uint8_t address) { 886 | tpi_send_byte(0x80 | address); 887 | return tpi_receive_byte(); 888 | } 889 | 890 | // converts two chars to one byte 891 | // c1 is MS, c2 is LS 892 | uint8_t byteval(char c1, char c2) { 893 | uint8_t by; 894 | if (c1 <= '9') { 895 | by = c1 - '0'; 896 | } else { 897 | by = c1 - 'A' + 10; 898 | } 899 | by = by << 4; 900 | if (c2 <= '9') { 901 | by += c2 - '0'; 902 | } else { 903 | by += c2 - 'A' + 10; 904 | } 905 | return by; 906 | } 907 | 908 | char Sread(void) { 909 | while (Serial.available() < 1) {} 910 | return Serial.read(); 911 | } 912 | 913 | 914 | void outHex(unsigned int n, char l) { // call with the number to be printed, and # of nibbles expected. 915 | for (char count = l - 1; count > 0; count--) { // quick and dirty to add zeros to the hex value 916 | if (((n >> (count * 4)) & 0x0f) == 0) // if MSB is 0 917 | Serial.print(F("0")); //prepend a 0 918 | else 919 | break; //exit the for loop 920 | } 921 | Serial.print(n, HEX); 922 | } 923 | 924 | // end of ATtiny_4_5_9_10_20_40Programmer 925 | /*******************************************************************************************************/ 926 | 927 | 928 | // ArduinoISP 929 | // Copyright (c) 2008-2011 Randall Bohn 930 | // If you require a license, see 931 | // http://www.opensource.org/licenses/bsd-license.php 932 | // 933 | // This sketch turns the Arduino into a AVRISP using the following Arduino pins: 934 | // 935 | // Pin 10 is used to reset the target microcontroller. 936 | // 937 | // By default, the hardware SPI pins MISO, MOSI and SCK are used to communicate 938 | // with the target. On all Arduinos, these pins can be found 939 | // on the ICSP/SPI header: 940 | // 941 | // MISO °. . 5V (!) Avoid this pin on Due, Zero... 942 | // SCK . . MOSI 943 | // . . GND 944 | // 945 | // On some Arduinos (Uno,...), pins MOSI, MISO and SCK are the same pins as 946 | // digital pin 11, 12 and 13, respectively. That is why many tutorials instruct 947 | // you to hook up the target to these pins. If you find this wiring more 948 | // practical, have a define USE_OLD_STYLE_WIRING. This will work even when not 949 | // using an Uno. (On an Uno this is not needed). 950 | // 951 | // Alternatively you can use any other digital pin by configuring 952 | // software ('BitBanged') SPI and having appropriate defines for PIN_MOSI, 953 | // PIN_MISO and PIN_SCK. 954 | // 955 | // IMPORTANT: When using an Arduino that is not 5V tolerant (Due, Zero, ...) as 956 | // the programmer, make sure to not expose any of the programmer's pins to 5V. 957 | // A simple way to accomplish this is to power the complete system (programmer 958 | // and target) at 3V3. 959 | // 960 | // Put an LED (with resistor) on the following pins: 961 | // 9: Heartbeat - shows the programmer is running 962 | // 8: Error - Lights up if something goes wrong (use red if that makes sense) 963 | // 7: Programming - In communication with the slave 964 | // 965 | 966 | #include "Arduino.h" 967 | #undef SERIAL 968 | 969 | 970 | #define PROG_FLICKER true 971 | 972 | // Configure SPI clock (in Hz). 973 | // E.g. for an ATtiny @ 128 kHz: the datasheet states that both the high and low 974 | // SPI clock pulse must be > 2 CPU cycles, so take 3 cycles i.e. divide target 975 | // f_cpu by 6: 976 | // #define SPI_CLOCK (128000/6) 977 | // 978 | // A clock slow enough for an ATtiny85 @ 1 MHz, is a reasonable default: 979 | 980 | #define SPI_CLOCK (1000000/6) 981 | 982 | 983 | // Select hardware or software SPI, depending on SPI clock. 984 | // Currently only for AVR, for other architectures (Due, Zero,...), hardware SPI 985 | // is probably too fast anyway. 986 | 987 | #if defined(ARDUINO_ARCH_AVR) 988 | 989 | #if SPI_CLOCK > (F_CPU / 128) 990 | #define USE_HARDWARE_SPI 991 | #endif 992 | 993 | #endif 994 | 995 | // Configure which pins to use: 996 | 997 | // The standard pin configuration. 998 | #ifndef ARDUINO_HOODLOADER2 999 | 1000 | #define RESET 10 // Use pin 10 to reset the target rather than SS 1001 | #define LED_HB 9 1002 | #define LED_ERR 8 1003 | #define LED_PMODE 7 1004 | 1005 | // Uncomment following line to use the old Uno style wiring 1006 | // (using pin 11, 12 and 13 instead of the SPI header) on Leonardo, Due... 1007 | 1008 | // #define USE_OLD_STYLE_WIRING 1009 | 1010 | #ifdef USE_OLD_STYLE_WIRING 1011 | 1012 | #define PIN_MOSI 11 1013 | #define PIN_MISO 12 1014 | #define PIN_SCK 13 1015 | 1016 | #endif 1017 | 1018 | // HOODLOADER2 means running sketches on the ATmega16U2 serial converter chips 1019 | // on Uno or Mega boards. We must use pins that are broken out: 1020 | #else 1021 | 1022 | #define RESET 4 1023 | #define LED_HB 7 1024 | #define LED_ERR 6 1025 | #define LED_PMODE 5 1026 | 1027 | #endif 1028 | 1029 | // By default, use hardware SPI pins: 1030 | #ifndef PIN_MOSI 1031 | #define PIN_MOSI MOSI 1032 | #endif 1033 | 1034 | #ifndef PIN_MISO 1035 | #define PIN_MISO MISO 1036 | #endif 1037 | 1038 | #ifndef PIN_SCK 1039 | #define PIN_SCK SCK 1040 | #endif 1041 | 1042 | // Force bitbanged SPI if not using the hardware SPI pins: 1043 | #if (PIN_MISO != MISO) || (PIN_MOSI != MOSI) || (PIN_SCK != SCK) 1044 | #undef USE_HARDWARE_SPI 1045 | #endif 1046 | 1047 | 1048 | // Configure the serial port to use. 1049 | // 1050 | // Prefer the USB virtual serial port (aka. native USB port), if the Arduino has one: 1051 | // - it does not autoreset (except for the magic baud rate of 1200). 1052 | // - it is more reliable because of USB handshaking. 1053 | // 1054 | // Leonardo and similar have an USB virtual serial port: 'Serial'. 1055 | // Due and Zero have an USB virtual serial port: 'SerialUSB'. 1056 | // 1057 | // On the Due and Zero, 'Serial' can be used too, provided you disable autoreset. 1058 | // To use 'Serial': #define SERIAL Serial 1059 | 1060 | #ifdef SERIAL_PORT_USBVIRTUAL 1061 | #define SERIAL SERIAL_PORT_USBVIRTUAL 1062 | #else 1063 | #define SERIAL Serial 1064 | #endif 1065 | 1066 | 1067 | // Configure the baud rate: 1068 | 1069 | #define BAUDRATE_SPI 19200 1070 | // #define BAUDRATE 115200 1071 | // #define BAUDRATE 1000000 1072 | 1073 | 1074 | #define HWVER 2 1075 | #define SWMAJ 1 1076 | #define SWMIN 18 1077 | 1078 | // STK Definitions 1079 | #define STK_OK 0x10 1080 | #define STK_FAILED 0x11 1081 | #define STK_UNKNOWN 0x12 1082 | #define STK_INSYNC 0x14 1083 | #define STK_NOSYNC 0x15 1084 | #define CRC_EOP 0x20 //ok it is a space... 1085 | 1086 | void pulse(int pin, int times); 1087 | 1088 | #ifdef USE_HARDWARE_SPI 1089 | #include "SPI.h" 1090 | #else 1091 | 1092 | #define SPI_MODE0 0x00 1093 | 1094 | class SPISettings { 1095 | public: 1096 | // clock is in Hz 1097 | SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) : clock(clock) { 1098 | (void) bitOrder; 1099 | (void) dataMode; 1100 | }; 1101 | 1102 | private: 1103 | uint32_t clock; 1104 | 1105 | friend class BitBangedSPI; 1106 | }; 1107 | 1108 | class BitBangedSPI { 1109 | public: 1110 | void begin() { 1111 | digitalWrite(PIN_SCK, LOW); 1112 | digitalWrite(PIN_MOSI, LOW); 1113 | pinMode(PIN_SCK, OUTPUT); 1114 | pinMode(PIN_MOSI, OUTPUT); 1115 | pinMode(PIN_MISO, INPUT); 1116 | } 1117 | 1118 | void beginTransaction(SPISettings settings) { 1119 | pulseWidth = (500000 + settings.clock - 1) / settings.clock; 1120 | if (pulseWidth == 0) 1121 | pulseWidth = 1; 1122 | } 1123 | 1124 | void end() {} 1125 | 1126 | uint8_t transfer (uint8_t b) { 1127 | for (unsigned int i = 0; i < 8; ++i) { 1128 | digitalWrite(PIN_MOSI, (b & 0x80) ? HIGH : LOW); 1129 | digitalWrite(PIN_SCK, HIGH); 1130 | delayMicroseconds(pulseWidth); 1131 | b = (b << 1) | digitalRead(PIN_MISO); 1132 | digitalWrite(PIN_SCK, LOW); // slow pulse 1133 | delayMicroseconds(pulseWidth); 1134 | } 1135 | return b; 1136 | } 1137 | 1138 | private: 1139 | unsigned long pulseWidth; // in microseconds 1140 | }; 1141 | 1142 | static BitBangedSPI SPI; 1143 | 1144 | #endif 1145 | 1146 | // ArduinoISP setup() 1147 | void isp_setup() { 1148 | // SERIAL.begin(BAUDRATE); 1149 | 1150 | pinMode(LED_PMODE, OUTPUT); 1151 | pulse(LED_PMODE, 2); 1152 | pinMode(LED_ERR, OUTPUT); 1153 | pulse(LED_ERR, 2); 1154 | pinMode(LED_HB, OUTPUT); 1155 | pulse(LED_HB, 2); 1156 | isp_loop(); 1157 | } 1158 | 1159 | int error = 0; 1160 | int pmode = 0; 1161 | // address for reading and writing, set by 'U' command 1162 | unsigned int here; 1163 | uint8_t buff[256]; // global block storage 1164 | 1165 | #define beget16(addr) (*addr * 256 + *(addr+1) ) 1166 | typedef struct param { 1167 | uint8_t devicecode; 1168 | uint8_t revision; 1169 | uint8_t progtype; 1170 | uint8_t parmode; 1171 | uint8_t polling; 1172 | uint8_t selftimed; 1173 | uint8_t lockbytes; 1174 | uint8_t fusebytes; 1175 | uint8_t flashpoll; 1176 | uint16_t eeprompoll; 1177 | uint16_t pagesize; 1178 | uint16_t eepromsize; 1179 | uint32_t flashsize; 1180 | } 1181 | parameter; 1182 | 1183 | parameter param; 1184 | 1185 | // this provides a heartbeat on pin 9, so you can tell the software is running. 1186 | uint8_t hbval = 128; 1187 | int8_t hbdelta = 8; 1188 | void heartbeat() { 1189 | static unsigned long last_time = 0; 1190 | unsigned long now = millis(); 1191 | if ((now - last_time) < 40) 1192 | return; 1193 | last_time = now; 1194 | if (hbval > 192) hbdelta = -hbdelta; 1195 | if (hbval < 32) hbdelta = -hbdelta; 1196 | hbval += hbdelta; 1197 | analogWrite(LED_HB, hbval); 1198 | } 1199 | 1200 | static bool rst_active_high; 1201 | 1202 | void reset_target(bool reset) { 1203 | digitalWrite(RESET, ((reset && rst_active_high) || (!reset && !rst_active_high)) ? HIGH : LOW); 1204 | } 1205 | 1206 | 1207 | // ArduinoISP LOOP 1208 | void isp_loop(void) { 1209 | while(1){ 1210 | // is pmode active? 1211 | if (pmode) { 1212 | digitalWrite(LED_PMODE, HIGH); 1213 | } else { 1214 | digitalWrite(LED_PMODE, LOW); 1215 | } 1216 | // is there an error? 1217 | if (error) { 1218 | digitalWrite(LED_ERR, HIGH); 1219 | } else { 1220 | digitalWrite(LED_ERR, LOW); 1221 | } 1222 | 1223 | // light the heartbeat LED 1224 | heartbeat(); 1225 | if (SERIAL.available()) { 1226 | avrisp(); 1227 | } 1228 | } 1229 | } 1230 | 1231 | uint8_t getch() { 1232 | while (!SERIAL.available()); 1233 | return SERIAL.read(); 1234 | } 1235 | void fill(int n) { 1236 | for (int x = 0; x < n; x++) { 1237 | buff[x] = getch(); 1238 | } 1239 | } 1240 | 1241 | #define PTIME 30 1242 | void pulse(int pin, int times) { 1243 | do { 1244 | digitalWrite(pin, HIGH); 1245 | delay(PTIME); 1246 | digitalWrite(pin, LOW); 1247 | delay(PTIME); 1248 | } while (times--); 1249 | } 1250 | 1251 | void prog_lamp(int state) { 1252 | if (PROG_FLICKER) { 1253 | digitalWrite(LED_PMODE, state); 1254 | } 1255 | } 1256 | 1257 | uint8_t spi_transaction(uint8_t a, uint8_t b, uint8_t c, uint8_t d) { 1258 | SPI.transfer(a); 1259 | SPI.transfer(b); 1260 | SPI.transfer(c); 1261 | return SPI.transfer(d); 1262 | } 1263 | 1264 | void empty_reply() { 1265 | if (CRC_EOP == getch()) { 1266 | SERIAL.print((char)STK_INSYNC); 1267 | SERIAL.print((char)STK_OK); 1268 | } else { 1269 | error++; 1270 | SERIAL.print((char)STK_NOSYNC); 1271 | } 1272 | } 1273 | 1274 | void breply(uint8_t b) { 1275 | if (CRC_EOP == getch()) { 1276 | SERIAL.print((char)STK_INSYNC); 1277 | SERIAL.print((char)b); 1278 | SERIAL.print((char)STK_OK); 1279 | } else { 1280 | error++; 1281 | SERIAL.print((char)STK_NOSYNC); 1282 | } 1283 | } 1284 | 1285 | void get_version(uint8_t c) { 1286 | switch (c) { 1287 | case 0x80: 1288 | breply(HWVER); 1289 | break; 1290 | case 0x81: 1291 | breply(SWMAJ); 1292 | break; 1293 | case 0x82: 1294 | breply(SWMIN); 1295 | break; 1296 | case 0x93: 1297 | breply('S'); // serial programmer 1298 | break; 1299 | default: 1300 | breply(0); 1301 | } 1302 | } 1303 | 1304 | void set_parameters() { 1305 | // call this after reading parameter packet into buff[] 1306 | param.devicecode = buff[0]; 1307 | param.revision = buff[1]; 1308 | param.progtype = buff[2]; 1309 | param.parmode = buff[3]; 1310 | param.polling = buff[4]; 1311 | param.selftimed = buff[5]; 1312 | param.lockbytes = buff[6]; 1313 | param.fusebytes = buff[7]; 1314 | param.flashpoll = buff[8]; 1315 | // ignore buff[9] (= buff[8]) 1316 | // following are 16 bits (big endian) 1317 | param.eeprompoll = beget16(&buff[10]); 1318 | param.pagesize = beget16(&buff[12]); 1319 | param.eepromsize = beget16(&buff[14]); 1320 | 1321 | // 32 bits flashsize (big endian) 1322 | param.flashsize = buff[16] * 0x01000000 1323 | + buff[17] * 0x00010000 1324 | + buff[18] * 0x00000100 1325 | + buff[19]; 1326 | 1327 | // AVR devices have active low reset, AT89Sx are active high 1328 | rst_active_high = (param.devicecode >= 0xe0); 1329 | } 1330 | 1331 | void start_pmode() { 1332 | 1333 | // Reset target before driving PIN_SCK or PIN_MOSI 1334 | 1335 | // SPI.begin() will configure SS as output, so SPI master mode is selected. 1336 | // We have defined RESET as pin 10, which for many Arduinos is not the SS pin. 1337 | // So we have to configure RESET as output here, 1338 | // (reset_target() first sets the correct level) 1339 | reset_target(true); 1340 | pinMode(RESET, OUTPUT); 1341 | SPI.begin(); 1342 | SPI.beginTransaction(SPISettings(SPI_CLOCK, MSBFIRST, SPI_MODE0)); 1343 | 1344 | // See AVR datasheets, chapter "SERIAL_PRG Programming Algorithm": 1345 | 1346 | // Pulse RESET after PIN_SCK is low: 1347 | digitalWrite(PIN_SCK, LOW); 1348 | delay(20); // discharge PIN_SCK, value arbitrarily chosen 1349 | reset_target(false); 1350 | // Pulse must be minimum 2 target CPU clock cycles so 100 usec is ok for CPU 1351 | // speeds above 20 KHz 1352 | delayMicroseconds(100); 1353 | reset_target(true); 1354 | 1355 | // Send the enable programming command: 1356 | delay(50); // datasheet: must be > 20 msec 1357 | spi_transaction(0xAC, 0x53, 0x00, 0x00); 1358 | pmode = 1; 1359 | } 1360 | 1361 | void end_pmode() { 1362 | SPI.end(); 1363 | // We're about to take the target out of reset so configure SPI pins as input 1364 | pinMode(PIN_MOSI, INPUT); 1365 | pinMode(PIN_SCK, INPUT); 1366 | reset_target(false); 1367 | pinMode(RESET, INPUT); 1368 | pmode = 0; 1369 | } 1370 | 1371 | void universal() { 1372 | uint8_t ch; 1373 | 1374 | fill(4); 1375 | ch = spi_transaction(buff[0], buff[1], buff[2], buff[3]); 1376 | breply(ch); 1377 | } 1378 | 1379 | void flash(uint8_t hilo, unsigned int addr, uint8_t data) { 1380 | spi_transaction(0x40 + 8 * hilo, 1381 | addr >> 8 & 0xFF, 1382 | addr & 0xFF, 1383 | data); 1384 | } 1385 | void commit(unsigned int addr) { 1386 | if (PROG_FLICKER) { 1387 | prog_lamp(LOW); 1388 | } 1389 | spi_transaction(0x4C, (addr >> 8) & 0xFF, addr & 0xFF, 0); 1390 | if (PROG_FLICKER) { 1391 | delay(PTIME); 1392 | prog_lamp(HIGH); 1393 | } 1394 | } 1395 | 1396 | unsigned int current_page() { 1397 | if (param.pagesize == 32) { 1398 | return here & 0xFFFFFFF0; 1399 | } 1400 | if (param.pagesize == 64) { 1401 | return here & 0xFFFFFFE0; 1402 | } 1403 | if (param.pagesize == 128) { 1404 | return here & 0xFFFFFFC0; 1405 | } 1406 | if (param.pagesize == 256) { 1407 | return here & 0xFFFFFF80; 1408 | } 1409 | return here; 1410 | } 1411 | 1412 | 1413 | void write_flash(int length) { 1414 | fill(length); 1415 | if (CRC_EOP == getch()) { 1416 | SERIAL.print((char) STK_INSYNC); 1417 | SERIAL.print((char) write_flash_pages(length)); 1418 | } else { 1419 | error++; 1420 | SERIAL.print((char) STK_NOSYNC); 1421 | } 1422 | } 1423 | 1424 | uint8_t write_flash_pages(int length) { 1425 | int x = 0; 1426 | unsigned int page = current_page(); 1427 | while (x < length) { 1428 | if (page != current_page()) { 1429 | commit(page); 1430 | page = current_page(); 1431 | } 1432 | flash(LOW, here, buff[x++]); 1433 | flash(HIGH, here, buff[x++]); 1434 | here++; 1435 | } 1436 | 1437 | commit(page); 1438 | 1439 | return STK_OK; 1440 | } 1441 | 1442 | #define EECHUNK (32) 1443 | uint8_t write_eeprom(unsigned int length) { 1444 | // here is a word address, get the byte address 1445 | unsigned int start = here * 2; 1446 | unsigned int remaining = length; 1447 | if (length > param.eepromsize) { 1448 | error++; 1449 | return STK_FAILED; 1450 | } 1451 | while (remaining > EECHUNK) { 1452 | write_eeprom_chunk(start, EECHUNK); 1453 | start += EECHUNK; 1454 | remaining -= EECHUNK; 1455 | } 1456 | write_eeprom_chunk(start, remaining); 1457 | return STK_OK; 1458 | } 1459 | // write (length) bytes, (start) is a byte address 1460 | uint8_t write_eeprom_chunk(unsigned int start, unsigned int length) { 1461 | // this writes byte-by-byte, page writing may be faster (4 bytes at a time) 1462 | fill(length); 1463 | prog_lamp(LOW); 1464 | for (unsigned int x = 0; x < length; x++) { 1465 | unsigned int addr = start + x; 1466 | spi_transaction(0xC0, (addr >> 8) & 0xFF, addr & 0xFF, buff[x]); 1467 | delay(45); 1468 | } 1469 | prog_lamp(HIGH); 1470 | return STK_OK; 1471 | } 1472 | 1473 | void program_page() { 1474 | char result = (char) STK_FAILED; 1475 | unsigned int length = 256 * getch(); 1476 | length += getch(); 1477 | char memtype = getch(); 1478 | // flash memory @here, (length) bytes 1479 | if (memtype == 'F') { 1480 | write_flash(length); 1481 | return; 1482 | } 1483 | if (memtype == 'E') { 1484 | result = (char)write_eeprom(length); 1485 | if (CRC_EOP == getch()) { 1486 | SERIAL.print((char) STK_INSYNC); 1487 | SERIAL.print(result); 1488 | } else { 1489 | error++; 1490 | SERIAL.print((char) STK_NOSYNC); 1491 | } 1492 | return; 1493 | } 1494 | SERIAL.print((char)STK_FAILED); 1495 | return; 1496 | } 1497 | 1498 | uint8_t flash_read(uint8_t hilo, unsigned int addr) { 1499 | return spi_transaction(0x20 + hilo * 8, 1500 | (addr >> 8) & 0xFF, 1501 | addr & 0xFF, 1502 | 0); 1503 | } 1504 | 1505 | char flash_read_page(int length) { 1506 | for (int x = 0; x < length; x += 2) { 1507 | uint8_t low = flash_read(LOW, here); 1508 | SERIAL.print((char) low); 1509 | uint8_t high = flash_read(HIGH, here); 1510 | SERIAL.print((char) high); 1511 | here++; 1512 | } 1513 | return STK_OK; 1514 | } 1515 | 1516 | char eeprom_read_page(int length) { 1517 | // here again we have a word address 1518 | int start = here * 2; 1519 | for (int x = 0; x < length; x++) { 1520 | int addr = start + x; 1521 | uint8_t ee = spi_transaction(0xA0, (addr >> 8) & 0xFF, addr & 0xFF, 0xFF); 1522 | SERIAL.print((char) ee); 1523 | } 1524 | return STK_OK; 1525 | } 1526 | 1527 | void read_page() { 1528 | char result = (char)STK_FAILED; 1529 | int length = 256 * getch(); 1530 | length += getch(); 1531 | char memtype = getch(); 1532 | if (CRC_EOP != getch()) { 1533 | error++; 1534 | SERIAL.print((char) STK_NOSYNC); 1535 | return; 1536 | } 1537 | SERIAL.print((char) STK_INSYNC); 1538 | if (memtype == 'F') result = flash_read_page(length); 1539 | if (memtype == 'E') result = eeprom_read_page(length); 1540 | SERIAL.print(result); 1541 | } 1542 | 1543 | void read_signature() { 1544 | if (CRC_EOP != getch()) { 1545 | error++; 1546 | SERIAL.print((char) STK_NOSYNC); 1547 | return; 1548 | } 1549 | SERIAL.print((char) STK_INSYNC); 1550 | uint8_t high = spi_transaction(0x30, 0x00, 0x00, 0x00); 1551 | SERIAL.print((char) high); 1552 | uint8_t middle = spi_transaction(0x30, 0x00, 0x01, 0x00); 1553 | SERIAL.print((char) middle); 1554 | uint8_t low = spi_transaction(0x30, 0x00, 0x02, 0x00); 1555 | SERIAL.print((char) low); 1556 | SERIAL.print((char) STK_OK); 1557 | } 1558 | ////////////////////////////////////////// 1559 | ////////////////////////////////////////// 1560 | 1561 | 1562 | //////////////////////////////////// 1563 | //////////////////////////////////// 1564 | void avrisp() { 1565 | uint8_t ch = getch(); 1566 | switch (ch) { 1567 | case '0': // signon 1568 | error = 0; 1569 | empty_reply(); 1570 | break; 1571 | case '1': 1572 | if (getch() == CRC_EOP) { 1573 | SERIAL.print((char) STK_INSYNC); 1574 | SERIAL.print("AVR ISP"); 1575 | SERIAL.print((char) STK_OK); 1576 | } 1577 | else { 1578 | error++; 1579 | SERIAL.print((char) STK_NOSYNC); 1580 | } 1581 | break; 1582 | case 'A': 1583 | get_version(getch()); 1584 | break; 1585 | case 'B': 1586 | fill(20); 1587 | set_parameters(); 1588 | empty_reply(); 1589 | break; 1590 | case 'E': // extended parameters - ignore for now 1591 | fill(5); 1592 | empty_reply(); 1593 | break; 1594 | case 'P': 1595 | if (!pmode) 1596 | start_pmode(); 1597 | empty_reply(); 1598 | break; 1599 | case 'U': // set address (word) 1600 | here = getch(); 1601 | here += 256 * getch(); 1602 | empty_reply(); 1603 | break; 1604 | 1605 | case 0x60: //STK_PROG_FLASH 1606 | getch(); // low addr 1607 | getch(); // high addr 1608 | empty_reply(); 1609 | break; 1610 | case 0x61: //STK_PROG_DATA 1611 | getch(); // data 1612 | empty_reply(); 1613 | break; 1614 | 1615 | case 0x64: //STK_PROG_PAGE 1616 | program_page(); 1617 | break; 1618 | 1619 | case 0x74: //STK_READ_PAGE 't' 1620 | read_page(); 1621 | break; 1622 | 1623 | case 'V': //0x56 1624 | universal(); 1625 | break; 1626 | case 'Q': //0x51 1627 | error = 0; 1628 | end_pmode(); 1629 | empty_reply(); 1630 | break; 1631 | 1632 | case 0x75: //STK_READ_SIGN 'u' 1633 | read_signature(); 1634 | break; 1635 | 1636 | // expecting a command, not CRC_EOP 1637 | // this is how we can get back in sync 1638 | case CRC_EOP: 1639 | error++; 1640 | SERIAL.print((char) STK_NOSYNC); 1641 | break; 1642 | 1643 | // anything else we will return STK_UNKNOWN 1644 | default: 1645 | error++; 1646 | if (CRC_EOP == getch()) 1647 | SERIAL.print((char)STK_UNKNOWN); 1648 | else 1649 | SERIAL.print((char)STK_NOSYNC); 1650 | } 1651 | } 1652 | 1653 | 1654 | 1655 | 1656 | 1657 | #define OUTPUT_LOW 2 1658 | #define SELECT_BIT 3 1659 | #define TPI_LED 4 1660 | #define SPI_LED 5 1661 | 1662 | // gorobal SETUP 1663 | void setup(){ 1664 | char swd; 1665 | 1666 | pinMode(TPI_LED,OUTPUT); 1667 | pinMode(SPI_LED,OUTPUT); 1668 | pinMode(OUTPUT_LOW,OUTPUT); 1669 | digitalWrite(TPI_LED,LOW); 1670 | digitalWrite(SPI_LED,LOW); 1671 | digitalWrite(OUTPUT_LOW,LOW); 1672 | pinMode(SELECT_BIT,INPUT_PULLUP); 1673 | 1674 | /* 1675 | while (Serial.available() <= 0); 1676 | swd = Serial.read(); 1677 | if (swd == 'I') { 1678 | digitalWrite(TPI_LED,HIGH); 1679 | tpi_setup(); 1680 | } else { 1681 | digitalWrite(SPI_LED,HIGH); 1682 | isp_setup(); 1683 | } 1684 | 1685 | */ 1686 | 1687 | if (digitalRead(SELECT_BIT) == LOW ) { 1688 | digitalWrite(TPI_LED,HIGH); 1689 | Serial.begin(BAUDRATE_TPI); 1690 | tpi_setup(); 1691 | } else { 1692 | digitalWrite(SPI_LED,HIGH); 1693 | Serial.begin(BAUDRATE_SPI); 1694 | isp_setup(); 1695 | } 1696 | 1697 | } 1698 | // Dummy LOOP 1699 | void loop(){ 1700 | 1701 | } 1702 | --------------------------------------------------------------------------------