mirror of
https://github.com/esp8266/Arduino.git
synced 2025-07-30 16:24:09 +03:00
Renaming platform components.
This commit is contained in:
536
hardware/avr/bootloaders/optiboot/optiboot.c
Normal file
536
hardware/avr/bootloaders/optiboot/optiboot.c
Normal file
@ -0,0 +1,536 @@
|
||||
/**********************************************************/
|
||||
/* Optiboot bootloader for Arduino */
|
||||
/* */
|
||||
/* Heavily optimised bootloader that is faster and */
|
||||
/* smaller than the Arduino standard bootloader */
|
||||
/* */
|
||||
/* Enhancements: */
|
||||
/* Fits in 512 bytes, saving 1.5K of code space */
|
||||
/* Background page erasing speeds up programming */
|
||||
/* Higher baud rate speeds up programming */
|
||||
/* Written almost entirely in C */
|
||||
/* Customisable timeout with accurate timeconstant */
|
||||
/* */
|
||||
/* What you lose: */
|
||||
/* Implements a skeleton STK500 protocol which is */
|
||||
/* missing several features including EEPROM */
|
||||
/* programming and non-page-aligned writes */
|
||||
/* High baud rate breaks compatibility with standard */
|
||||
/* Arduino flash settings */
|
||||
/* */
|
||||
/* Currently supports: */
|
||||
/* ATmega168 based devices (Diecimila etc) */
|
||||
/* ATmega328P based devices (Duemilanove etc) */
|
||||
/* */
|
||||
/* Does not support: */
|
||||
/* ATmega1280 based devices (eg. Mega) */
|
||||
/* */
|
||||
/* Assumptions: */
|
||||
/* The code makes several assumptions that reduce the */
|
||||
/* code size. They are all true after a hardware reset, */
|
||||
/* but may not be true if the bootloader is called by */
|
||||
/* other means or on other hardware. */
|
||||
/* No interrupts can occur */
|
||||
/* UART and Timer 1 are set to their reset state */
|
||||
/* SP points to RAMEND */
|
||||
/* */
|
||||
/* Code builds on code, libraries and optimisations from: */
|
||||
/* stk500boot.c by Jason P. Kyle */
|
||||
/* Arduino bootloader http://arduino.cc */
|
||||
/* Spiff's 1K bootloader http://spiffie.org/know/arduino_1k_bootloader/bootloader.shtml */
|
||||
/* avr-libc project http://nongnu.org/avr-libc */
|
||||
/* Adaboot http://www.ladyada.net/library/arduino/bootloader.html */
|
||||
/* AVR305 Atmel Application Note */
|
||||
/* */
|
||||
/* This program is free software; you can redistribute it */
|
||||
/* and/or modify it under the terms of the GNU General */
|
||||
/* Public License as published by the Free Software */
|
||||
/* Foundation; either version 2 of the License, or */
|
||||
/* (at your option) any later version. */
|
||||
/* */
|
||||
/* This program is distributed in the hope that it will */
|
||||
/* be useful, but WITHOUT ANY WARRANTY; without even the */
|
||||
/* implied warranty of MERCHANTABILITY or FITNESS FOR A */
|
||||
/* PARTICULAR PURPOSE. See the GNU General Public */
|
||||
/* License for more details. */
|
||||
/* */
|
||||
/* You should have received a copy of the GNU General */
|
||||
/* Public License along with this program; if not, write */
|
||||
/* to the Free Software Foundation, Inc., */
|
||||
/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
/* */
|
||||
/* Licence can be viewed at */
|
||||
/* http://www.fsf.org/licenses/gpl.txt */
|
||||
/* */
|
||||
/**********************************************************/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <avr/boot.h>
|
||||
|
||||
//#define LED_DATA_FLASH
|
||||
|
||||
#ifndef LED_START_FLASHES
|
||||
#define LED_START_FLASHES 0
|
||||
#endif
|
||||
|
||||
/* Build-time variables */
|
||||
/* BAUD_RATE Programming baud rate */
|
||||
/* LED_NO_FLASHES Number of LED flashes on boot */
|
||||
/* FLASH_TIME_MS Duration of each LED flash */
|
||||
/* BOOT_TIMEOUT_MS Serial port wait time before exiting bootloader */
|
||||
|
||||
/* set the UART baud rate */
|
||||
#ifndef BAUD_RATE
|
||||
#define BAUD_RATE 19200
|
||||
#endif
|
||||
|
||||
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__)
|
||||
/* Onboard LED is connected to pin PB5 in Arduino NG, Diecimila, and Duemilanove */
|
||||
#define LED_DDR DDRB
|
||||
#define LED_PORT PORTB
|
||||
#define LED_PIN PINB
|
||||
#define LED PINB5
|
||||
|
||||
/* Ports for soft UART */
|
||||
#ifdef SOFT_UART
|
||||
#define UART_PORT PORTD
|
||||
#define UART_PIN PIND
|
||||
#define UART_DDR DDRD
|
||||
#define UART_TX_BIT 1
|
||||
#define UART_RX_BIT 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__AVR_ATtiny84__)
|
||||
/* Onboard LED is connected to pin PB5 in Arduino NG, Diecimila, and Duemilanove */
|
||||
#define LED_DDR DDRA
|
||||
#define LED_PORT PORTA
|
||||
#define LED_PIN PINA
|
||||
#define LED PINA4
|
||||
|
||||
/* Ports for soft UART - left port only for now*/
|
||||
#ifdef SOFT_UART
|
||||
#define UART_PORT PORTA
|
||||
#define UART_PIN PINA
|
||||
#define UART_DDR DDRA
|
||||
#define UART_TX_BIT 2
|
||||
#define UART_RX_BIT 3
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* STK500 constants list, from AVRDUDE */
|
||||
#define STK_OK 0x10
|
||||
#define STK_FAILED 0x11 // Not used
|
||||
#define STK_UNKNOWN 0x12 // Not used
|
||||
#define STK_NODEVICE 0x13 // Not used
|
||||
#define STK_INSYNC 0x14 // ' '
|
||||
#define STK_NOSYNC 0x15 // Not used
|
||||
#define ADC_CHANNEL_ERROR 0x16 // Not used
|
||||
#define ADC_MEASURE_OK 0x17 // Not used
|
||||
#define PWM_CHANNEL_ERROR 0x18 // Not used
|
||||
#define PWM_ADJUST_OK 0x19 // Not used
|
||||
#define CRC_EOP 0x20 // 'SPACE'
|
||||
#define STK_GET_SYNC 0x30 // '0'
|
||||
#define STK_GET_SIGN_ON 0x31 // '1'
|
||||
#define STK_SET_PARAMETER 0x40 // '@'
|
||||
#define STK_GET_PARAMETER 0x41 // 'A'
|
||||
#define STK_SET_DEVICE 0x42 // 'B'
|
||||
#define STK_SET_DEVICE_EXT 0x45 // 'E'
|
||||
#define STK_ENTER_PROGMODE 0x50 // 'P'
|
||||
#define STK_LEAVE_PROGMODE 0x51 // 'Q'
|
||||
#define STK_CHIP_ERASE 0x52 // 'R'
|
||||
#define STK_CHECK_AUTOINC 0x53 // 'S'
|
||||
#define STK_LOAD_ADDRESS 0x55 // 'U'
|
||||
#define STK_UNIVERSAL 0x56 // 'V'
|
||||
#define STK_PROG_FLASH 0x60 // '`'
|
||||
#define STK_PROG_DATA 0x61 // 'a'
|
||||
#define STK_PROG_FUSE 0x62 // 'b'
|
||||
#define STK_PROG_LOCK 0x63 // 'c'
|
||||
#define STK_PROG_PAGE 0x64 // 'd'
|
||||
#define STK_PROG_FUSE_EXT 0x65 // 'e'
|
||||
#define STK_READ_FLASH 0x70 // 'p'
|
||||
#define STK_READ_DATA 0x71 // 'q'
|
||||
#define STK_READ_FUSE 0x72 // 'r'
|
||||
#define STK_READ_LOCK 0x73 // 's'
|
||||
#define STK_READ_PAGE 0x74 // 't'
|
||||
#define STK_READ_SIGN 0x75 // 'u'
|
||||
#define STK_READ_OSCCAL 0x76 // 'v'
|
||||
#define STK_READ_FUSE_EXT 0x77 // 'w'
|
||||
#define STK_READ_OSCCAL_EXT 0x78 // 'x'
|
||||
|
||||
/* Watchdog settings */
|
||||
#define WATCHDOG_OFF (0)
|
||||
#define WATCHDOG_16MS (_BV(WDE))
|
||||
#define WATCHDOG_32MS (_BV(WDP0) | _BV(WDE))
|
||||
#define WATCHDOG_64MS (_BV(WDP1) | _BV(WDE))
|
||||
#define WATCHDOG_125MS (_BV(WDP1) | _BV(WDP0) | _BV(WDE))
|
||||
#define WATCHDOG_250MS (_BV(WDP2) | _BV(WDE))
|
||||
#define WATCHDOG_500MS (_BV(WDP2) | _BV(WDP0) | _BV(WDE))
|
||||
#define WATCHDOG_1S (_BV(WDP2) | _BV(WDP1) | _BV(WDE))
|
||||
#define WATCHDOG_2S (_BV(WDP2) | _BV(WDP1) | _BV(WDP0) | _BV(WDE))
|
||||
#define WATCHDOG_4S (_BV(WDE3) | _BV(WDE))
|
||||
#define WATCHDOG_8S (_BV(WDE3) | _BV(WDE0) | _BV(WDE))
|
||||
|
||||
/* Function Prototypes */
|
||||
/* The main function is in init9, which removes the interrupt vector table */
|
||||
/* we don't need. It is also 'naked', which means the compiler does not */
|
||||
/* generate any entry or exit code itself. */
|
||||
int main(void) __attribute__ ((naked)) __attribute__ ((section (".init9")));
|
||||
void putch(char);
|
||||
uint8_t getch(void);
|
||||
static inline void getNch(uint8_t); /* "static inline" is a compiler hint to reduce code size */
|
||||
void verifySpace();
|
||||
static inline void flash_led(uint8_t);
|
||||
uint8_t getLen();
|
||||
static inline void watchdogReset();
|
||||
void watchdogConfig(uint8_t x);
|
||||
#ifdef SOFT_UART
|
||||
void uartDelay() __attribute__ ((naked));
|
||||
#endif
|
||||
void appStart() __attribute__ ((naked));
|
||||
|
||||
/* C zero initialises all global variables. However, that requires */
|
||||
/* These definitions are NOT zero initialised, but that doesn't matter */
|
||||
/* This allows us to drop the zero init code, saving us memory */
|
||||
#define buff ((uint8_t*)(0x100))
|
||||
#define address (*(uint16_t*)(0x200))
|
||||
#define length (*(uint8_t*)(0x202))
|
||||
#ifdef VIRTUAL_BOOT_PARTITION
|
||||
#define rstVect (*(uint16_t*)(0x204))
|
||||
#define wdtVect (*(uint16_t*)(0x206))
|
||||
#endif
|
||||
/* main program starts here */
|
||||
int main(void) {
|
||||
// After the zero init loop, this is the first code to run.
|
||||
//
|
||||
// This code makes the following assumptions:
|
||||
// No interrupts will execute
|
||||
// SP points to RAMEND
|
||||
// r1 contains zero
|
||||
//
|
||||
// If not, uncomment the following instructions:
|
||||
// cli();
|
||||
// SP=RAMEND; // This is done by hardware reset
|
||||
asm volatile ("clr __zero_reg__");
|
||||
|
||||
uint8_t ch;
|
||||
|
||||
#if LED_START_FLASHES > 0
|
||||
// Set up Timer 1 for timeout counter
|
||||
TCCR1B = _BV(CS12) | _BV(CS10); // div 1024
|
||||
#endif
|
||||
#ifndef SOFT_UART
|
||||
UCSR0A = _BV(U2X0); //Double speed mode USART0
|
||||
UCSR0B = _BV(RXEN0) | _BV(TXEN0);
|
||||
UCSR0C = _BV(UCSZ00) | _BV(UCSZ01);
|
||||
UBRR0L = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 );
|
||||
#endif
|
||||
|
||||
// Adaboot no-wait mod
|
||||
ch = MCUSR;
|
||||
MCUSR = 0;
|
||||
if (!(ch & _BV(EXTRF))) appStart();
|
||||
|
||||
// Set up watchdog to trigger after 500ms
|
||||
watchdogConfig(WATCHDOG_500MS);
|
||||
|
||||
/* Set LED pin as output */
|
||||
LED_DDR |= _BV(LED);
|
||||
|
||||
#ifdef SOFT_UART
|
||||
/* Set TX pin as output */
|
||||
UART_DDR |= _BV(UART_TX_BIT);
|
||||
#endif
|
||||
|
||||
#if LED_START_FLASHES > 0
|
||||
/* Flash onboard LED to signal entering of bootloader */
|
||||
flash_led(LED_START_FLASHES * 2);
|
||||
#endif
|
||||
|
||||
/* Forever loop */
|
||||
for (;;) {
|
||||
/* get character from UART */
|
||||
ch = getch();
|
||||
|
||||
if(ch == STK_GET_PARAMETER) {
|
||||
// GET PARAMETER returns a generic 0x03 reply - enough to keep Avrdude happy
|
||||
getNch(1);
|
||||
putch(0x03);
|
||||
}
|
||||
else if(ch == STK_SET_DEVICE) {
|
||||
// SET DEVICE is ignored
|
||||
getNch(20);
|
||||
}
|
||||
else if(ch == STK_SET_DEVICE_EXT) {
|
||||
// SET DEVICE EXT is ignored
|
||||
getNch(5);
|
||||
}
|
||||
else if(ch == STK_LOAD_ADDRESS) {
|
||||
// LOAD ADDRESS
|
||||
address = getch();
|
||||
address = (address & 0xff) | (getch() << 8);
|
||||
address += address; // Convert from word address to byte address
|
||||
verifySpace();
|
||||
}
|
||||
else if(ch == STK_UNIVERSAL) {
|
||||
// UNIVERSAL command is ignored
|
||||
getNch(4);
|
||||
putch(0x00);
|
||||
}
|
||||
/* Write memory, length is big endian and is in bytes */
|
||||
else if(ch == STK_PROG_PAGE) {
|
||||
// PROGRAM PAGE - we support flash programming only, not EEPROM
|
||||
uint8_t *bufPtr;
|
||||
uint16_t addrPtr;
|
||||
|
||||
getLen();
|
||||
|
||||
// Immediately start page erase - this will 4.5ms
|
||||
boot_page_erase((uint16_t)(void*)address);
|
||||
|
||||
// While that is going on, read in page contents
|
||||
bufPtr = buff;
|
||||
do *bufPtr++ = getch();
|
||||
while (--length);
|
||||
|
||||
// Read command terminator, start reply
|
||||
verifySpace();
|
||||
|
||||
// If only a partial page is to be programmed, the erase might not be complete.
|
||||
// So check that here
|
||||
boot_spm_busy_wait();
|
||||
|
||||
#ifdef VIRTUAL_BOOT_PARTITION
|
||||
if ((uint16_t)(void*)address == 0) {
|
||||
// This is the reset vector page. We need to live-patch the code so the
|
||||
// bootloader runs.
|
||||
//
|
||||
// Move RESET vector to WDT vector
|
||||
uint16_t vect = buff[0] | (buff[1]<<8);
|
||||
rstVect = vect;
|
||||
wdtVect = buff[10] | (buff[11]<<8);
|
||||
vect -= 4; // Instruction is a relative jump (rjmp), so recalculate.
|
||||
buff[10] = vect & 0xff;
|
||||
buff[11] = vect >> 8;
|
||||
|
||||
// Add jump to bootloader at RESET vector
|
||||
buff[0] = 0x7f;
|
||||
buff[1] = 0xce; // rjmp 0x1d00 instruction
|
||||
}
|
||||
#endif
|
||||
|
||||
// Copy buffer into programming buffer
|
||||
bufPtr = buff;
|
||||
addrPtr = (uint16_t)(void*)address;
|
||||
ch = SPM_PAGESIZE / 2;
|
||||
do {
|
||||
uint16_t a;
|
||||
a = *bufPtr++;
|
||||
a |= (*bufPtr++) << 8;
|
||||
boot_page_fill((uint16_t)(void*)addrPtr,a);
|
||||
addrPtr += 2;
|
||||
} while (--ch);
|
||||
|
||||
// Write from programming buffer
|
||||
boot_page_write((uint16_t)(void*)address);
|
||||
boot_spm_busy_wait();
|
||||
|
||||
#if defined(RWWSRE)
|
||||
// Reenable read access to flash
|
||||
boot_rww_enable();
|
||||
#endif
|
||||
|
||||
}
|
||||
/* Read memory block mode, length is big endian. */
|
||||
else if(ch == STK_READ_PAGE) {
|
||||
// READ PAGE - we only read flash
|
||||
getLen();
|
||||
verifySpace();
|
||||
#ifdef VIRTUAL_BOOT_PARTITION
|
||||
do {
|
||||
// Undo vector patch in bottom page so verify passes
|
||||
if (address == 0) ch=rstVect & 0xff;
|
||||
else if (address == 1) ch=rstVect >> 8;
|
||||
else if (address == 10) ch=wdtVect & 0xff;
|
||||
else if (address == 11) ch=wdtVect >> 8;
|
||||
else ch = pgm_read_byte_near(address);
|
||||
address++;
|
||||
putch(ch);
|
||||
} while (--length);
|
||||
#else
|
||||
do putch(pgm_read_byte_near(address++));
|
||||
while (--length);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Get device signature bytes */
|
||||
else if(ch == STK_READ_SIGN) {
|
||||
// READ SIGN - return what Avrdude wants to hear
|
||||
verifySpace();
|
||||
putch(SIGNATURE_0);
|
||||
putch(SIGNATURE_1);
|
||||
putch(SIGNATURE_2);
|
||||
}
|
||||
else if (ch == 'Q') {
|
||||
// Adaboot no-wait mod
|
||||
watchdogConfig(WATCHDOG_16MS);
|
||||
verifySpace();
|
||||
}
|
||||
else {
|
||||
// This covers the response to commands like STK_ENTER_PROGMODE
|
||||
verifySpace();
|
||||
}
|
||||
putch(STK_OK);
|
||||
}
|
||||
}
|
||||
|
||||
void putch(char ch) {
|
||||
#ifndef SOFT_UART
|
||||
while (!(UCSR0A & _BV(UDRE0)));
|
||||
UDR0 = ch;
|
||||
#else
|
||||
__asm__ __volatile__ (
|
||||
" com %[ch]\n" // ones complement, carry set
|
||||
" sec\n"
|
||||
"1: brcc 2f\n"
|
||||
" cbi %[uartPort],%[uartBit]\n"
|
||||
" rjmp 3f\n"
|
||||
"2: sbi %[uartPort],%[uartBit]\n"
|
||||
" nop\n"
|
||||
"3: rcall uartDelay\n"
|
||||
" rcall uartDelay\n"
|
||||
" lsr %[ch]\n"
|
||||
" dec %[bitcnt]\n"
|
||||
" brne 1b\n"
|
||||
:
|
||||
:
|
||||
[bitcnt] "d" (10),
|
||||
[ch] "r" (ch),
|
||||
[uartPort] "I" (_SFR_IO_ADDR(UART_PORT)),
|
||||
[uartBit] "I" (UART_TX_BIT)
|
||||
:
|
||||
"r25"
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t getch(void) {
|
||||
uint8_t ch;
|
||||
|
||||
watchdogReset();
|
||||
|
||||
#ifdef LED_DATA_FLASH
|
||||
LED_PIN |= _BV(LED);
|
||||
#endif
|
||||
|
||||
#ifdef SOFT_UART
|
||||
__asm__ __volatile__ (
|
||||
"1: sbic %[uartPin],%[uartBit]\n" // Wait for start edge
|
||||
" rjmp 1b\n"
|
||||
" rcall uartDelay\n" // Get to middle of start bit
|
||||
"2: rcall uartDelay\n" // Wait 1 bit period
|
||||
" rcall uartDelay\n" // Wait 1 bit period
|
||||
" clc\n"
|
||||
" sbic %[uartPin],%[uartBit]\n"
|
||||
" sec\n"
|
||||
" dec %[bitCnt]\n"
|
||||
" breq 3f\n"
|
||||
" ror %[ch]\n"
|
||||
" rjmp 2b\n"
|
||||
"3:\n"
|
||||
:
|
||||
[ch] "=r" (ch)
|
||||
:
|
||||
[bitCnt] "d" (9),
|
||||
[uartPin] "I" (_SFR_IO_ADDR(UART_PIN)),
|
||||
[uartBit] "I" (UART_RX_BIT)
|
||||
:
|
||||
"r25"
|
||||
);
|
||||
#else
|
||||
while(!(UCSR0A & _BV(RXC0)));
|
||||
ch = UDR0;
|
||||
#endif
|
||||
|
||||
#ifdef LED_DATA_FLASH
|
||||
LED_PIN |= _BV(LED);
|
||||
#endif
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
#ifdef SOFT_UART
|
||||
//#define UART_B_VALUE (((F_CPU/BAUD_RATE)-23)/6)
|
||||
#define UART_B_VALUE (((F_CPU/BAUD_RATE)-20)/6)
|
||||
#if UART_B_VALUE > 255
|
||||
#error Baud rate too slow for soft UART
|
||||
#endif
|
||||
|
||||
void uartDelay() {
|
||||
__asm__ __volatile__ (
|
||||
"ldi r25,%[count]\n"
|
||||
"1:dec r25\n"
|
||||
"brne 1b\n"
|
||||
"ret\n"
|
||||
::[count] "M" (UART_B_VALUE)
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
void getNch(uint8_t count) {
|
||||
do getch(); while (--count);
|
||||
verifySpace();
|
||||
}
|
||||
|
||||
void verifySpace() {
|
||||
if (getch() != CRC_EOP) appStart();
|
||||
putch(STK_INSYNC);
|
||||
}
|
||||
|
||||
#if LED_START_FLASHES > 0
|
||||
void flash_led(uint8_t count) {
|
||||
do {
|
||||
TCNT1 = -(F_CPU/(1024*16));
|
||||
TIFR1 = _BV(TOV1);
|
||||
while(!(TIFR1 & _BV(TOV1)));
|
||||
LED_PIN |= _BV(LED);
|
||||
watchdogReset();
|
||||
} while (--count);
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t getLen() {
|
||||
getch();
|
||||
length = getch();
|
||||
return getch();
|
||||
}
|
||||
|
||||
// Watchdog functions. These are only safe with interrupts turned off.
|
||||
void watchdogReset() {
|
||||
__asm__ __volatile__ (
|
||||
"wdr\n"
|
||||
);
|
||||
}
|
||||
|
||||
void watchdogConfig(uint8_t x) {
|
||||
WDTCSR = _BV(WDCE) | _BV(WDE);
|
||||
WDTCSR = x;
|
||||
}
|
||||
|
||||
void appStart() {
|
||||
watchdogConfig(WATCHDOG_OFF);
|
||||
__asm__ __volatile__ (
|
||||
#ifdef VIRTUAL_BOOT_PARTITION
|
||||
// Jump to WDT vector
|
||||
"ldi r30,5\n"
|
||||
"clr r31\n"
|
||||
#else
|
||||
// Jump to RST vector
|
||||
"clr r30\n"
|
||||
"clr r31\n"
|
||||
#endif
|
||||
"ijmp\n"
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user