├── README.md ├── examples └── Arduino_Wifi_AVRISP │ └── Arduino_Wifi_AVRISP.ino ├── library.properties └── src ├── ESP_AVRISP.cpp ├── ESP_AVRISP.h └── command.h /README.md: -------------------------------------------------------------------------------- 1 | # AVR In-System Programming over WiFi for ESP8266/ESP32 2 | 3 | This library allows an ESP8266/32 module with the HSPI port available to become 4 | an AVR In-System Programmer. 5 | 6 | ## Hardware 7 | 8 | The ESP module connects to the AVR target chip via the standard 6-pin 9 | AVR "Recommended In-System Programming Interface Connector Layout" as seen 10 | in [AVR910](http://www.atmel.com/images/doc0943.pdf) among other places. 11 | 12 | If the AVR target is powered by a different Vcc than what powers your ESP 13 | chip, you **must provide voltage level shifting** or some other form of buffers. 14 | Exposing the pins of ESP to anything larger than 3.6V will damage it. 15 | 16 | Connections are as follows: 17 | 18 | ESP | AVR / SPI 19 | --------|------------ 20 | GPIO12 | MISO 21 | GPIO13 | MOSI 22 | GPIO14 | SCK 23 | any* | RESET 24 | 25 | For RESET use a GPIO other than 0, 2 and 15 (bootselect pins), and apply an 26 | external pullup/down so that the target is normally running. 27 | 28 | ## Usage 29 | 30 | See the included example. In short: 31 | 32 | ```arduino 33 | 34 | // Create the programmer object 35 | ESP_AVRISP avrprog(PORT, RESET_PIN) 36 | // ... with custom SPI frequency 37 | ESP_AVRISP avrprog(PORT, RESET_PIN, 4e6) 38 | 39 | // Check current connection state, but don't perform any actions 40 | AVRISPState_t state = avrprog.update(); 41 | 42 | // Serve the pending connection, execute STK500 commands 43 | AVRISPState_t state = avrprog.serve(); 44 | ``` 45 | 46 | ### License and Authors 47 | 48 | This library started off from the source of ArduinoISP "sketch" included with 49 | the Arduino IDE: 50 | 51 | ArduinoISP version 04m3 52 | Copyright (c) 2008-2011 Randall Bohn 53 | If you require a license, see 54 | http://www.opensource.org/licenses/bsd-license.php 55 | 56 | Support for TCP on ESP8266/32 57 | Copyright (c) Kiril Zyapkov . 58 | -------------------------------------------------------------------------------- /examples/Arduino_Wifi_AVRISP/Arduino_Wifi_AVRISP.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #ifdef ESP8266 4 | #include 5 | #include 6 | #else 7 | #include 8 | #include 9 | #endif 10 | 11 | const char* host = "esp-avrisp"; 12 | const char* ssid = "**********"; 13 | const char* pass = "**********"; 14 | const uint16_t port = 328; 15 | const uint8_t reset_pin = 5; 16 | 17 | ESP_AVRISP avrprog(port, reset_pin); 18 | 19 | void setup() { 20 | Serial.begin(115200); 21 | Serial.println(""); 22 | Serial.println("Arduino AVR-ISP over TCP"); 23 | avrprog.setReset(false); // let the AVR run 24 | 25 | WiFi.begin(ssid, pass); 26 | while (WiFi.waitForConnectResult() != WL_CONNECTED); 27 | 28 | MDNS.begin(host); 29 | MDNS.addService("avrisp", "tcp", port); 30 | 31 | IPAddress local_ip = WiFi.localIP(); 32 | Serial.print("IP address: "); 33 | Serial.println(local_ip); 34 | Serial.println("Use your avrdude:"); 35 | Serial.print("avrdude -c arduino -p -P net:"); 36 | Serial.print(local_ip); 37 | Serial.print(":"); 38 | Serial.print(port); 39 | Serial.println(" -t # or -U ..."); 40 | 41 | // listen for avrdudes 42 | avrprog.begin(); 43 | } 44 | 45 | void loop() { 46 | static AVRISPState_t last_state = AVRISP_STATE_IDLE; 47 | AVRISPState_t new_state = avrprog.update(); 48 | if (last_state != new_state) { 49 | switch (new_state) { 50 | case AVRISP_STATE_IDLE: { 51 | Serial.printf("[AVRISP] now idle\r\n"); 52 | // Use the SPI bus for other purposes 53 | break; 54 | } 55 | case AVRISP_STATE_PENDING: { 56 | Serial.printf("[AVRISP] connection pending\r\n"); 57 | // Clean up your other purposes and prepare for programming mode 58 | break; 59 | } 60 | case AVRISP_STATE_ACTIVE: { 61 | Serial.printf("[AVRISP] programming mode\r\n"); 62 | // Stand by for completion 63 | break; 64 | } 65 | } 66 | last_state = new_state; 67 | } 68 | // Serve the client 69 | if (last_state != AVRISP_STATE_IDLE) { 70 | avrprog.serve(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=ESP_AVRISP 2 | version=1.0 3 | author=Kiril Zyapkov, Larry Bernstone 4 | maintainer=Larry Bernstone 5 | sentence=AVR In-System Programming over WiFi for ESP8266/32 6 | paragraph=This library allows programming 8-bit AVR ICSP targets via TCP over WiFi with ESP8266/32. 7 | category=Communication 8 | url= 9 | architectures=esp8266,esp32 10 | -------------------------------------------------------------------------------- /src/ESP_AVRISP.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | AVR In-System Programming over WiFi for ESP 3 | Copyright (c) Kiril Zyapkov 4 | Converted for ESP32 Larry Bernstone 5 | 6 | Original version: 7 | ArduinoISP version 04m3 8 | Copyright (c) 2008-2011 Randall Bohn 9 | If you require a license, see 10 | http://www.opensource.org/licenses/bsd-license.php 11 | */ 12 | 13 | 14 | #include 15 | #include 16 | #include "ESP_AVRISP.h" 17 | #include "command.h" 18 | #ifdef ESP8266 19 | #include 20 | #include 21 | extern "C" { 22 | #include "user_interface.h" 23 | #include "memory" 24 | } 25 | #ifdef malloc 26 | #undef malloc 27 | #endif 28 | #define malloc os_malloc 29 | #ifdef free 30 | #undef free 31 | #endif 32 | #define free os_free 33 | #else 34 | #include 35 | #endif 36 | 37 | // #define AVRISP_DEBUG(fmt, ...) os_printf("[AVRP] " fmt "\r\n", ##__VA_ARGS__ ) 38 | #define AVRISP_DEBUG(...) 39 | 40 | #define AVRISP_HWVER 2 41 | #define AVRISP_SWMAJ 1 42 | #define AVRISP_SWMIN 18 43 | #define AVRISP_PTIME 10 44 | 45 | #define EECHUNK (32) 46 | 47 | #define beget16(addr) (*addr * 256 + *(addr+1)) 48 | 49 | ESP_AVRISP::ESP_AVRISP(uint16_t port, uint8_t reset_pin, uint32_t spi_freq, bool reset_state, bool reset_activehigh): 50 | _reset_pin(reset_pin), _reset_state(reset_state), _spi_freq(spi_freq), _reset_activehigh(reset_activehigh), 51 | _server(WiFiServer(port)), _state(AVRISP_STATE_IDLE) 52 | { 53 | pinMode(_reset_pin, OUTPUT); 54 | setReset(_reset_state); 55 | } 56 | 57 | void ESP_AVRISP::begin() { 58 | _server.begin(); 59 | } 60 | 61 | void ESP_AVRISP::setSpiFrequency(uint32_t freq) { 62 | _spi_freq = freq; 63 | if (_state == AVRISP_STATE_ACTIVE) { 64 | SPI.setFrequency(freq); 65 | } 66 | } 67 | 68 | void ESP_AVRISP::setReset(bool rst) { 69 | _reset_state = rst; 70 | digitalWrite(_reset_pin, _resetLevel(_reset_state)); 71 | } 72 | 73 | AVRISPState_t ESP_AVRISP::update() { 74 | switch (_state) { 75 | case AVRISP_STATE_IDLE: { 76 | if (_server.hasClient()) { 77 | _client = _server.available(); 78 | _client.setNoDelay(true); 79 | ip4_addr_t lip; 80 | lip.addr = _client.remoteIP(); 81 | AVRISP_DEBUG("client connect %d.%d.%d.%d:%d", IP2STR(&lip), _client.remotePort()); 82 | _client.setTimeout(100); // for getch() 83 | _state = AVRISP_STATE_PENDING; 84 | _reject_incoming(); 85 | } 86 | break; 87 | } 88 | case AVRISP_STATE_PENDING: 89 | case AVRISP_STATE_ACTIVE: { 90 | // handle disconnect 91 | if (!_client.connected()) { 92 | _client.stop(); 93 | AVRISP_DEBUG("client disconnect"); 94 | if (pmode) { 95 | SPI.end(); 96 | pmode = 0; 97 | } 98 | setReset(_reset_state); 99 | _state = AVRISP_STATE_IDLE; 100 | } else { 101 | _reject_incoming(); 102 | } 103 | break; 104 | } 105 | } 106 | return _state; 107 | } 108 | 109 | AVRISPState_t ESP_AVRISP::serve() { 110 | switch (update()) { 111 | case AVRISP_STATE_IDLE: 112 | // should not be called when idle, error? 113 | break; 114 | case AVRISP_STATE_PENDING: { 115 | _state = AVRISP_STATE_ACTIVE; 116 | // fallthrough 117 | } 118 | case AVRISP_STATE_ACTIVE: { 119 | while (_client.available()) { 120 | avrisp(); 121 | } 122 | return update(); 123 | } 124 | } 125 | return _state; 126 | } 127 | 128 | inline void ESP_AVRISP::_reject_incoming(void) { 129 | while (_server.hasClient()) _server.available().stop(); 130 | } 131 | 132 | uint8_t ESP_AVRISP::getch() { 133 | while (!_client.available()) yield(); 134 | uint8_t b = (uint8_t)_client.read(); 135 | // AVRISP_DEBUG("< %02x", b); 136 | return b; 137 | } 138 | 139 | void ESP_AVRISP::fill(int n) { 140 | // AVRISP_DEBUG("fill(%u)", n); 141 | for (int x = 0; x < n; x++) { 142 | buff[x] = getch(); 143 | } 144 | } 145 | 146 | uint8_t ESP_AVRISP::spi_transaction(uint8_t a, uint8_t b, uint8_t c, uint8_t d) { 147 | uint8_t n; 148 | SPI.transfer(a); 149 | n = SPI.transfer(b); 150 | n = SPI.transfer(c); 151 | return SPI.transfer(d); 152 | } 153 | 154 | void ESP_AVRISP::empty_reply() { 155 | if (Sync_CRC_EOP == getch()) { 156 | _client.print((char)Resp_STK_INSYNC); 157 | _client.print((char)Resp_STK_OK); 158 | } else { 159 | error++; 160 | _client.print((char)Resp_STK_NOSYNC); 161 | } 162 | } 163 | 164 | void ESP_AVRISP::breply(uint8_t b) { 165 | if (Sync_CRC_EOP == getch()) { 166 | uint8_t resp[3]; 167 | resp[0] = Resp_STK_INSYNC; 168 | resp[1] = b; 169 | resp[2] = Resp_STK_OK; 170 | _client.write((const uint8_t *)resp, (size_t)3); 171 | } else { 172 | error++; 173 | _client.print((char)Resp_STK_NOSYNC); 174 | } 175 | 176 | } 177 | 178 | void ESP_AVRISP::get_parameter(uint8_t c) { 179 | switch (c) { 180 | case 0x80: 181 | breply(AVRISP_HWVER); 182 | break; 183 | case 0x81: 184 | breply(AVRISP_SWMAJ); 185 | break; 186 | case 0x82: 187 | breply(AVRISP_SWMIN); 188 | break; 189 | case 0x93: 190 | breply('S'); // serial programmer 191 | break; 192 | default: 193 | breply(0); 194 | } 195 | } 196 | 197 | void ESP_AVRISP::set_parameters() { 198 | // call this after reading paramter packet into buff[] 199 | param.devicecode = buff[0]; 200 | param.revision = buff[1]; 201 | param.progtype = buff[2]; 202 | param.parmode = buff[3]; 203 | param.polling = buff[4]; 204 | param.selftimed = buff[5]; 205 | param.lockbytes = buff[6]; 206 | param.fusebytes = buff[7]; 207 | param.flashpoll = buff[8]; 208 | // ignore buff[9] (= buff[8]) 209 | // following are 16 bits (big endian) 210 | param.eeprompoll = beget16(&buff[10]); 211 | param.pagesize = beget16(&buff[12]); 212 | param.eepromsize = beget16(&buff[14]); 213 | 214 | // 32 bits flashsize (big endian) 215 | param.flashsize = buff[16] * 0x01000000 216 | + buff[17] * 0x00010000 217 | + buff[18] * 0x00000100 218 | + buff[19]; 219 | } 220 | 221 | void ESP_AVRISP::start_pmode() { 222 | #ifdef SPI_PINS 223 | SPI.begin(SPI_PINS); 224 | #else 225 | SPI.begin(); 226 | #endif 227 | SPI.setFrequency(_spi_freq); 228 | SPI.setHwCs(false); 229 | 230 | // try to sync the bus 231 | SPI.transfer(0x00); 232 | digitalWrite(_reset_pin, _resetLevel(false)); 233 | delayMicroseconds(50); 234 | digitalWrite(_reset_pin, _resetLevel(true)); 235 | delay(30); 236 | 237 | spi_transaction(0xAC, 0x53, 0x00, 0x00); 238 | pmode = 1; 239 | } 240 | 241 | void ESP_AVRISP::end_pmode() { 242 | SPI.end(); 243 | setReset(_reset_state); 244 | pmode = 0; 245 | } 246 | 247 | void ESP_AVRISP::universal() { 248 | int w; 249 | uint8_t ch; 250 | 251 | fill(4); 252 | ch = spi_transaction(buff[0], buff[1], buff[2], buff[3]); 253 | breply(ch); 254 | } 255 | 256 | void ESP_AVRISP::flash(uint8_t hilo, int addr, uint8_t data) { 257 | spi_transaction(0x40 + 8 * hilo, 258 | addr >> 8 & 0xFF, 259 | addr & 0xFF, 260 | data); 261 | } 262 | 263 | void ESP_AVRISP::commit(int addr) { 264 | spi_transaction(0x4C, (addr >> 8) & 0xFF, addr & 0xFF, 0); 265 | delay(AVRISP_PTIME); 266 | } 267 | 268 | //#define _addr_page(x) (here & 0xFFFFE0) 269 | int ESP_AVRISP::addr_page(int addr) { 270 | if (param.pagesize == 32) return addr & 0xFFFFFFF0; 271 | if (param.pagesize == 64) return addr & 0xFFFFFFE0; 272 | if (param.pagesize == 128) return addr & 0xFFFFFFC0; 273 | if (param.pagesize == 256) return addr & 0xFFFFFF80; 274 | AVRISP_DEBUG("unknown page size: %d", param.pagesize); 275 | return addr; 276 | } 277 | 278 | 279 | void ESP_AVRISP::write_flash(int length) { 280 | uint32_t started = millis(); 281 | 282 | fill(length); 283 | 284 | if (Sync_CRC_EOP == getch()) { 285 | _client.print((char) Resp_STK_INSYNC); 286 | _client.print((char) write_flash_pages(length)); 287 | } else { 288 | error++; 289 | _client.print((char) Resp_STK_NOSYNC); 290 | } 291 | } 292 | 293 | uint8_t ESP_AVRISP::write_flash_pages(int length) { 294 | int x = 0; 295 | int page = addr_page(here); 296 | while (x < length) { 297 | yield(); 298 | if (page != addr_page(here)) { 299 | commit(page); 300 | page = addr_page(here); 301 | } 302 | flash(LOW, here, buff[x++]); 303 | flash(HIGH, here, buff[x++]); 304 | here++; 305 | } 306 | commit(page); 307 | return Resp_STK_OK; 308 | } 309 | 310 | uint8_t ESP_AVRISP::write_eeprom(int length) { 311 | // here is a word address, get the byte address 312 | int start = here * 2; 313 | int remaining = length; 314 | if (length > param.eepromsize) { 315 | error++; 316 | return Resp_STK_FAILED; 317 | } 318 | while (remaining > EECHUNK) { 319 | write_eeprom_chunk(start, EECHUNK); 320 | start += EECHUNK; 321 | remaining -= EECHUNK; 322 | } 323 | write_eeprom_chunk(start, remaining); 324 | return Resp_STK_OK; 325 | } 326 | // write (length) bytes, (start) is a byte address 327 | uint8_t ESP_AVRISP::write_eeprom_chunk(int start, int length) { 328 | // this writes byte-by-byte, 329 | // page writing may be faster (4 bytes at a time) 330 | fill(length); 331 | // prog_lamp(LOW); 332 | for (int x = 0; x < length; x++) { 333 | int addr = start + x; 334 | spi_transaction(0xC0, (addr >> 8) & 0xFF, addr & 0xFF, buff[x]); 335 | delay(45); 336 | } 337 | // prog_lamp(HIGH); 338 | return Resp_STK_OK; 339 | } 340 | 341 | void ESP_AVRISP::program_page() { 342 | char result = (char) Resp_STK_FAILED; 343 | int length = 256 * getch(); 344 | length += getch(); 345 | char memtype = getch(); 346 | char buf[100]; 347 | // flash memory @here, (length) bytes 348 | if (memtype == 'F') { 349 | write_flash(length); 350 | return; 351 | } 352 | 353 | if (memtype == 'E') { 354 | result = (char)write_eeprom(length); 355 | if (Sync_CRC_EOP == getch()) { 356 | _client.print((char) Resp_STK_INSYNC); 357 | _client.print(result); 358 | } else { 359 | error++; 360 | _client.print((char) Resp_STK_NOSYNC); 361 | } 362 | return; 363 | } 364 | _client.print((char)Resp_STK_FAILED); 365 | return; 366 | 367 | } 368 | 369 | uint8_t ESP_AVRISP::flash_read(uint8_t hilo, int addr) { 370 | return spi_transaction(0x20 + hilo * 8, 371 | (addr >> 8) & 0xFF, 372 | addr & 0xFF, 373 | 0); 374 | } 375 | 376 | void ESP_AVRISP::flash_read_page(int length) { 377 | uint8_t *data = (uint8_t *) malloc(length + 1); 378 | for (int x = 0; x < length; x += 2) { 379 | *(data + x) = flash_read(LOW, here); 380 | *(data + x + 1) = flash_read(HIGH, here); 381 | here++; 382 | } 383 | *(data + length) = Resp_STK_OK; 384 | _client.write((const uint8_t *)data, (size_t)(length + 1)); 385 | free(data); 386 | return; 387 | } 388 | 389 | void ESP_AVRISP::eeprom_read_page(int length) { 390 | // here again we have a word address 391 | uint8_t *data = (uint8_t *) malloc(length + 1); 392 | int start = here * 2; 393 | for (int x = 0; x < length; x++) { 394 | int addr = start + x; 395 | uint8_t ee = spi_transaction(0xA0, (addr >> 8) & 0xFF, addr & 0xFF, 0xFF); 396 | *(data + x) = ee; 397 | } 398 | *(data + length) = Resp_STK_OK; 399 | _client.write((const uint8_t *)data, (size_t)(length + 1)); 400 | free(data); 401 | return; 402 | } 403 | 404 | void ESP_AVRISP::read_page() { 405 | char result = (char)Resp_STK_FAILED; 406 | int length = 256 * getch(); 407 | length += getch(); 408 | char memtype = getch(); 409 | if (Sync_CRC_EOP != getch()) { 410 | error++; 411 | _client.print((char) Resp_STK_NOSYNC); 412 | return; 413 | } 414 | _client.print((char) Resp_STK_INSYNC); 415 | if (memtype == 'F') flash_read_page(length); 416 | if (memtype == 'E') eeprom_read_page(length); 417 | return; 418 | } 419 | 420 | void ESP_AVRISP::read_signature() { 421 | if (Sync_CRC_EOP != getch()) { 422 | error++; 423 | _client.print((char) Resp_STK_NOSYNC); 424 | return; 425 | } 426 | _client.print((char) Resp_STK_INSYNC); 427 | 428 | uint8_t high = spi_transaction(0x30, 0x00, 0x00, 0x00); 429 | _client.print((char) high); 430 | uint8_t middle = spi_transaction(0x30, 0x00, 0x01, 0x00); 431 | _client.print((char) middle); 432 | uint8_t low = spi_transaction(0x30, 0x00, 0x02, 0x00); 433 | _client.print((char) low); 434 | _client.print((char) Resp_STK_OK); 435 | } 436 | 437 | // It seems ArduinoISP is based on the original STK500 (not v2) 438 | // but implements only a subset of the commands. 439 | int ESP_AVRISP::avrisp() { 440 | uint8_t data, low, high; 441 | uint8_t ch = getch(); 442 | // AVRISP_DEBUG("CMD 0x%02x", ch); 443 | switch (ch) { 444 | case Cmnd_STK_GET_SYNC: 445 | error = 0; 446 | empty_reply(); 447 | break; 448 | 449 | case Cmnd_STK_GET_SIGN_ON: 450 | if (getch() == Sync_CRC_EOP) { 451 | _client.print((char) Resp_STK_INSYNC); 452 | _client.print(F("AVR ISP")); // AVR061 says "AVR STK"? 453 | _client.print((char) Resp_STK_OK); 454 | } 455 | break; 456 | 457 | case Cmnd_STK_GET_PARAMETER: 458 | get_parameter(getch()); 459 | break; 460 | 461 | case Cmnd_STK_SET_DEVICE: 462 | fill(20); 463 | set_parameters(); 464 | empty_reply(); 465 | break; 466 | 467 | case Cmnd_STK_SET_DEVICE_EXT: // ignored 468 | fill(5); 469 | empty_reply(); 470 | break; 471 | 472 | case Cmnd_STK_ENTER_PROGMODE: 473 | start_pmode(); 474 | empty_reply(); 475 | break; 476 | 477 | case Cmnd_STK_LOAD_ADDRESS: 478 | here = getch(); 479 | here += 256 * getch(); 480 | // AVRISP_DEBUG("here=0x%04x", here); 481 | empty_reply(); 482 | break; 483 | 484 | // XXX: not implemented! 485 | case Cmnd_STK_PROG_FLASH: 486 | low = getch(); 487 | high = getch(); 488 | empty_reply(); 489 | break; 490 | 491 | // XXX: not implemented! 492 | case Cmnd_STK_PROG_DATA: 493 | data = getch(); 494 | empty_reply(); 495 | break; 496 | 497 | case Cmnd_STK_PROG_PAGE: 498 | program_page(); 499 | break; 500 | 501 | case Cmnd_STK_READ_PAGE: 502 | read_page(); 503 | break; 504 | 505 | case Cmnd_STK_UNIVERSAL: 506 | universal(); 507 | break; 508 | 509 | case Cmnd_STK_LEAVE_PROGMODE: 510 | error = 0; 511 | end_pmode(); 512 | empty_reply(); 513 | delay(5); 514 | // if (_client && _client.connected()) 515 | _client.stop(); 516 | // AVRISP_DEBUG("left progmode"); 517 | 518 | break; 519 | 520 | case Cmnd_STK_READ_SIGN: 521 | read_signature(); 522 | break; 523 | // expecting a command, not Sync_CRC_EOP 524 | // this is how we can get back in sync 525 | case Sync_CRC_EOP: // 0x20, space 526 | error++; 527 | _client.print((char) Resp_STK_NOSYNC); 528 | break; 529 | 530 | // anything else we will return STK_UNKNOWN 531 | default: 532 | AVRISP_DEBUG("??!?"); 533 | error++; 534 | if (Sync_CRC_EOP == getch()) { 535 | _client.print((char)Resp_STK_UNKNOWN); 536 | } else { 537 | _client.print((char)Resp_STK_NOSYNC); 538 | } 539 | } 540 | } 541 | -------------------------------------------------------------------------------- /src/ESP_AVRISP.h: -------------------------------------------------------------------------------- 1 | /* 2 | AVR In-System Programming over WiFi for ESP8266 3 | Copyright (c) Kiril Zyapkov 4 | 5 | Original version: 6 | ArduinoISP version 04m3 7 | Copyright (c) 2008-2011 Randall Bohn 8 | If you require a license, see 9 | http://www.opensource.org/licenses/bsd-license.php 10 | */ 11 | 12 | #ifndef _ESP_AVRISP_H 13 | #define _ESP_AVRISP_H 14 | 15 | #include 16 | #ifdef ESP8266 17 | #include 18 | #else 19 | #include 20 | #endif 21 | 22 | // uncomment if you use an n-mos to level-shift the reset line 23 | // #define AVRISP_ACTIVE_HIGH_RESET 24 | 25 | // SPI clock frequency in Hz 26 | #define AVRISP_SPI_FREQ 300e3 27 | 28 | // programmer states 29 | typedef enum { 30 | AVRISP_STATE_IDLE = 0, // no active TCP session 31 | AVRISP_STATE_PENDING, // TCP connected, pending SPI activation 32 | AVRISP_STATE_ACTIVE // programmer is active and owns the SPI bus 33 | } AVRISPState_t; 34 | 35 | // stk500 parameters 36 | typedef struct { 37 | uint8_t devicecode; 38 | uint8_t revision; 39 | uint8_t progtype; 40 | uint8_t parmode; 41 | uint8_t polling; 42 | uint8_t selftimed; 43 | uint8_t lockbytes; 44 | uint8_t fusebytes; 45 | int flashpoll; 46 | int eeprompoll; 47 | int pagesize; 48 | int eepromsize; 49 | int flashsize; 50 | } AVRISP_parameter_t; 51 | 52 | 53 | class ESP_AVRISP { 54 | public: 55 | ESP_AVRISP(uint16_t port, uint8_t reset_pin, uint32_t spi_freq=AVRISP_SPI_FREQ, bool reset_state=false, bool reset_activehigh=false); 56 | 57 | void begin(); 58 | 59 | // set the SPI clock frequency 60 | void setSpiFrequency(uint32_t); 61 | 62 | // control the state of the RESET pin of the target 63 | // see AVRISP_ACTIVE_HIGH_RESET 64 | void setReset(bool); 65 | 66 | // check for pending clients if IDLE, check for disconnect otherwise 67 | // returns the updated state 68 | AVRISPState_t update(); 69 | 70 | // transition to ACTIVE if PENDING 71 | // serve STK500 commands from buffer if ACTIVE 72 | // returns the updated state 73 | AVRISPState_t serve(); 74 | 75 | protected: 76 | 77 | inline void _reject_incoming(void); // reject any incoming tcp connections 78 | 79 | int avrisp(void); // handle incoming STK500 commands 80 | 81 | uint8_t getch(void); // retrieve a character from the remote end 82 | uint8_t spi_transaction(uint8_t, uint8_t, uint8_t, uint8_t); 83 | void empty_reply(void); 84 | void breply(uint8_t); 85 | 86 | void get_parameter(uint8_t); 87 | void set_parameters(void); 88 | int addr_page(int); 89 | void flash(uint8_t, int, uint8_t); 90 | void write_flash(int); 91 | uint8_t write_flash_pages(int length); 92 | uint8_t write_eeprom(int length); 93 | uint8_t write_eeprom_chunk(int start, int length); 94 | void commit(int addr); 95 | void program_page(); 96 | uint8_t flash_read(uint8_t hilo, int addr); 97 | void flash_read_page(int length); 98 | void eeprom_read_page(int length); 99 | void read_page(); 100 | void read_signature(); 101 | 102 | void universal(void); 103 | 104 | void fill(int); // fill the buffer with n bytes 105 | void start_pmode(void); // enter program mode 106 | void end_pmode(void); // exit program mode 107 | 108 | inline bool _resetLevel(bool reset_state) { return reset_state == _reset_activehigh; } 109 | 110 | uint32_t _spi_freq; 111 | WiFiServer _server; 112 | WiFiClient _client; 113 | AVRISPState_t _state; 114 | uint8_t _reset_pin; 115 | bool _reset_state; 116 | bool _reset_activehigh; 117 | 118 | // programmer settings, set by remote end 119 | AVRISP_parameter_t param; 120 | // page buffer 121 | uint8_t buff[256]; 122 | 123 | int error = 0; 124 | bool pmode = 0; 125 | 126 | // address for reading and writing, set by 'U' command 127 | int here; 128 | }; 129 | 130 | 131 | #endif // _ESP_AVRISP_H 132 | -------------------------------------------------------------------------------- /src/command.h: -------------------------------------------------------------------------------- 1 | //**** ATMEL AVR - A P P L I C A T I O N N O T E ************************ 2 | //* 3 | //* Title: AVR061 - STK500 Communication Protocol 4 | //* Filename: command.h 5 | //* Version: 1.0 6 | //* Last updated: 09.09.2002 7 | //* 8 | //* Support E-mail: avr@atmel.com 9 | //* 10 | //************************************************************************** 11 | 12 | // *****************[ STK Message constants ]*************************** 13 | 14 | #define STK_SIGN_ON_MESSAGE "AVR STK" // Sign on string for Cmnd_STK_GET_SIGN_ON 15 | 16 | // *****************[ STK Response constants ]*************************** 17 | 18 | #define Resp_STK_OK 0x10 // ' ' 19 | #define Resp_STK_FAILED 0x11 // ' ' 20 | #define Resp_STK_UNKNOWN 0x12 // ' ' 21 | #define Resp_STK_NODEVICE 0x13 // ' ' 22 | #define Resp_STK_INSYNC 0x14 // ' ' 23 | #define Resp_STK_NOSYNC 0x15 // ' ' 24 | 25 | #define Resp_ADC_CHANNEL_ERROR 0x16 // ' ' 26 | #define Resp_ADC_MEASURE_OK 0x17 // ' ' 27 | #define Resp_PWM_CHANNEL_ERROR 0x18 // ' ' 28 | #define Resp_PWM_ADJUST_OK 0x19 // ' ' 29 | 30 | // *****************[ STK Special constants ]*************************** 31 | 32 | #define Sync_CRC_EOP 0x20 // 'SPACE' 33 | 34 | // *****************[ STK Command constants ]*************************** 35 | 36 | #define Cmnd_STK_GET_SYNC 0x30 // ' ' 37 | #define Cmnd_STK_GET_SIGN_ON 0x31 // ' ' 38 | #define Cmnd_STK_RESET 0x32 // ' ' 39 | #define Cmnd_STK_SINGLE_CLOCK 0x33 // ' ' 40 | #define Cmnd_STK_STORE_PARAMETERS 0x34 // ' ' 41 | 42 | #define Cmnd_STK_SET_PARAMETER 0x40 // ' ' 43 | #define Cmnd_STK_GET_PARAMETER 0x41 // ' ' 44 | #define Cmnd_STK_SET_DEVICE 0x42 // ' ' 45 | #define Cmnd_STK_GET_DEVICE 0x43 // ' ' 46 | #define Cmnd_STK_GET_STATUS 0x44 // ' ' 47 | #define Cmnd_STK_SET_DEVICE_EXT 0x45 // ' ' 48 | 49 | #define Cmnd_STK_ENTER_PROGMODE 0x50 // ' ' 50 | #define Cmnd_STK_LEAVE_PROGMODE 0x51 // ' ' 51 | #define Cmnd_STK_CHIP_ERASE 0x52 // ' ' 52 | #define Cmnd_STK_CHECK_AUTOINC 0x53 // ' ' 53 | #define Cmnd_STK_CHECK_DEVICE 0x54 // ' ' 54 | #define Cmnd_STK_LOAD_ADDRESS 0x55 // ' ' 55 | #define Cmnd_STK_UNIVERSAL 0x56 // ' ' 56 | 57 | #define Cmnd_STK_PROG_FLASH 0x60 // ' ' 58 | #define Cmnd_STK_PROG_DATA 0x61 // ' ' 59 | #define Cmnd_STK_PROG_FUSE 0x62 // ' ' 60 | #define Cmnd_STK_PROG_LOCK 0x63 // ' ' 61 | #define Cmnd_STK_PROG_PAGE 0x64 // ' ' 62 | #define Cmnd_STK_PROG_FUSE_EXT 0x65 // ' ' 63 | 64 | #define Cmnd_STK_READ_FLASH 0x70 // ' ' 65 | #define Cmnd_STK_READ_DATA 0x71 // ' ' 66 | #define Cmnd_STK_READ_FUSE 0x72 // ' ' 67 | #define Cmnd_STK_READ_LOCK 0x73 // ' ' 68 | #define Cmnd_STK_READ_PAGE 0x74 // ' ' 69 | #define Cmnd_STK_READ_SIGN 0x75 // ' ' 70 | #define Cmnd_STK_READ_OSCCAL 0x76 // ' ' 71 | #define Cmnd_STK_READ_FUSE_EXT 0x77 // ' ' 72 | #define Cmnd_STK_READ_OSCCAL_EXT 0x78 // ' ' 73 | 74 | // *****************[ STK Parameter constants ]*************************** 75 | 76 | #define Parm_STK_HW_VER 0x80 // ' ' - R 77 | #define Parm_STK_SW_MAJOR 0x81 // ' ' - R 78 | #define Parm_STK_SW_MINOR 0x82 // ' ' - R 79 | #define Parm_STK_LEDS 0x83 // ' ' - R/W 80 | #define Parm_STK_VTARGET 0x84 // ' ' - R/W 81 | #define Parm_STK_VADJUST 0x85 // ' ' - R/W 82 | #define Parm_STK_OSC_PSCALE 0x86 // ' ' - R/W 83 | #define Parm_STK_OSC_CMATCH 0x87 // ' ' - R/W 84 | #define Parm_STK_RESET_DURATION 0x88 // ' ' - R/W 85 | #define Parm_STK_SCK_DURATION 0x89 // ' ' - R/W 86 | 87 | #define Parm_STK_BUFSIZEL 0x90 // ' ' - R/W, Range {0..255} 88 | #define Parm_STK_BUFSIZEH 0x91 // ' ' - R/W, Range {0..255} 89 | #define Parm_STK_DEVICE 0x92 // ' ' - R/W, Range {0..255} 90 | #define Parm_STK_PROGMODE 0x93 // ' ' - 'P' or 'S' 91 | #define Parm_STK_PARAMODE 0x94 // ' ' - TRUE or FALSE 92 | #define Parm_STK_POLLING 0x95 // ' ' - TRUE or FALSE 93 | #define Parm_STK_SELFTIMED 0x96 // ' ' - TRUE or FALSE 94 | 95 | 96 | // *****************[ STK status bit definitions ]*************************** 97 | 98 | #define Stat_STK_INSYNC 0x01 // INSYNC status bit, '1' - INSYNC 99 | #define Stat_STK_PROGMODE 0x02 // Programming mode, '1' - PROGMODE 100 | #define Stat_STK_STANDALONE 0x04 // Standalone mode, '1' - SM mode 101 | #define Stat_STK_RESET 0x08 // RESET button, '1' - Pushed 102 | #define Stat_STK_PROGRAM 0x10 // Program button, ' 1' - Pushed 103 | #define Stat_STK_LEDG 0x20 // Green LED status, '1' - Lit 104 | #define Stat_STK_LEDR 0x40 // Red LED status, '1' - Lit 105 | #define Stat_STK_LEDBLINK 0x80 // LED blink ON/OFF, '1' - Blink 106 | 107 | 108 | // *****************************[ End Of COMMAND.H ]************************** 109 | --------------------------------------------------------------------------------