mirror of
https://github.com/esp8266/Arduino.git
synced 2025-04-22 21:23:07 +03:00
commit
be2303f198
57
libraries/ESP8266AVRISP/README.md
Normal file
57
libraries/ESP8266AVRISP/README.md
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# AVR In-System Programming over WiFi for ESP8266
|
||||||
|
|
||||||
|
This library allows an ESP8266 module with the HSPI port available to become
|
||||||
|
an AVR In-System Programmer.
|
||||||
|
|
||||||
|
## Hardware
|
||||||
|
|
||||||
|
The ESP8266 module connects to the AVR target chip via the standard 6-pin
|
||||||
|
AVR "Recommended In-System Programming Interface Connector Layout" as seen
|
||||||
|
in [AVR910](http://www.atmel.com/images/doc0943.pdf) among other places.
|
||||||
|
|
||||||
|
If the AVR target is powered by a different Vcc than what powers your ESP8266
|
||||||
|
chip, you **must provide voltage level shifting** or some other form of buffers.
|
||||||
|
Exposing the pins of ESP8266 to anything larger than 3.6V will damage it.
|
||||||
|
|
||||||
|
Connections are as follows:
|
||||||
|
|
||||||
|
ESP8266 | AVR / SPI
|
||||||
|
--------|------------
|
||||||
|
GPIO12 | MISO
|
||||||
|
GPIO13 | MOSI
|
||||||
|
GPIO14 | SCK
|
||||||
|
any* | RESET
|
||||||
|
|
||||||
|
For RESET use a GPIO other than 0, 2 and 15 (bootselect pins), and apply an
|
||||||
|
external pullup/down so that the target is normally running.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
See the included example. In short:
|
||||||
|
|
||||||
|
```arduino
|
||||||
|
|
||||||
|
// Create the programmer object
|
||||||
|
ESP8266AVRISP avrprog(PORT, RESET_PIN)
|
||||||
|
// ... with custom SPI frequency
|
||||||
|
ESP8266AVRISP avrprog(PORT, RESET_PIN, 4e6)
|
||||||
|
|
||||||
|
// Check current connection state, but don't perform any actions
|
||||||
|
AVRISPState_t state = avrprog.update();
|
||||||
|
|
||||||
|
// Serve the pending connection, execute STK500 commands
|
||||||
|
AVRISPState_t state = avrprog.serve();
|
||||||
|
```
|
||||||
|
|
||||||
|
### License and Authors
|
||||||
|
|
||||||
|
This library started off from the source of ArduinoISP "sketch" included with
|
||||||
|
the Arduino IDE:
|
||||||
|
|
||||||
|
ArduinoISP version 04m3
|
||||||
|
Copyright (c) 2008-2011 Randall Bohn
|
||||||
|
If you require a license, see
|
||||||
|
http://www.opensource.org/licenses/bsd-license.php
|
||||||
|
|
||||||
|
Support for TCP on ESP8266
|
||||||
|
Copyright (c) Kiril Zyapkov <kiril@robotev.com>.
|
@ -0,0 +1,67 @@
|
|||||||
|
#include <SPI.h>
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ESP8266mDNS.h>
|
||||||
|
#include <ESP8266AVRISP.h>
|
||||||
|
|
||||||
|
const char* host = "esp8266-avrisp";
|
||||||
|
const char* ssid = "**********";
|
||||||
|
const char* pass = "**********";
|
||||||
|
const uint16_t port = 328;
|
||||||
|
const uint8_t reset_pin = 5;
|
||||||
|
|
||||||
|
ESP8266AVRISP avrprog(port, reset_pin);
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println("");
|
||||||
|
Serial.println("Arduino AVR-ISP over TCP");
|
||||||
|
avrprog.setReset(false); // let the AVR run
|
||||||
|
|
||||||
|
WiFi.begin(ssid, pass);
|
||||||
|
while (WiFi.waitForConnectResult() != WL_CONNECTED);
|
||||||
|
|
||||||
|
MDNS.begin(host);
|
||||||
|
MDNS.addService("avrisp", "tcp", port);
|
||||||
|
|
||||||
|
IPAddress local_ip = WiFi.localIP();
|
||||||
|
Serial.print("IP address: ");
|
||||||
|
Serial.println(local_ip);
|
||||||
|
Serial.println("Use your avrdude:");
|
||||||
|
Serial.print("avrdude -c arduino -p <device> -P net:");
|
||||||
|
Serial.print(local_ip);
|
||||||
|
Serial.print(":");
|
||||||
|
Serial.print(port);
|
||||||
|
Serial.println(" -t # or -U ...");
|
||||||
|
|
||||||
|
// listen for avrdudes
|
||||||
|
avrprog.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
static AVRISPState_t last_state = AVRISP_STATE_IDLE;
|
||||||
|
AVRISPState_t new_state = avrprog.update();
|
||||||
|
if (last_state != new_state) {
|
||||||
|
switch (new_state) {
|
||||||
|
case AVRISP_STATE_IDLE: {
|
||||||
|
Serial.printf("[AVRISP] now idle\r\n");
|
||||||
|
// Use the SPI bus for other purposes
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AVRISP_STATE_PENDING: {
|
||||||
|
Serial.printf("[AVRISP] connection pending\r\n");
|
||||||
|
// Clean up your other purposes and prepare for programming mode
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AVRISP_STATE_ACTIVE: {
|
||||||
|
Serial.printf("[AVRISP] programming mode\r\n");
|
||||||
|
// Stand by for completion
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
last_state = new_state;
|
||||||
|
}
|
||||||
|
// Serve the client
|
||||||
|
if (last_state != AVRISP_STATE_IDLE) {
|
||||||
|
avrprog.serve();
|
||||||
|
}
|
||||||
|
}
|
9
libraries/ESP8266AVRISP/library.properties
Normal file
9
libraries/ESP8266AVRISP/library.properties
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
name=ESP8266AVRISP
|
||||||
|
version=1.0
|
||||||
|
author=Kiril Zyapkov
|
||||||
|
maintainer=Kiril Zyapkov <kiril@robotev.com>
|
||||||
|
sentence=AVR In-System Programming over WiFi for ESP8266
|
||||||
|
paragraph=This library allows programming 8-bit AVR ICSP targets via TCP over WiFi with ESP8266.
|
||||||
|
category=Communication
|
||||||
|
url=
|
||||||
|
architectures=esp8266
|
541
libraries/ESP8266AVRISP/src/ESP8266AVRISP.cpp
Normal file
541
libraries/ESP8266AVRISP/src/ESP8266AVRISP.cpp
Normal file
@ -0,0 +1,541 @@
|
|||||||
|
/*
|
||||||
|
AVR In-System Programming over WiFi for ESP8266
|
||||||
|
Copyright (c) Kiril Zyapkov <kiril@robotev.com>
|
||||||
|
|
||||||
|
Original version:
|
||||||
|
ArduinoISP version 04m3
|
||||||
|
Copyright (c) 2008-2011 Randall Bohn
|
||||||
|
If you require a license, see
|
||||||
|
http://www.opensource.org/licenses/bsd-license.php
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <pgmspace.h>
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
|
||||||
|
#include "ESP8266AVRISP.h"
|
||||||
|
#include "command.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "user_interface.h"
|
||||||
|
#include "mem.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
#define malloc os_malloc
|
||||||
|
#define free os_free
|
||||||
|
|
||||||
|
#ifdef AVRISP_ACTIVE_HIGH_RESET
|
||||||
|
#define AVRISP_RESET_ON HIGH
|
||||||
|
#define AVRISP_RESET_OFF LOW
|
||||||
|
#else
|
||||||
|
#define AVRISP_RESET_ON LOW
|
||||||
|
#define AVRISP_RESET_OFF HIGH
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// #define AVRISP_DEBUG(fmt, ...) os_printf("[AVRP] " fmt "\r\n", ##__VA_ARGS__ )
|
||||||
|
#define AVRISP_DEBUG(...)
|
||||||
|
|
||||||
|
#define AVRISP_HWVER 2
|
||||||
|
#define AVRISP_SWMAJ 1
|
||||||
|
#define AVRISP_SWMIN 18
|
||||||
|
#define AVRISP_PTIME 10
|
||||||
|
|
||||||
|
#define EECHUNK (32)
|
||||||
|
|
||||||
|
#define beget16(addr) (*addr * 256 + *(addr+1))
|
||||||
|
|
||||||
|
ESP8266AVRISP::ESP8266AVRISP(uint16_t port, uint8_t reset_pin, uint32_t spi_freq, bool reset_state):
|
||||||
|
_reset_pin(reset_pin), _reset_state(reset_state), _spi_freq(spi_freq),
|
||||||
|
_server(WiFiServer(port)), _state(AVRISP_STATE_IDLE)
|
||||||
|
{
|
||||||
|
pinMode(_reset_pin, OUTPUT);
|
||||||
|
setReset(_reset_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::begin() {
|
||||||
|
_server.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::setSpiFrequency(uint32_t freq) {
|
||||||
|
_spi_freq = freq;
|
||||||
|
if (_state == AVRISP_STATE_ACTIVE) {
|
||||||
|
SPI.setFrequency(freq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::setReset(bool rst) {
|
||||||
|
_reset_state = rst;
|
||||||
|
if (_reset_state) {
|
||||||
|
digitalWrite(_reset_pin, AVRISP_RESET_ON);
|
||||||
|
} else {
|
||||||
|
digitalWrite(_reset_pin, AVRISP_RESET_OFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AVRISPState_t ESP8266AVRISP::update() {
|
||||||
|
switch (_state) {
|
||||||
|
case AVRISP_STATE_IDLE: {
|
||||||
|
if (_server.hasClient()) {
|
||||||
|
_client = _server.available();
|
||||||
|
_client.setNoDelay(true);
|
||||||
|
ip_addr_t lip;
|
||||||
|
lip.addr = _client.remoteIP();
|
||||||
|
AVRISP_DEBUG("client connect %d.%d.%d.%d:%d", IP2STR(&lip), _client.remotePort());
|
||||||
|
_client.setTimeout(100); // for getch()
|
||||||
|
_state = AVRISP_STATE_PENDING;
|
||||||
|
_reject_incoming();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AVRISP_STATE_PENDING:
|
||||||
|
case AVRISP_STATE_ACTIVE: {
|
||||||
|
// handle disconnect
|
||||||
|
if (!_client.connected()) {
|
||||||
|
_client.stop();
|
||||||
|
AVRISP_DEBUG("client disconnect");
|
||||||
|
if (pmode) {
|
||||||
|
SPI.end();
|
||||||
|
pmode = 0;
|
||||||
|
}
|
||||||
|
setReset(_reset_state);
|
||||||
|
_state = AVRISP_STATE_IDLE;
|
||||||
|
} else {
|
||||||
|
_reject_incoming();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _state;
|
||||||
|
}
|
||||||
|
|
||||||
|
AVRISPState_t ESP8266AVRISP::serve() {
|
||||||
|
switch (update()) {
|
||||||
|
case AVRISP_STATE_IDLE:
|
||||||
|
// should not be called when idle, error?
|
||||||
|
break;
|
||||||
|
case AVRISP_STATE_PENDING: {
|
||||||
|
_state = AVRISP_STATE_ACTIVE;
|
||||||
|
// fallthrough
|
||||||
|
}
|
||||||
|
case AVRISP_STATE_ACTIVE: {
|
||||||
|
while (_client.available()) {
|
||||||
|
avrisp();
|
||||||
|
}
|
||||||
|
return update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _state;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void ESP8266AVRISP::_reject_incoming(void) {
|
||||||
|
while (_server.hasClient()) _server.available().stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ESP8266AVRISP::getch() {
|
||||||
|
while (!_client.available()) yield();
|
||||||
|
uint8_t b = (uint8_t)_client.read();
|
||||||
|
// AVRISP_DEBUG("< %02x", b);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::fill(int n) {
|
||||||
|
// AVRISP_DEBUG("fill(%u)", n);
|
||||||
|
for (int x = 0; x < n; x++) {
|
||||||
|
buff[x] = getch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ESP8266AVRISP::spi_transaction(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
|
||||||
|
uint8_t n;
|
||||||
|
SPI.transfer(a);
|
||||||
|
n = SPI.transfer(b);
|
||||||
|
n = SPI.transfer(c);
|
||||||
|
return SPI.transfer(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::empty_reply() {
|
||||||
|
if (Sync_CRC_EOP == getch()) {
|
||||||
|
_client.print((char)Resp_STK_INSYNC);
|
||||||
|
_client.print((char)Resp_STK_OK);
|
||||||
|
} else {
|
||||||
|
error++;
|
||||||
|
_client.print((char)Resp_STK_NOSYNC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::breply(uint8_t b) {
|
||||||
|
if (Sync_CRC_EOP == getch()) {
|
||||||
|
uint8_t resp[3];
|
||||||
|
resp[0] = Resp_STK_INSYNC;
|
||||||
|
resp[1] = b;
|
||||||
|
resp[2] = Resp_STK_OK;
|
||||||
|
_client.write((const uint8_t *)resp, (size_t)3);
|
||||||
|
} else {
|
||||||
|
error++;
|
||||||
|
_client.print((char)Resp_STK_NOSYNC);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::get_parameter(uint8_t c) {
|
||||||
|
switch (c) {
|
||||||
|
case 0x80:
|
||||||
|
breply(AVRISP_HWVER);
|
||||||
|
break;
|
||||||
|
case 0x81:
|
||||||
|
breply(AVRISP_SWMAJ);
|
||||||
|
break;
|
||||||
|
case 0x82:
|
||||||
|
breply(AVRISP_SWMIN);
|
||||||
|
break;
|
||||||
|
case 0x93:
|
||||||
|
breply('S'); // serial programmer
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
breply(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::set_parameters() {
|
||||||
|
// call this after reading paramter packet into buff[]
|
||||||
|
param.devicecode = buff[0];
|
||||||
|
param.revision = buff[1];
|
||||||
|
param.progtype = buff[2];
|
||||||
|
param.parmode = buff[3];
|
||||||
|
param.polling = buff[4];
|
||||||
|
param.selftimed = buff[5];
|
||||||
|
param.lockbytes = buff[6];
|
||||||
|
param.fusebytes = buff[7];
|
||||||
|
param.flashpoll = buff[8];
|
||||||
|
// ignore buff[9] (= buff[8])
|
||||||
|
// following are 16 bits (big endian)
|
||||||
|
param.eeprompoll = beget16(&buff[10]);
|
||||||
|
param.pagesize = beget16(&buff[12]);
|
||||||
|
param.eepromsize = beget16(&buff[14]);
|
||||||
|
|
||||||
|
// 32 bits flashsize (big endian)
|
||||||
|
param.flashsize = buff[16] * 0x01000000
|
||||||
|
+ buff[17] * 0x00010000
|
||||||
|
+ buff[18] * 0x00000100
|
||||||
|
+ buff[19];
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::start_pmode() {
|
||||||
|
SPI.begin();
|
||||||
|
SPI.setFrequency(_spi_freq);
|
||||||
|
SPI.setHwCs(false);
|
||||||
|
|
||||||
|
// try to sync the bus
|
||||||
|
SPI.transfer(0x00);
|
||||||
|
digitalWrite(_reset_pin, AVRISP_RESET_OFF);
|
||||||
|
delayMicroseconds(50);
|
||||||
|
digitalWrite(_reset_pin, AVRISP_RESET_ON);
|
||||||
|
delay(30);
|
||||||
|
|
||||||
|
spi_transaction(0xAC, 0x53, 0x00, 0x00);
|
||||||
|
pmode = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::end_pmode() {
|
||||||
|
SPI.end();
|
||||||
|
setReset(_reset_state);
|
||||||
|
pmode = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::universal() {
|
||||||
|
int w;
|
||||||
|
uint8_t ch;
|
||||||
|
|
||||||
|
fill(4);
|
||||||
|
ch = spi_transaction(buff[0], buff[1], buff[2], buff[3]);
|
||||||
|
breply(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::flash(uint8_t hilo, int addr, uint8_t data) {
|
||||||
|
spi_transaction(0x40 + 8 * hilo,
|
||||||
|
addr >> 8 & 0xFF,
|
||||||
|
addr & 0xFF,
|
||||||
|
data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::commit(int addr) {
|
||||||
|
spi_transaction(0x4C, (addr >> 8) & 0xFF, addr & 0xFF, 0);
|
||||||
|
delay(AVRISP_PTIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
//#define _addr_page(x) (here & 0xFFFFE0)
|
||||||
|
int ESP8266AVRISP::addr_page(int addr) {
|
||||||
|
if (param.pagesize == 32) return addr & 0xFFFFFFF0;
|
||||||
|
if (param.pagesize == 64) return addr & 0xFFFFFFE0;
|
||||||
|
if (param.pagesize == 128) return addr & 0xFFFFFFC0;
|
||||||
|
if (param.pagesize == 256) return addr & 0xFFFFFF80;
|
||||||
|
AVRISP_DEBUG("unknown page size: %d", param.pagesize);
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ESP8266AVRISP::write_flash(int length) {
|
||||||
|
uint32_t started = millis();
|
||||||
|
|
||||||
|
fill(length);
|
||||||
|
|
||||||
|
if (Sync_CRC_EOP == getch()) {
|
||||||
|
_client.print((char) Resp_STK_INSYNC);
|
||||||
|
_client.print((char) write_flash_pages(length));
|
||||||
|
} else {
|
||||||
|
error++;
|
||||||
|
_client.print((char) Resp_STK_NOSYNC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ESP8266AVRISP::write_flash_pages(int length) {
|
||||||
|
int x = 0;
|
||||||
|
int page = addr_page(here);
|
||||||
|
while (x < length) {
|
||||||
|
yield();
|
||||||
|
if (page != addr_page(here)) {
|
||||||
|
commit(page);
|
||||||
|
page = addr_page(here);
|
||||||
|
}
|
||||||
|
flash(LOW, here, buff[x++]);
|
||||||
|
flash(HIGH, here, buff[x++]);
|
||||||
|
here++;
|
||||||
|
}
|
||||||
|
commit(page);
|
||||||
|
return Resp_STK_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ESP8266AVRISP::write_eeprom(int length) {
|
||||||
|
// here is a word address, get the byte address
|
||||||
|
int start = here * 2;
|
||||||
|
int remaining = length;
|
||||||
|
if (length > param.eepromsize) {
|
||||||
|
error++;
|
||||||
|
return Resp_STK_FAILED;
|
||||||
|
}
|
||||||
|
while (remaining > EECHUNK) {
|
||||||
|
write_eeprom_chunk(start, EECHUNK);
|
||||||
|
start += EECHUNK;
|
||||||
|
remaining -= EECHUNK;
|
||||||
|
}
|
||||||
|
write_eeprom_chunk(start, remaining);
|
||||||
|
return Resp_STK_OK;
|
||||||
|
}
|
||||||
|
// write (length) bytes, (start) is a byte address
|
||||||
|
uint8_t ESP8266AVRISP::write_eeprom_chunk(int start, int length) {
|
||||||
|
// this writes byte-by-byte,
|
||||||
|
// page writing may be faster (4 bytes at a time)
|
||||||
|
fill(length);
|
||||||
|
// prog_lamp(LOW);
|
||||||
|
for (int x = 0; x < length; x++) {
|
||||||
|
int addr = start + x;
|
||||||
|
spi_transaction(0xC0, (addr >> 8) & 0xFF, addr & 0xFF, buff[x]);
|
||||||
|
delay(45);
|
||||||
|
}
|
||||||
|
// prog_lamp(HIGH);
|
||||||
|
return Resp_STK_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::program_page() {
|
||||||
|
char result = (char) Resp_STK_FAILED;
|
||||||
|
int length = 256 * getch();
|
||||||
|
length += getch();
|
||||||
|
char memtype = getch();
|
||||||
|
char buf[100];
|
||||||
|
// flash memory @here, (length) bytes
|
||||||
|
if (memtype == 'F') {
|
||||||
|
write_flash(length);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memtype == 'E') {
|
||||||
|
result = (char)write_eeprom(length);
|
||||||
|
if (Sync_CRC_EOP == getch()) {
|
||||||
|
_client.print((char) Resp_STK_INSYNC);
|
||||||
|
_client.print(result);
|
||||||
|
} else {
|
||||||
|
error++;
|
||||||
|
_client.print((char) Resp_STK_NOSYNC);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_client.print((char)Resp_STK_FAILED);
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ESP8266AVRISP::flash_read(uint8_t hilo, int addr) {
|
||||||
|
return spi_transaction(0x20 + hilo * 8,
|
||||||
|
(addr >> 8) & 0xFF,
|
||||||
|
addr & 0xFF,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::flash_read_page(int length) {
|
||||||
|
uint8_t *data = (uint8_t *) malloc(length + 1);
|
||||||
|
for (int x = 0; x < length; x += 2) {
|
||||||
|
*(data + x) = flash_read(LOW, here);
|
||||||
|
*(data + x + 1) = flash_read(HIGH, here);
|
||||||
|
here++;
|
||||||
|
}
|
||||||
|
*(data + length) = Resp_STK_OK;
|
||||||
|
_client.write((const uint8_t *)data, (size_t)(length + 1));
|
||||||
|
free(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::eeprom_read_page(int length) {
|
||||||
|
// here again we have a word address
|
||||||
|
uint8_t *data = (uint8_t *) malloc(length + 1);
|
||||||
|
int start = here * 2;
|
||||||
|
for (int x = 0; x < length; x++) {
|
||||||
|
int addr = start + x;
|
||||||
|
uint8_t ee = spi_transaction(0xA0, (addr >> 8) & 0xFF, addr & 0xFF, 0xFF);
|
||||||
|
*(data + x) = ee;
|
||||||
|
}
|
||||||
|
*(data + length) = Resp_STK_OK;
|
||||||
|
_client.write((const uint8_t *)data, (size_t)(length + 1));
|
||||||
|
free(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::read_page() {
|
||||||
|
char result = (char)Resp_STK_FAILED;
|
||||||
|
int length = 256 * getch();
|
||||||
|
length += getch();
|
||||||
|
char memtype = getch();
|
||||||
|
if (Sync_CRC_EOP != getch()) {
|
||||||
|
error++;
|
||||||
|
_client.print((char) Resp_STK_NOSYNC);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_client.print((char) Resp_STK_INSYNC);
|
||||||
|
if (memtype == 'F') flash_read_page(length);
|
||||||
|
if (memtype == 'E') eeprom_read_page(length);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266AVRISP::read_signature() {
|
||||||
|
if (Sync_CRC_EOP != getch()) {
|
||||||
|
error++;
|
||||||
|
_client.print((char) Resp_STK_NOSYNC);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_client.print((char) Resp_STK_INSYNC);
|
||||||
|
|
||||||
|
uint8_t high = spi_transaction(0x30, 0x00, 0x00, 0x00);
|
||||||
|
_client.print((char) high);
|
||||||
|
uint8_t middle = spi_transaction(0x30, 0x00, 0x01, 0x00);
|
||||||
|
_client.print((char) middle);
|
||||||
|
uint8_t low = spi_transaction(0x30, 0x00, 0x02, 0x00);
|
||||||
|
_client.print((char) low);
|
||||||
|
_client.print((char) Resp_STK_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
// It seems ArduinoISP is based on the original STK500 (not v2)
|
||||||
|
// but implements only a subset of the commands.
|
||||||
|
int ESP8266AVRISP::avrisp() {
|
||||||
|
uint8_t data, low, high;
|
||||||
|
uint8_t ch = getch();
|
||||||
|
// AVRISP_DEBUG("CMD 0x%02x", ch);
|
||||||
|
switch (ch) {
|
||||||
|
case Cmnd_STK_GET_SYNC:
|
||||||
|
error = 0;
|
||||||
|
empty_reply();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Cmnd_STK_GET_SIGN_ON:
|
||||||
|
if (getch() == Sync_CRC_EOP) {
|
||||||
|
_client.print((char) Resp_STK_INSYNC);
|
||||||
|
_client.print(F("AVR ISP")); // AVR061 says "AVR STK"?
|
||||||
|
_client.print((char) Resp_STK_OK);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Cmnd_STK_GET_PARAMETER:
|
||||||
|
get_parameter(getch());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Cmnd_STK_SET_DEVICE:
|
||||||
|
fill(20);
|
||||||
|
set_parameters();
|
||||||
|
empty_reply();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Cmnd_STK_SET_DEVICE_EXT: // ignored
|
||||||
|
fill(5);
|
||||||
|
empty_reply();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Cmnd_STK_ENTER_PROGMODE:
|
||||||
|
start_pmode();
|
||||||
|
empty_reply();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Cmnd_STK_LOAD_ADDRESS:
|
||||||
|
here = getch();
|
||||||
|
here += 256 * getch();
|
||||||
|
// AVRISP_DEBUG("here=0x%04x", here);
|
||||||
|
empty_reply();
|
||||||
|
break;
|
||||||
|
|
||||||
|
// XXX: not implemented!
|
||||||
|
case Cmnd_STK_PROG_FLASH:
|
||||||
|
low = getch();
|
||||||
|
high = getch();
|
||||||
|
empty_reply();
|
||||||
|
break;
|
||||||
|
|
||||||
|
// XXX: not implemented!
|
||||||
|
case Cmnd_STK_PROG_DATA:
|
||||||
|
data = getch();
|
||||||
|
empty_reply();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Cmnd_STK_PROG_PAGE:
|
||||||
|
program_page();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Cmnd_STK_READ_PAGE:
|
||||||
|
read_page();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Cmnd_STK_UNIVERSAL:
|
||||||
|
universal();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Cmnd_STK_LEAVE_PROGMODE:
|
||||||
|
error = 0;
|
||||||
|
end_pmode();
|
||||||
|
empty_reply();
|
||||||
|
delay(5);
|
||||||
|
// if (_client && _client.connected())
|
||||||
|
_client.stop();
|
||||||
|
// AVRISP_DEBUG("left progmode");
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Cmnd_STK_READ_SIGN:
|
||||||
|
read_signature();
|
||||||
|
break;
|
||||||
|
// expecting a command, not Sync_CRC_EOP
|
||||||
|
// this is how we can get back in sync
|
||||||
|
case Sync_CRC_EOP: // 0x20, space
|
||||||
|
error++;
|
||||||
|
_client.print((char) Resp_STK_NOSYNC);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// anything else we will return STK_UNKNOWN
|
||||||
|
default:
|
||||||
|
AVRISP_DEBUG("??!?");
|
||||||
|
error++;
|
||||||
|
if (Sync_CRC_EOP == getch()) {
|
||||||
|
_client.print((char)Resp_STK_UNKNOWN);
|
||||||
|
} else {
|
||||||
|
_client.print((char)Resp_STK_NOSYNC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
125
libraries/ESP8266AVRISP/src/ESP8266AVRISP.h
Normal file
125
libraries/ESP8266AVRISP/src/ESP8266AVRISP.h
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
AVR In-System Programming over WiFi for ESP8266
|
||||||
|
Copyright (c) Kiril Zyapkov <kiril@robotev.com>
|
||||||
|
|
||||||
|
Original version:
|
||||||
|
ArduinoISP version 04m3
|
||||||
|
Copyright (c) 2008-2011 Randall Bohn
|
||||||
|
If you require a license, see
|
||||||
|
http://www.opensource.org/licenses/bsd-license.php
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _ESP8266AVRISP_H
|
||||||
|
#define _ESP8266AVRISP_H
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
// uncomment if you use an n-mos to level-shift the reset line
|
||||||
|
// #define AVRISP_ACTIVE_HIGH_RESET
|
||||||
|
|
||||||
|
// SPI clock frequency in Hz
|
||||||
|
#define AVRISP_SPI_FREQ 300e3
|
||||||
|
|
||||||
|
// programmer states
|
||||||
|
typedef enum {
|
||||||
|
AVRISP_STATE_IDLE = 0, // no active TCP session
|
||||||
|
AVRISP_STATE_PENDING, // TCP connected, pending SPI activation
|
||||||
|
AVRISP_STATE_ACTIVE // programmer is active and owns the SPI bus
|
||||||
|
} AVRISPState_t;
|
||||||
|
|
||||||
|
// stk500 parameters
|
||||||
|
typedef struct {
|
||||||
|
uint8_t devicecode;
|
||||||
|
uint8_t revision;
|
||||||
|
uint8_t progtype;
|
||||||
|
uint8_t parmode;
|
||||||
|
uint8_t polling;
|
||||||
|
uint8_t selftimed;
|
||||||
|
uint8_t lockbytes;
|
||||||
|
uint8_t fusebytes;
|
||||||
|
int flashpoll;
|
||||||
|
int eeprompoll;
|
||||||
|
int pagesize;
|
||||||
|
int eepromsize;
|
||||||
|
int flashsize;
|
||||||
|
} AVRISP_parameter_t;
|
||||||
|
|
||||||
|
|
||||||
|
class ESP8266AVRISP {
|
||||||
|
public:
|
||||||
|
ESP8266AVRISP(uint16_t port, uint8_t reset_pin, uint32_t spi_freq=AVRISP_SPI_FREQ, bool reset_state=false);
|
||||||
|
|
||||||
|
void begin();
|
||||||
|
|
||||||
|
// set the SPI clock frequency
|
||||||
|
void setSpiFrequency(uint32_t);
|
||||||
|
|
||||||
|
// control the state of the RESET pin of the target
|
||||||
|
// see AVRISP_ACTIVE_HIGH_RESET
|
||||||
|
void setReset(bool);
|
||||||
|
|
||||||
|
// check for pending clients if IDLE, check for disconnect otherwise
|
||||||
|
// returns the updated state
|
||||||
|
AVRISPState_t update();
|
||||||
|
|
||||||
|
// transition to ACTIVE if PENDING
|
||||||
|
// serve STK500 commands from buffer if ACTIVE
|
||||||
|
// returns the updated state
|
||||||
|
AVRISPState_t serve();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
inline void _reject_incoming(void); // reject any incoming tcp connections
|
||||||
|
|
||||||
|
int avrisp(void); // handle incoming STK500 commands
|
||||||
|
|
||||||
|
uint8_t getch(void); // retrieve a character from the remote end
|
||||||
|
uint8_t spi_transaction(uint8_t, uint8_t, uint8_t, uint8_t);
|
||||||
|
void empty_reply(void);
|
||||||
|
void breply(uint8_t);
|
||||||
|
|
||||||
|
void get_parameter(uint8_t);
|
||||||
|
void set_parameters(void);
|
||||||
|
int addr_page(int);
|
||||||
|
void flash(uint8_t, int, uint8_t);
|
||||||
|
void write_flash(int);
|
||||||
|
uint8_t write_flash_pages(int length);
|
||||||
|
uint8_t write_eeprom(int length);
|
||||||
|
uint8_t write_eeprom_chunk(int start, int length);
|
||||||
|
void commit(int addr);
|
||||||
|
void program_page();
|
||||||
|
uint8_t flash_read(uint8_t hilo, int addr);
|
||||||
|
void flash_read_page(int length);
|
||||||
|
void eeprom_read_page(int length);
|
||||||
|
void read_page();
|
||||||
|
void read_signature();
|
||||||
|
|
||||||
|
void universal(void);
|
||||||
|
|
||||||
|
void fill(int); // fill the buffer with n bytes
|
||||||
|
void start_pmode(void); // enter program mode
|
||||||
|
void end_pmode(void); // exit program mode
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t _spi_freq;
|
||||||
|
WiFiServer _server;
|
||||||
|
WiFiClient _client;
|
||||||
|
AVRISPState_t _state;
|
||||||
|
uint8_t _reset_pin;
|
||||||
|
bool _reset_state;
|
||||||
|
|
||||||
|
// programmer settings, set by remote end
|
||||||
|
AVRISP_parameter_t param;
|
||||||
|
// page buffer
|
||||||
|
uint8_t buff[256];
|
||||||
|
|
||||||
|
int error = 0;
|
||||||
|
bool pmode = 0;
|
||||||
|
|
||||||
|
// address for reading and writing, set by 'U' command
|
||||||
|
int here;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _ESP8266AVRISP_H
|
108
libraries/ESP8266AVRISP/src/command.h
Normal file
108
libraries/ESP8266AVRISP/src/command.h
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
//**** ATMEL AVR - A P P L I C A T I O N N O T E ************************
|
||||||
|
//*
|
||||||
|
//* Title: AVR061 - STK500 Communication Protocol
|
||||||
|
//* Filename: command.h
|
||||||
|
//* Version: 1.0
|
||||||
|
//* Last updated: 09.09.2002
|
||||||
|
//*
|
||||||
|
//* Support E-mail: avr@atmel.com
|
||||||
|
//*
|
||||||
|
//**************************************************************************
|
||||||
|
|
||||||
|
// *****************[ STK Message constants ]***************************
|
||||||
|
|
||||||
|
#define STK_SIGN_ON_MESSAGE "AVR STK" // Sign on string for Cmnd_STK_GET_SIGN_ON
|
||||||
|
|
||||||
|
// *****************[ STK Response constants ]***************************
|
||||||
|
|
||||||
|
#define Resp_STK_OK 0x10 // ' '
|
||||||
|
#define Resp_STK_FAILED 0x11 // ' '
|
||||||
|
#define Resp_STK_UNKNOWN 0x12 // ' '
|
||||||
|
#define Resp_STK_NODEVICE 0x13 // ' '
|
||||||
|
#define Resp_STK_INSYNC 0x14 // ' '
|
||||||
|
#define Resp_STK_NOSYNC 0x15 // ' '
|
||||||
|
|
||||||
|
#define Resp_ADC_CHANNEL_ERROR 0x16 // ' '
|
||||||
|
#define Resp_ADC_MEASURE_OK 0x17 // ' '
|
||||||
|
#define Resp_PWM_CHANNEL_ERROR 0x18 // ' '
|
||||||
|
#define Resp_PWM_ADJUST_OK 0x19 // ' '
|
||||||
|
|
||||||
|
// *****************[ STK Special constants ]***************************
|
||||||
|
|
||||||
|
#define Sync_CRC_EOP 0x20 // 'SPACE'
|
||||||
|
|
||||||
|
// *****************[ STK Command constants ]***************************
|
||||||
|
|
||||||
|
#define Cmnd_STK_GET_SYNC 0x30 // ' '
|
||||||
|
#define Cmnd_STK_GET_SIGN_ON 0x31 // ' '
|
||||||
|
#define Cmnd_STK_RESET 0x32 // ' '
|
||||||
|
#define Cmnd_STK_SINGLE_CLOCK 0x33 // ' '
|
||||||
|
#define Cmnd_STK_STORE_PARAMETERS 0x34 // ' '
|
||||||
|
|
||||||
|
#define Cmnd_STK_SET_PARAMETER 0x40 // ' '
|
||||||
|
#define Cmnd_STK_GET_PARAMETER 0x41 // ' '
|
||||||
|
#define Cmnd_STK_SET_DEVICE 0x42 // ' '
|
||||||
|
#define Cmnd_STK_GET_DEVICE 0x43 // ' '
|
||||||
|
#define Cmnd_STK_GET_STATUS 0x44 // ' '
|
||||||
|
#define Cmnd_STK_SET_DEVICE_EXT 0x45 // ' '
|
||||||
|
|
||||||
|
#define Cmnd_STK_ENTER_PROGMODE 0x50 // ' '
|
||||||
|
#define Cmnd_STK_LEAVE_PROGMODE 0x51 // ' '
|
||||||
|
#define Cmnd_STK_CHIP_ERASE 0x52 // ' '
|
||||||
|
#define Cmnd_STK_CHECK_AUTOINC 0x53 // ' '
|
||||||
|
#define Cmnd_STK_CHECK_DEVICE 0x54 // ' '
|
||||||
|
#define Cmnd_STK_LOAD_ADDRESS 0x55 // ' '
|
||||||
|
#define Cmnd_STK_UNIVERSAL 0x56 // ' '
|
||||||
|
|
||||||
|
#define Cmnd_STK_PROG_FLASH 0x60 // ' '
|
||||||
|
#define Cmnd_STK_PROG_DATA 0x61 // ' '
|
||||||
|
#define Cmnd_STK_PROG_FUSE 0x62 // ' '
|
||||||
|
#define Cmnd_STK_PROG_LOCK 0x63 // ' '
|
||||||
|
#define Cmnd_STK_PROG_PAGE 0x64 // ' '
|
||||||
|
#define Cmnd_STK_PROG_FUSE_EXT 0x65 // ' '
|
||||||
|
|
||||||
|
#define Cmnd_STK_READ_FLASH 0x70 // ' '
|
||||||
|
#define Cmnd_STK_READ_DATA 0x71 // ' '
|
||||||
|
#define Cmnd_STK_READ_FUSE 0x72 // ' '
|
||||||
|
#define Cmnd_STK_READ_LOCK 0x73 // ' '
|
||||||
|
#define Cmnd_STK_READ_PAGE 0x74 // ' '
|
||||||
|
#define Cmnd_STK_READ_SIGN 0x75 // ' '
|
||||||
|
#define Cmnd_STK_READ_OSCCAL 0x76 // ' '
|
||||||
|
#define Cmnd_STK_READ_FUSE_EXT 0x77 // ' '
|
||||||
|
#define Cmnd_STK_READ_OSCCAL_EXT 0x78 // ' '
|
||||||
|
|
||||||
|
// *****************[ STK Parameter constants ]***************************
|
||||||
|
|
||||||
|
#define Parm_STK_HW_VER 0x80 // ' ' - R
|
||||||
|
#define Parm_STK_SW_MAJOR 0x81 // ' ' - R
|
||||||
|
#define Parm_STK_SW_MINOR 0x82 // ' ' - R
|
||||||
|
#define Parm_STK_LEDS 0x83 // ' ' - R/W
|
||||||
|
#define Parm_STK_VTARGET 0x84 // ' ' - R/W
|
||||||
|
#define Parm_STK_VADJUST 0x85 // ' ' - R/W
|
||||||
|
#define Parm_STK_OSC_PSCALE 0x86 // ' ' - R/W
|
||||||
|
#define Parm_STK_OSC_CMATCH 0x87 // ' ' - R/W
|
||||||
|
#define Parm_STK_RESET_DURATION 0x88 // ' ' - R/W
|
||||||
|
#define Parm_STK_SCK_DURATION 0x89 // ' ' - R/W
|
||||||
|
|
||||||
|
#define Parm_STK_BUFSIZEL 0x90 // ' ' - R/W, Range {0..255}
|
||||||
|
#define Parm_STK_BUFSIZEH 0x91 // ' ' - R/W, Range {0..255}
|
||||||
|
#define Parm_STK_DEVICE 0x92 // ' ' - R/W, Range {0..255}
|
||||||
|
#define Parm_STK_PROGMODE 0x93 // ' ' - 'P' or 'S'
|
||||||
|
#define Parm_STK_PARAMODE 0x94 // ' ' - TRUE or FALSE
|
||||||
|
#define Parm_STK_POLLING 0x95 // ' ' - TRUE or FALSE
|
||||||
|
#define Parm_STK_SELFTIMED 0x96 // ' ' - TRUE or FALSE
|
||||||
|
|
||||||
|
|
||||||
|
// *****************[ STK status bit definitions ]***************************
|
||||||
|
|
||||||
|
#define Stat_STK_INSYNC 0x01 // INSYNC status bit, '1' - INSYNC
|
||||||
|
#define Stat_STK_PROGMODE 0x02 // Programming mode, '1' - PROGMODE
|
||||||
|
#define Stat_STK_STANDALONE 0x04 // Standalone mode, '1' - SM mode
|
||||||
|
#define Stat_STK_RESET 0x08 // RESET button, '1' - Pushed
|
||||||
|
#define Stat_STK_PROGRAM 0x10 // Program button, ' 1' - Pushed
|
||||||
|
#define Stat_STK_LEDG 0x20 // Green LED status, '1' - Lit
|
||||||
|
#define Stat_STK_LEDR 0x40 // Red LED status, '1' - Lit
|
||||||
|
#define Stat_STK_LEDBLINK 0x80 // LED blink ON/OFF, '1' - Blink
|
||||||
|
|
||||||
|
|
||||||
|
// *****************************[ End Of COMMAND.H ]**************************
|
Loading…
x
Reference in New Issue
Block a user