/*
Author: Vinod S
http://blog.vinu.co.in
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 3 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, see .
*/
#include
#define F_CPU 16000000
#include
#include "uart.h"
#include "i2c.h"
#include "boot.h"
#include
#include
#include "stk500.h"
#include "pin_defs.h"
/////////////////////// definitions /////////////////////////////////////////////////////
#define FUNC_READ 1
#define FUNC_WRITE 1
#define ER 0b10100001
#define EW 0b10100000
#define OPTIBOOT_MAJVER 6
#define OPTIBOOT_MINVER 2
#define LED_START_FLASHES 0
#define GETLENGTH(len) (void) getch() /* skip high byte */; len = getch()
#define save_vect_num (SPM_RDY_vect_num)
#define appstart_vec (save_vect_num*2)
#define WATCHDOG_1S (_BV(WDP2) | _BV(WDP1) | _BV(WDE))
#define WATCHDOG_OFF (0)
#define WATCHDOG_16MS (_BV(WDE))
////////////////////// global variables ////////////////////////////////////////////////
volatile uint16_t dd = 0;
typedef uint8_t pagelen_t;
uint8_t buff[200];
///////////////////// function prototypes //////////////////////////////////////////////
static inline void writebuffer(int8_t memtype, uint8_t * mybuff,
uint16_t address, pagelen_t len);
static inline void read_mem(uint8_t memtype, uint16_t address,
pagelen_t length);
void watchdogReset();
void verifySpace();
void watchdogConfig(uint8_t x);
void getNch(uint8_t count);
//////////////////// JUMP to main application function ////////////////////////////////
void app_start(void)
{
watchdogConfig(WATCHDOG_OFF);
__asm__ __volatile__("clr r30\n" "clr r31\n" "ijmp");
}
///////////////// main function ////////////////////////////////////////////////////////
int main()
{
uint8_t ch;
uint16_t address = 0;
pagelen_t length;
ch = MCUSR;
MCUSR = 0;
watchdogConfig(WATCHDOG_OFF);
if (ch & (_BV(WDRF) | _BV(BORF) | _BV(PORF)))
app_start();
PORTB &= ~(1 << PB5);
DDRB |= 1 << PB5;
//PIN 10 of arduino as ZERO
PORTC &= ~(1 << PC0); //A0
//enable pin10 as output
DDRC |= 1 << PC0; //A0
//PULL UP pin 11 of arduino
PORTC |= 1 << PC1; //A1
//enable pin11 as input.
DDRC &= ~(1 << PC1); //A1
_delay_ms(10);
//check if 10 and 11 is shorted while MCU is reset.
//LED ON
PORTB |= 1 << PB5;
if ((PINC & (1 << PC1)) == 0) { //A1
uint8_t buff2[128];
uint8_t buff1[128];
_delay_ms(1000);
PORTB &= ~(1 << PB5);
if ((PINC & (1 << PC1)) == 0) { //A1
app_start();
}
i2c_init();
watchdogConfig(WATCHDOG_OFF);
uint16_t addr = 0;
for (int i = 0; i < 224; i++) {
while (i2c_start(EW)) ;
i2c_write(addr >> 8);
i2c_write(addr);
i2c_start(ER);
//read one page from i2c eeprom
//read one page from internal flash
for (int j = 0; j < 128; j++) {
buff2[j] = i2c_read_ack();
buff1[j] = pgm_read_byte_near(addr + j);
}
i2c_stop();
i2c_start(EW);
i2c_write(addr >> 8);
i2c_write(addr);
//write the page read from internal flash to i2c eeprom. (Swap write)
for (int j = 0; j < 128; j++) {
i2c_write(buff1[j]);
}
i2c_stop();
//write the page read from external eeprom to internal flash.
writebuffer(0, buff2, addr, 128);
_delay_ms(2);
//increment page address. Here both flash and eeprom are of same page size.
addr += 128;
//toggle LED
PORTB ^= 1 << PB5;
}
// wait while dualboot enable pin is LOW
while ((PINC & (1 << PC1)) == 0) ; //PB3
//forcefull watchdog reset for app start.
watchdogConfig(WATCHDOG_16MS);
while (1) ;
}
uart_init();
watchdogConfig(WATCHDOG_1S);
watchdogReset();
for (;;) {
/* get character from UART */
ch = getch();
if (ch == STK_GET_PARAMETER) {
unsigned char which = getch();
verifySpace();
/*
* Send optiboot version as "SW version"
* Note that the references to memory are optimized away.
*/
if (which == STK_SW_MINOR) {
putch((256 * 6 + 2) & 0xFF);
} else if (which == STK_SW_MAJOR) {
putch((256 * 6 + 2) >> 8);
} else {
/*
* GET PARAMETER returns a generic 0x03 reply for
* other parameters - enough to keep Avrdude happy
*/
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
uint16_t newAddress;
newAddress = getch();
newAddress = (newAddress & 0xff) | (getch() << 8);
newAddress += newAddress; // Convert from word address to byte address
address = newAddress;
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 desttype;
uint8_t *bufPtr;
pagelen_t savelength;
GETLENGTH(length);
savelength = length;
desttype = getch();
// read a page worth of contents
bufPtr = buff;
do
*bufPtr++ = getch();
while (--length);
// Read command terminator, start reply
verifySpace();
writebuffer(desttype, buff, address, savelength);
}
/* Read memory block mode, length is big endian. */
else if (ch == STK_READ_PAGE) {
uint8_t desttype;
GETLENGTH(length);
desttype = getch();
verifySpace();
read_mem(desttype, address, length);
}
/* 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 == STK_LEAVE_PROGMODE) { /* 'Q' */
// Adaboot no-wait mod
watchdogConfig(WATCHDOG_1S);
verifySpace();
} else {
// This covers the response to commands like STK_ENTER_PROGMODE
verifySpace();
}
putch(STK_OK);
}
}
/*
* void writebuffer(memtype, buffer, address, length)
*/
static inline void writebuffer(int8_t memtype, uint8_t * mybuff,
uint16_t address, pagelen_t len)
{
// Copy buffer into programming buffer
uint8_t *bufPtr = mybuff;
uint16_t addrPtr = (uint16_t) (void *)address;
watchdogReset();
/*
* Start the page erase and wait for it to finish. There
* used to be code to do this while receiving the data over
* the serial link, but the performance improvement was slight,
* and we needed the space back.
*/
__boot_page_erase_short((uint16_t) (void *)address);
boot_spm_busy_wait();
/*
* Copy data from the buffer into the flash write buffer.
*/
do {
uint16_t a;
a = *bufPtr++;
a |= (*bufPtr++) << 8;
__boot_page_fill_short((uint16_t) (void *)addrPtr, a);
addrPtr += 2;
} while (len -= 2);
/*
* Actually Write the buffer to flash (and wait for it to finish.)
*/
__boot_page_write_short((uint16_t) (void *)address);
boot_spm_busy_wait();
__boot_rww_enable_alternate();
}
static inline void read_mem(uint8_t memtype, uint16_t address, pagelen_t length)
{
uint8_t cc;
//watchdogReset();
// read a Flash byte and increment the address
do {
__asm__("lpm %0,Z+\n": "=r"(cc), "=z"(address):"1"(address));
putch(cc);
} while (--length);
}
void verifySpace()
{
if (getch() != CRC_EOP) {
watchdogConfig(WATCHDOG_1S); // shorten WD timeout
while (1) // and busy-loop so that WD causes
; // a reset and app start.
}
putch(STK_INSYNC);
}
void getNch(uint8_t count)
{
do
getch();
while (--count);
verifySpace();
}
void watchdogConfig(uint8_t x)
{
WDTCSR = _BV(WDCE) | _BV(WDE);
WDTCSR = x;
}
// Watchdog functions. These are only safe with interrupts turned off.
void watchdogReset()
{
__asm__ __volatile__("wdr\n");
}