mirror of https://github.com/jeelabs/esp-link.git
Bits and pieces for flashing an Arduino Mega. (#290)
parent
c0cd698860
commit
bc87885a5f
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,14 @@ |
|||||||
|
// Copyright (c) 2016-2017 by Danny Backx, see LICENSE.txt in the esp-link repo
|
||||||
|
|
||||||
|
#ifndef CGIMEGA_H |
||||||
|
#define CGIMEGA_H |
||||||
|
|
||||||
|
#include <httpd.h> |
||||||
|
|
||||||
|
int ICACHE_FLASH_ATTR cgiMegaSync(HttpdConnData *connData); |
||||||
|
int ICACHE_FLASH_ATTR cgiMegaData(HttpdConnData *connData); |
||||||
|
int ICACHE_FLASH_ATTR cgiMegaRead(HttpdConnData *connData); |
||||||
|
int ICACHE_FLASH_ATTR cgiMegaFuse(HttpdConnData *connData); |
||||||
|
int ICACHE_FLASH_ATTR cgiMegaRebootMCU(HttpdConnData *connData); |
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,149 @@ |
|||||||
|
// Copyright (c) 2015 by Thorsten von Eicken, see LICENSE.txt in the esp-link repo
|
||||||
|
// Copyright (c) 2016-2017 by Danny Backx
|
||||||
|
|
||||||
|
#include <esp8266.h> |
||||||
|
#include <osapi.h> |
||||||
|
#include "cgi.h" |
||||||
|
#include "config.h" |
||||||
|
#include "uart.h" |
||||||
|
#include "stk500v2.h" |
||||||
|
#include "serbridge.h" |
||||||
|
#include "serled.h" |
||||||
|
|
||||||
|
#include "pgmshared.h" |
||||||
|
|
||||||
|
struct optibootData *optibootData; |
||||||
|
|
||||||
|
char responseBuf[RESP_SZ]; // buffer to accumulate responses from optiboot
|
||||||
|
short responseLen = 0; // amount accumulated so far
|
||||||
|
char errMessage[ERR_MAX]; // error message
|
||||||
|
|
||||||
|
// verify that N chars are hex characters
|
||||||
|
bool ICACHE_FLASH_ATTR checkHex(char *buf, short len) { |
||||||
|
while (len--) { |
||||||
|
char c = *buf++; |
||||||
|
if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) |
||||||
|
continue; |
||||||
|
DBG("OB non-hex\n"); |
||||||
|
os_sprintf(errMessage, "Non hex char in POST record: '%c'/0x%02x", c, c); |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
// get hex value of some hex characters
|
||||||
|
uint32_t ICACHE_FLASH_ATTR getHexValue(char *buf, short len) { |
||||||
|
uint32_t v = 0; |
||||||
|
while (len--) { |
||||||
|
v = (v<<4) | (uint32_t)(*buf & 0xf); |
||||||
|
if (*buf > '9') v += 9; |
||||||
|
buf++; |
||||||
|
} |
||||||
|
return v; |
||||||
|
} |
||||||
|
|
||||||
|
// verify checksum
|
||||||
|
static bool ICACHE_FLASH_ATTR verifyChecksum(char *buf, short len) { |
||||||
|
uint8_t sum = 0; |
||||||
|
while (len >= 2) { |
||||||
|
sum += (uint8_t)getHexValue(buf, 2); |
||||||
|
buf += 2; |
||||||
|
len -= 2; |
||||||
|
} |
||||||
|
return sum == 0; |
||||||
|
} |
||||||
|
|
||||||
|
// We've not built one function that works on both, but kept the different functions.
|
||||||
|
// This calls one or the other
|
||||||
|
static bool ICACHE_FLASH_ATTR programPage() { |
||||||
|
if (optibootData->mega) |
||||||
|
return megaProgramPage(); |
||||||
|
return optibootProgramPage(); |
||||||
|
} |
||||||
|
|
||||||
|
// Process a hex record -- assumes that the records starts with ':' & hex length
|
||||||
|
bool ICACHE_FLASH_ATTR processRecord(char *buf, short len) { |
||||||
|
buf++; len--; // skip leading ':'
|
||||||
|
// check we have all hex chars
|
||||||
|
if (!checkHex(buf, len)) return false; |
||||||
|
// verify checksum
|
||||||
|
if (!verifyChecksum(buf, len)) { |
||||||
|
buf[len] = 0; |
||||||
|
os_sprintf(errMessage, "Invalid checksum for record %s", buf); |
||||||
|
return false; |
||||||
|
} |
||||||
|
// dispatch based on record type
|
||||||
|
uint8_t type = getHexValue(buf+6, 2); |
||||||
|
switch (type) { |
||||||
|
case 0x00: { // Intel HEX data record
|
||||||
|
//DBG("OB REC data %ld pglen=%d\n", getHexValue(buf, 2), optibootData->pageLen);
|
||||||
|
uint32_t addr = getHexValue(buf+2, 4); |
||||||
|
// check whether we need to program previous record(s)
|
||||||
|
if (optibootData->pageLen > 0 && |
||||||
|
addr != ((optibootData->address+optibootData->pageLen)&0xffff)) { |
||||||
|
//DBG("OB addr chg\n");
|
||||||
|
//DBG("processRecord addr chg, len %d, addr 0x%04x\n", optibootData->pageLen, addr);
|
||||||
|
if (!programPage()) return false; |
||||||
|
} |
||||||
|
// set address, unless we're adding to the end (programPage may have changed pageLen)
|
||||||
|
if (optibootData->pageLen == 0) { |
||||||
|
optibootData->address = (optibootData->address & 0xffff0000) | addr; |
||||||
|
//DBG("OB set-addr 0x%lx\n", optibootData->address);
|
||||||
|
} |
||||||
|
// append record
|
||||||
|
uint16_t recLen = getHexValue(buf, 2); |
||||||
|
for (uint16_t i=0; i<recLen; i++) |
||||||
|
optibootData->pageBuf[optibootData->pageLen++] = getHexValue(buf+8+2*i, 2); |
||||||
|
// program page, if we have a full page
|
||||||
|
if (optibootData->pageLen >= optibootData->pgmSz) { |
||||||
|
//DBG("OB full\n");
|
||||||
|
DBG("processRecord %d, call programPage() %08x\n", optibootData->pgmSz, optibootData->address + optibootData->segment); |
||||||
|
if (!programPage()) return false; |
||||||
|
} |
||||||
|
break; } |
||||||
|
case 0x01: // Intel HEX EOF record
|
||||||
|
DBG("OB EOF\n"); |
||||||
|
// program any remaining partial page
|
||||||
|
#if 1 |
||||||
|
if (optibootData->pageLen > 0) { |
||||||
|
// DBG("processRecord remaining partial page, len %d, addr 0x%04x\n", optibootData->pageLen, optibootData->address + optibootData->segment);
|
||||||
|
if (!programPage()) return false; |
||||||
|
} |
||||||
|
optibootData->eof = true; |
||||||
|
#else |
||||||
|
if (optibootData->pageLen > 0) { |
||||||
|
// HACK : fill up with 0xFF
|
||||||
|
while (optibootData->pageLen < 256) { |
||||||
|
optibootData->pageBuf[optibootData->pageLen++] = 0xFF; |
||||||
|
} |
||||||
|
if (!programPage()) return false; |
||||||
|
} |
||||||
|
optibootData->eof = true; |
||||||
|
#endif |
||||||
|
break; |
||||||
|
case 0x04: // Intel HEX address record
|
||||||
|
DBG("OB address 0x%x\n", getHexValue(buf+8, 4) << 16); |
||||||
|
// program any remaining partial page
|
||||||
|
if (optibootData->pageLen > 0) { |
||||||
|
DBG("processRecord 0x04 remaining partial page, len %d, addr 0x%04x\n", |
||||||
|
optibootData->pageLen, optibootData->address + optibootData->segment); |
||||||
|
if (!programPage()) return false; |
||||||
|
} |
||||||
|
optibootData->address = getHexValue(buf+8, 4) << 16; |
||||||
|
break; |
||||||
|
case 0x05: // Intel HEX start address (MDK-ARM only)
|
||||||
|
// ignore, there's no way to tell optiboot that...
|
||||||
|
break; |
||||||
|
case 0x02: // Intel HEX extended segment address record
|
||||||
|
// Depending on the case, just ignoring this record could solve the problem
|
||||||
|
// optibootData->segment = getHexValue(buf+8, 4) << 4;
|
||||||
|
DBG("OB segment 0x%08X\n", optibootData->segment); |
||||||
|
return true; |
||||||
|
default: |
||||||
|
// DBG("OB bad record type\n");
|
||||||
|
DBG(errMessage, "Invalid/unknown record type: 0x%02x, packet %s", type, buf); |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
@ -0,0 +1,54 @@ |
|||||||
|
// Copyright (c) 2015 by Thorsten von Eicken, see LICENSE.txt in the esp-link repo
|
||||||
|
// Copyright (c) 2017 by Danny Backx
|
||||||
|
|
||||||
|
#ifndef _PGM_SHARED_H_ |
||||||
|
#define _PGM_SHARED_H_ |
||||||
|
|
||||||
|
#include "user_config.h" |
||||||
|
|
||||||
|
#define RESP_SZ 64 |
||||||
|
#define ERR_MAX 128 |
||||||
|
|
||||||
|
extern char responseBuf[RESP_SZ]; |
||||||
|
extern short responseLen; |
||||||
|
extern char errMessage[ERR_MAX]; |
||||||
|
|
||||||
|
// structure used to remember request details from one callback to the next
|
||||||
|
// allocated dynamically so we don't burn so much static RAM
|
||||||
|
extern struct optibootData { |
||||||
|
char *saved; // buffer for saved incomplete hex records
|
||||||
|
char *pageBuf; // buffer for received data to be sent to AVR
|
||||||
|
uint16_t pageLen; // number of bytes in pageBuf
|
||||||
|
uint16_t pgmSz; // size of flash page to be programmed at a time
|
||||||
|
uint32_t pgmDone; // number of bytes programmed
|
||||||
|
uint32_t address; // address to write next page to
|
||||||
|
uint32_t segment; // for extended segment addressing, added to the address field
|
||||||
|
uint32_t startTime; // time of program POST request
|
||||||
|
HttpdConnData *conn; // request doing the programming, so we can cancel it
|
||||||
|
bool eof; // got EOF record
|
||||||
|
|
||||||
|
// Whether to use the Mega (STK500v2) protocol
|
||||||
|
bool mega; |
||||||
|
|
||||||
|
// STK500v2 variables
|
||||||
|
int hardwareVersion, |
||||||
|
firmwareVersionMajor, |
||||||
|
firmwareVersionMinor, |
||||||
|
vTarget; |
||||||
|
uint8_t signature[3]; |
||||||
|
uint8_t lfuse, hfuse, efuse; |
||||||
|
} *optibootData; |
||||||
|
|
||||||
|
bool ICACHE_FLASH_ATTR checkHex(char *buf, short len); |
||||||
|
uint32_t ICACHE_FLASH_ATTR getHexValue(char *buf, short len); |
||||||
|
bool ICACHE_FLASH_ATTR processRecord(char *buf, short len); |
||||||
|
bool megaProgramPage(void); |
||||||
|
bool optibootProgramPage(void); |
||||||
|
|
||||||
|
#ifdef OPTIBOOT_DBG |
||||||
|
#define DBG(format, ...) do { os_printf(format, ## __VA_ARGS__); } while(0) |
||||||
|
#else |
||||||
|
#define DBG(format, ...) do { } while(0) |
||||||
|
#endif |
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,114 @@ |
|||||||
|
//**** ATMEL AVR - A P P L I C A T I O N N O T E ************************
|
||||||
|
//*
|
||||||
|
//* Title: AVR068 - STK500 Communication Protocol
|
||||||
|
//* Filename: command.h
|
||||||
|
//* Version: 1.0
|
||||||
|
//* Last updated: 31.01.2005
|
||||||
|
//*
|
||||||
|
//* Support E-mail: avr@atmel.com
|
||||||
|
//*
|
||||||
|
//**************************************************************************
|
||||||
|
|
||||||
|
// *****************[ STK message constants ]***************************
|
||||||
|
|
||||||
|
#define MESSAGE_START 0x1B //= ESC = 27 decimal
|
||||||
|
#define TOKEN 0x0E |
||||||
|
|
||||||
|
// *****************[ STK general command constants ]**************************
|
||||||
|
|
||||||
|
#define CMD_SIGN_ON 0x01 |
||||||
|
#define CMD_SET_PARAMETER 0x02 |
||||||
|
#define CMD_GET_PARAMETER 0x03 |
||||||
|
#define CMD_SET_DEVICE_PARAMETERS 0x04 |
||||||
|
#define CMD_OSCCAL 0x05 |
||||||
|
#define CMD_LOAD_ADDRESS 0x06 |
||||||
|
#define CMD_FIRMWARE_UPGRADE 0x07 |
||||||
|
|
||||||
|
|
||||||
|
// *****************[ STK ISP command constants ]******************************
|
||||||
|
|
||||||
|
#define CMD_ENTER_PROGMODE_ISP 0x10 |
||||||
|
#define CMD_LEAVE_PROGMODE_ISP 0x11 |
||||||
|
#define CMD_CHIP_ERASE_ISP 0x12 |
||||||
|
#define CMD_PROGRAM_FLASH_ISP 0x13 |
||||||
|
#define CMD_READ_FLASH_ISP 0x14 |
||||||
|
#define CMD_PROGRAM_EEPROM_ISP 0x15 |
||||||
|
#define CMD_READ_EEPROM_ISP 0x16 |
||||||
|
#define CMD_PROGRAM_FUSE_ISP 0x17 |
||||||
|
#define CMD_READ_FUSE_ISP 0x18 |
||||||
|
#define CMD_PROGRAM_LOCK_ISP 0x19 |
||||||
|
#define CMD_READ_LOCK_ISP 0x1A |
||||||
|
#define CMD_READ_SIGNATURE_ISP 0x1B |
||||||
|
#define CMD_READ_OSCCAL_ISP 0x1C |
||||||
|
#define CMD_SPI_MULTI 0x1D |
||||||
|
|
||||||
|
// *****************[ STK PP command constants ]*******************************
|
||||||
|
|
||||||
|
#define CMD_ENTER_PROGMODE_PP 0x20 |
||||||
|
#define CMD_LEAVE_PROGMODE_PP 0x21 |
||||||
|
#define CMD_CHIP_ERASE_PP 0x22 |
||||||
|
#define CMD_PROGRAM_FLASH_PP 0x23 |
||||||
|
#define CMD_READ_FLASH_PP 0x24 |
||||||
|
#define CMD_PROGRAM_EEPROM_PP 0x25 |
||||||
|
#define CMD_READ_EEPROM_PP 0x26 |
||||||
|
#define CMD_PROGRAM_FUSE_PP 0x27 |
||||||
|
#define CMD_READ_FUSE_PP 0x28 |
||||||
|
#define CMD_PROGRAM_LOCK_PP 0x29 |
||||||
|
#define CMD_READ_LOCK_PP 0x2A |
||||||
|
#define CMD_READ_SIGNATURE_PP 0x2B |
||||||
|
#define CMD_READ_OSCCAL_PP 0x2C |
||||||
|
|
||||||
|
#define CMD_SET_CONTROL_STACK 0x2D |
||||||
|
|
||||||
|
// *****************[ STK HVSP command constants ]*****************************
|
||||||
|
|
||||||
|
#define CMD_ENTER_PROGMODE_HVSP 0x30 |
||||||
|
#define CMD_LEAVE_PROGMODE_HVSP 0x31 |
||||||
|
#define CMD_CHIP_ERASE_HVSP 0x32 |
||||||
|
#define CMD_PROGRAM_FLASH_HVSP 0x33 |
||||||
|
#define CMD_READ_FLASH_HVSP 0x34 |
||||||
|
#define CMD_PROGRAM_EEPROM_HVSP 0x35 |
||||||
|
#define CMD_READ_EEPROM_HVSP 0x36 |
||||||
|
#define CMD_PROGRAM_FUSE_HVSP 0x37 |
||||||
|
#define CMD_READ_FUSE_HVSP 0x38 |
||||||
|
#define CMD_PROGRAM_LOCK_HVSP 0x39 |
||||||
|
#define CMD_READ_LOCK_HVSP 0x3A |
||||||
|
#define CMD_READ_SIGNATURE_HVSP 0x3B |
||||||
|
#define CMD_READ_OSCCAL_HVSP 0x3C |
||||||
|
|
||||||
|
// *****************[ STK status constants ]***************************
|
||||||
|
|
||||||
|
// Success
|
||||||
|
#define STATUS_CMD_OK 0x00 |
||||||
|
|
||||||
|
// Warnings
|
||||||
|
#define STATUS_CMD_TOUT 0x80 |
||||||
|
#define STATUS_RDY_BSY_TOUT 0x81 |
||||||
|
#define STATUS_SET_PARAM_MISSING 0x82 |
||||||
|
|
||||||
|
// Errors
|
||||||
|
#define STATUS_CMD_FAILED 0xC0 |
||||||
|
#define STATUS_CKSUM_ERROR 0xC1 |
||||||
|
#define STATUS_CMD_UNKNOWN 0xC9 |
||||||
|
|
||||||
|
// *****************[ STK parameter constants ]***************************
|
||||||
|
#define PARAM_BUILD_NUMBER_LOW 0x80 |
||||||
|
#define PARAM_BUILD_NUMBER_HIGH 0x81 |
||||||
|
#define PARAM_HW_VER 0x90 |
||||||
|
#define PARAM_SW_MAJOR 0x91 |
||||||
|
#define PARAM_SW_MINOR 0x92 |
||||||
|
#define PARAM_VTARGET 0x94 |
||||||
|
#define PARAM_VADJUST 0x95 |
||||||
|
#define PARAM_OSC_PSCALE 0x96 |
||||||
|
#define PARAM_OSC_CMATCH 0x97 |
||||||
|
#define PARAM_SCK_DURATION 0x98 |
||||||
|
#define PARAM_TOPCARD_DETECT 0x9A |
||||||
|
#define PARAM_STATUS 0x9C |
||||||
|
#define PARAM_DATA 0x9D |
||||||
|
#define PARAM_RESET_POLARITY 0x9E |
||||||
|
#define PARAM_CONTROLLER_INIT 0x9F |
||||||
|
|
||||||
|
// *****************[ STK answer constants ]***************************
|
||||||
|
|
||||||
|
#define ANSWER_CKSUM_ERROR 0xB0 |
||||||
|
|
@ -0,0 +1,114 @@ |
|||||||
|
#! /bin/bash |
||||||
|
# |
||||||
|
# Flash an Arduino Mega with STK500v2 using the esp-link built-in programmer |
||||||
|
# Basically we first reset the AVR and get in sync, and then send the hex file |
||||||
|
# |
||||||
|
# ---------------------------------------------------------------------------- |
||||||
|
# "THE BEER-WARE LICENSE" (Revision 42): |
||||||
|
# Thorsten von Eicken wrote this file. As long as you retain |
||||||
|
# this notice you can do whatever you want with this stuff. If we meet some day, |
||||||
|
# and you think this stuff is worth it, you can buy me a beer in return. |
||||||
|
# |
||||||
|
# Danny Backx wrote the changes for Arduino Mega. |
||||||
|
# ---------------------------------------------------------------------------- |
||||||
|
|
||||||
|
show_help() { |
||||||
|
cat <<EOT |
||||||
|
Usage: ${0##*/} [-options...] hostname sketch.hex |
||||||
|
Flash the Mega running optiboot attached to esp-link with the sketch. |
||||||
|
Note : this is for stk500v2 MCUs, use avrflash for Arduino Uno etc instead. |
||||||
|
-v Be verbose |
||||||
|
-h show this help |
||||||
|
|
||||||
|
Example: ${0##*/} -v esp-link mysketch.hex |
||||||
|
${0##*/} 192.168.4.1 mysketch.hex |
||||||
|
EOT |
||||||
|
} |
||||||
|
|
||||||
|
if ! which curl >/dev/null; then |
||||||
|
echo "ERROR: Cannot find curl: it is required for this script." >&2 |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
|
||||||
|
start=`date +%s` |
||||||
|
|
||||||
|
# ===== Parse arguments |
||||||
|
|
||||||
|
verbose= |
||||||
|
|
||||||
|
while getopts "hvx:" opt; do |
||||||
|
case "$opt" in |
||||||
|
h) show_help; exit 0 ;; |
||||||
|
v) verbose=1 ;; |
||||||
|
x) foo="$OPTARG" ;; |
||||||
|
'?') show_help >&2; exit 1 ;; |
||||||
|
esac |
||||||
|
done |
||||||
|
|
||||||
|
# Shift off the options and optional --. |
||||||
|
shift "$((OPTIND-1))" |
||||||
|
|
||||||
|
# Get the fixed arguments |
||||||
|
if [[ $# != 2 ]]; then |
||||||
|
show_help >&2 |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
hostname=$1 |
||||||
|
hex=$2 |
||||||
|
|
||||||
|
re='[-A-Za-z0-9.]+' |
||||||
|
if [[ ! "$hostname" =~ $re ]]; then |
||||||
|
echo "ERROR: hostname ${hostname} is not a valid hostname or ip address" >&2 |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
|
||||||
|
if [[ ! -r "$hex" ]]; then |
||||||
|
echo "ERROR: cannot read hex file ($hex)" >&2 |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
|
||||||
|
# ===== Get AVR in sync |
||||||
|
|
||||||
|
[[ -n "$verbose" ]] && echo "Resetting AVR with http://$hostname/pgmmega/sync" >&2 |
||||||
|
v=; [[ -n "$verbose" ]] && v=-v |
||||||
|
sync=`curl -m 10 $v -s -w '%{http_code}' -XPOST "http://$hostname/pgmmega/sync"` |
||||||
|
if [[ $? != 0 || "$sync" != 204 ]]; then |
||||||
|
echo "Error resetting AVR" >&2 |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
|
||||||
|
while true; do |
||||||
|
# sync=`curl -m 10 $v -s "http://$hostname/pgmmega/sync"` |
||||||
|
sync=`curl $v -s "http://$hostname/pgmmega/sync"` |
||||||
|
if [[ $? != 0 ]]; then |
||||||
|
echo "Error checking sync" >&2 |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
case "$sync" in |
||||||
|
SYNC*) |
||||||
|
echo "AVR in $sync" >&2 |
||||||
|
break;; |
||||||
|
"NOT READY"*) |
||||||
|
[[ -n "$verbose" ]] && echo " Waiting for sync..." >&2 |
||||||
|
;; |
||||||
|
*) |
||||||
|
echo "Error checking sync: $sync" >&2 |
||||||
|
exit 1 |
||||||
|
;; |
||||||
|
esac |
||||||
|
sleep 0.1 |
||||||
|
done |
||||||
|
|
||||||
|
# ===== Send HEX file |
||||||
|
|
||||||
|
[[ -n "$verbose" ]] && echo "Sending HEX file for programming" >&2 |
||||||
|
sync=`curl -m 20 $v -s -g -d "@$hex" "http://$hostname/pgmmega/upload"` |
||||||
|
echo $sync |
||||||
|
if [[ $? != 0 || ! "$sync" =~ ^Success ]]; then |
||||||
|
echo "Error programming AVR" >&2 |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
|
||||||
|
sec=$(( `date +%s` - $start )) |
||||||
|
echo "Success, took $sec seconds" >&2 |
||||||
|
exit 0 |
Loading…
Reference in new issue