add reset line to snes
This commit is contained in:
parent
68d4ffc7f1
commit
8670300642
@ -1,24 +1,11 @@
|
|||||||
/* simple USBasp compatible bootloader
|
/*
|
||||||
* by Alexander Neumann <alexander@lochraster.org>
|
* simple USBasp compatible bootloader by Alexander Neumann <alexander@lochraster.org> inspired by USBasploader by Christian Starkjohann,
|
||||||
*
|
* see http://www.obdev.at/products/avrusb/usbasploader.html This program is free software; you can redistribute it and/or modify it under
|
||||||
* inspired by USBasploader by Christian Starkjohann,
|
* the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the
|
||||||
* see http://www.obdev.at/products/avrusb/usbasploader.html
|
* 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
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. For more information on
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
* the GPL, please go to: http://www.gnu.org/copyleft/gpl.html
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
||||||
*
|
|
||||||
* For more information on the GPL, please go to:
|
|
||||||
* http://www.gnu.org/copyleft/gpl.html
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <avr/io.h>
|
#include <avr/io.h>
|
||||||
@ -33,7 +20,9 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "usbdrv/usbdrv.c"
|
#include "usbdrv/usbdrv.c"
|
||||||
|
|
||||||
/* USBasp requests, taken from the original USBasp sourcecode */
|
/*
|
||||||
|
* USBasp requests, taken from the original USBasp sourcecode
|
||||||
|
*/
|
||||||
#define USBASP_FUNC_CONNECT 1
|
#define USBASP_FUNC_CONNECT 1
|
||||||
#define USBASP_FUNC_DISCONNECT 2
|
#define USBASP_FUNC_DISCONNECT 2
|
||||||
#define USBASP_FUNC_TRANSMIT 3
|
#define USBASP_FUNC_TRANSMIT 3
|
||||||
@ -44,10 +33,14 @@
|
|||||||
#define USBASP_FUNC_WRITEEEPROM 8
|
#define USBASP_FUNC_WRITEEEPROM 8
|
||||||
#define USBASP_FUNC_SETLONGADDRESS 9
|
#define USBASP_FUNC_SETLONGADDRESS 9
|
||||||
|
|
||||||
/* additional functions */
|
/*
|
||||||
|
* additional functions
|
||||||
|
*/
|
||||||
#define FUNC_ECHO 0x17
|
#define FUNC_ECHO 0x17
|
||||||
|
|
||||||
/* atmel isp commands */
|
/*
|
||||||
|
* atmel isp commands
|
||||||
|
*/
|
||||||
#define ISP_CHIP_ERASE1 0xAC
|
#define ISP_CHIP_ERASE1 0xAC
|
||||||
#define ISP_CHIP_ERASE2 0x80
|
#define ISP_CHIP_ERASE2 0x80
|
||||||
#define ISP_READ_SIGNATURE 0x30
|
#define ISP_READ_SIGNATURE 0x30
|
||||||
@ -70,7 +63,9 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* some predefined signatures, taken from the original USBasp sourcecode */
|
/*
|
||||||
|
* some predefined signatures, taken from the original USBasp sourcecode
|
||||||
|
*/
|
||||||
static const uint8_t signature[4] = {
|
static const uint8_t signature[4] = {
|
||||||
#ifdef SIGNATURE_BYTES
|
#ifdef SIGNATURE_BYTES
|
||||||
SIGNATURE_BYTES
|
SIGNATURE_BYTES
|
||||||
@ -96,41 +91,45 @@ static const uint8_t signature[4] = {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined (__AVR_ATmega644__)
|
#if defined (__AVR_ATmega644__)
|
||||||
/* Due arvdude limitations we can't erase the whole progmem
|
/*
|
||||||
without running into an usb timeount on cleint side. So we
|
* Due arvdude limitations we can't erase the whole progmem without running into an usb timeount on cleint side. So we we limit the
|
||||||
we limit the erase section by 0x1000
|
* erase section by 0x1000
|
||||||
*/
|
*/
|
||||||
#define ERASE_SECTION 0xe000
|
#define ERASE_SECTION 0xe000
|
||||||
#else
|
#else
|
||||||
#define ERASE_SECTION BOOT_SECTION_START
|
#define ERASE_SECTION BOOT_SECTION_START
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifdef DEBUG_UART
|
#ifdef DEBUG_UART
|
||||||
static __attribute__ (( __noinline__ )) void uart_putc(uint8_t data) {
|
static __attribute__ ((__noinline__))
|
||||||
while(!(UCSR0A & _BV(UDRE0)));
|
void uart_putc(uint8_t data)
|
||||||
|
{
|
||||||
|
while (!(UCSR0A & _BV(UDRE0)));
|
||||||
UDR0 = data;
|
UDR0 = data;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#define uart_putc(x)
|
#define uart_putc(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DEBUG_UART
|
#ifdef DEBUG_UART
|
||||||
static __attribute__ (( __noinline__ )) void uart_puts(uint8_t *data) {
|
static __attribute__ ((__noinline__))
|
||||||
while(*data){
|
void uart_puts(uint8_t * data)
|
||||||
|
{
|
||||||
|
while (*data) {
|
||||||
uart_putc(*data);
|
uart_putc(*data);
|
||||||
data++;
|
data++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#define uart_puts(x)
|
#define uart_puts(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* supply custom usbDeviceConnect() and usbDeviceDisconnect() macros
|
/*
|
||||||
* which turn the interrupt on and off at the right times,
|
* supply custom usbDeviceConnect() and usbDeviceDisconnect() macros which turn the interrupt on and off at the right times, and prevent
|
||||||
* and prevent the execution of an interrupt while the pullup resistor
|
* the execution of an interrupt while the pullup resistor is switched off
|
||||||
* is switched off */
|
*/
|
||||||
|
|
||||||
#ifdef USB_CFG_PULLUP_IOPORTNAME
|
#ifdef USB_CFG_PULLUP_IOPORTNAME
|
||||||
#undef usbDeviceConnect
|
#undef usbDeviceConnect
|
||||||
@ -147,24 +146,30 @@ static __attribute__ (( __noinline__ )) void uart_puts(uint8_t *data) {
|
|||||||
} while(0);
|
} while(0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* prototypes */
|
/*
|
||||||
void __attribute__ (( __noreturn__, __noinline__, __naked__ )) leave_bootloader(void);
|
* prototypes
|
||||||
|
*/
|
||||||
|
void __attribute__ ((__noreturn__, __noinline__,
|
||||||
|
__naked__)) leave_bootloader(void);
|
||||||
|
|
||||||
/* we just support flash sizes <= 64kb, for code size reasons
|
/*
|
||||||
* if you need to program bigger devices, have a look at USBasploader:
|
* we just support flash sizes <= 64kb, for code size reasons if you need to program bigger devices, have a look at USBasploader:
|
||||||
* http://www.obdev.at/products/avrusb/usbasploader.html */
|
* http://www.obdev.at/products/avrusb/usbasploader.html
|
||||||
|
*/
|
||||||
#if FLASHEND > 0xffff
|
#if FLASHEND > 0xffff
|
||||||
# error "usbload only supports up to 64kb of flash!"
|
# error "usbload only supports up to 64kb of flash!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* we are just checking the lower byte of flash_address,
|
/*
|
||||||
* so make sure SPM_PAGESIZE is <= 256
|
* we are just checking the lower byte of flash_address, so make sure SPM_PAGESIZE is <= 256
|
||||||
*/
|
*/
|
||||||
#if SPM_PAGESIZE > 256
|
#if SPM_PAGESIZE > 256
|
||||||
# error "SPM_PAGESIZE is too big (just checking lower byte)"
|
# error "SPM_PAGESIZE is too big (just checking lower byte)"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* start flash (byte address) read/write at this address */
|
/*
|
||||||
|
* start flash (byte address) read/write at this address
|
||||||
|
*/
|
||||||
usbWord_t flash_address;
|
usbWord_t flash_address;
|
||||||
uint8_t bytes_remaining;
|
uint8_t bytes_remaining;
|
||||||
uint8_t request;
|
uint8_t request;
|
||||||
@ -176,66 +181,93 @@ uint8_t timeout;
|
|||||||
|
|
||||||
usbMsgLen_t usbFunctionSetup(uchar data[8])
|
usbMsgLen_t usbFunctionSetup(uchar data[8])
|
||||||
{
|
{
|
||||||
usbRequest_t *req = (void *)data;
|
usbRequest_t *req = (void *) data;
|
||||||
uint8_t len = 0;
|
uint8_t len = 0;
|
||||||
static uint8_t buf[4];
|
static uint8_t buf[4];
|
||||||
|
|
||||||
/* set global data pointer to local buffer */
|
/*
|
||||||
|
* set global data pointer to local buffer
|
||||||
|
*/
|
||||||
usbMsgPtr = buf;
|
usbMsgPtr = buf;
|
||||||
|
|
||||||
/* on enableprog just return one zero, which means success */
|
/*
|
||||||
|
* on enableprog just return one zero, which means success
|
||||||
|
*/
|
||||||
if (req->bRequest == USBASP_FUNC_ENABLEPROG) {
|
if (req->bRequest == USBASP_FUNC_ENABLEPROG) {
|
||||||
buf[0] = 0;
|
buf[0] = 0;
|
||||||
len = 1;
|
len = 1;
|
||||||
timeout = 255;
|
timeout = 255;
|
||||||
} else if (req->bRequest == USBASP_FUNC_CONNECT) {
|
} else if (req->bRequest == USBASP_FUNC_CONNECT) {
|
||||||
/* turn on led */
|
/*
|
||||||
|
* turn on led
|
||||||
|
*/
|
||||||
DLED_ON;
|
DLED_ON;
|
||||||
} else if (req->bRequest == USBASP_FUNC_DISCONNECT) {
|
} else if (req->bRequest == USBASP_FUNC_DISCONNECT) {
|
||||||
/* turn off led */
|
/*
|
||||||
|
* turn off led
|
||||||
|
*/
|
||||||
DLED_OFF;
|
DLED_OFF;
|
||||||
request_exit = 1;
|
request_exit = 1;
|
||||||
/* catch query for the devicecode, chip erase and eeprom byte requests */
|
/*
|
||||||
|
* catch query for the devicecode, chip erase and eeprom byte requests
|
||||||
|
*/
|
||||||
} else if (req->bRequest == USBASP_FUNC_TRANSMIT) {
|
} else if (req->bRequest == USBASP_FUNC_TRANSMIT) {
|
||||||
|
|
||||||
/* reset buffer with zeroes */
|
/*
|
||||||
|
* reset buffer with zeroes
|
||||||
|
*/
|
||||||
memset(buf, '\0', sizeof(buf));
|
memset(buf, '\0', sizeof(buf));
|
||||||
|
|
||||||
/* read the address for eeprom operations */
|
/*
|
||||||
|
* read the address for eeprom operations
|
||||||
|
*/
|
||||||
usbWord_t address;
|
usbWord_t address;
|
||||||
address.bytes[0] = data[4]; /* low byte is data[4] */
|
address.bytes[0] = data[4]; /* low byte is data[4] */
|
||||||
address.bytes[1] = data[3]; /* high byte is data[3] */
|
address.bytes[1] = data[3]; /* high byte is data[3] */
|
||||||
|
|
||||||
/* if this is a request to read the device signature, answer with the
|
/*
|
||||||
* appropiate signature byte */
|
* if this is a request to read the device signature, answer with the appropiate signature byte
|
||||||
|
*/
|
||||||
if (data[2] == ISP_READ_SIGNATURE) {
|
if (data[2] == ISP_READ_SIGNATURE) {
|
||||||
/* the complete isp data is reported back to avrdude, but we just need byte 4
|
/*
|
||||||
* bits 0 and 1 of byte 3 determine the signature byte address */
|
* the complete isp data is reported back to avrdude, but we just need byte 4 bits 0 and 1 of byte 3 determine the signature
|
||||||
|
* byte address
|
||||||
|
*/
|
||||||
buf[3] = signature[data[4] & 0x03];
|
buf[3] = signature[data[4] & 0x03];
|
||||||
|
|
||||||
#ifdef ENABLE_CATCH_EEPROM_ISP
|
#ifdef ENABLE_CATCH_EEPROM_ISP
|
||||||
/* catch eeprom read */
|
/*
|
||||||
|
* catch eeprom read
|
||||||
|
*/
|
||||||
} else if (data[2] == ISP_READ_EEPROM) {
|
} else if (data[2] == ISP_READ_EEPROM) {
|
||||||
|
|
||||||
buf[3] = eeprom_read_byte((uint8_t *)address.word);
|
buf[3] = eeprom_read_byte((uint8_t *) address.word);
|
||||||
|
|
||||||
/* catch eeprom write */
|
/*
|
||||||
|
* catch eeprom write
|
||||||
|
*/
|
||||||
} else if (data[2] == ISP_WRITE_EEPROM) {
|
} else if (data[2] == ISP_WRITE_EEPROM) {
|
||||||
|
|
||||||
/* address is in data[4], data[3], and databyte is in data[5] */
|
/*
|
||||||
eeprom_write_byte((uint8_t *)address.word, data[5]);
|
* address is in data[4], data[3], and databyte is in data[5]
|
||||||
|
*/
|
||||||
|
eeprom_write_byte((uint8_t *) address.word, data[5]);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* catch a chip erase */
|
/*
|
||||||
|
* catch a chip erase
|
||||||
|
*/
|
||||||
} else if (data[2] == ISP_CHIP_ERASE1 && data[3] == ISP_CHIP_ERASE2) {
|
} else if (data[2] == ISP_CHIP_ERASE1 && data[3] == ISP_CHIP_ERASE2) {
|
||||||
uart_puts("\n\rErase Flash");
|
uart_puts("\n\rErase Flash");
|
||||||
for (flash_address.word = 0;
|
for (flash_address.word = 0;
|
||||||
flash_address.word < ERASE_SECTION;
|
flash_address.word < ERASE_SECTION;
|
||||||
flash_address.word += SPM_PAGESIZE) {
|
flash_address.word += SPM_PAGESIZE) {
|
||||||
|
|
||||||
/* wait and erase page */
|
/*
|
||||||
|
* wait and erase page
|
||||||
|
*/
|
||||||
boot_spm_busy_wait();
|
boot_spm_busy_wait();
|
||||||
if (flash_address.word && flash_address.word%1024 == 0 )
|
if (flash_address.word && flash_address.word % 1024 == 0)
|
||||||
uart_putc('.');
|
uart_putc('.');
|
||||||
cli();
|
cli();
|
||||||
boot_page_erase(flash_address.word);
|
boot_page_erase(flash_address.word);
|
||||||
@ -244,44 +276,55 @@ usbMsgLen_t usbFunctionSetup(uchar data[8])
|
|||||||
uart_puts("\n\r");
|
uart_puts("\n\r");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* in case no data has been filled in by the if's above, just return zeroes */
|
/*
|
||||||
|
* in case no data has been filled in by the if's above, just return zeroes
|
||||||
|
*/
|
||||||
len = 4;
|
len = 4;
|
||||||
|
|
||||||
#ifdef ENABLE_ECHO_FUNC
|
#ifdef ENABLE_ECHO_FUNC
|
||||||
/* implement a simple echo function, for testing the usb connectivity */
|
/*
|
||||||
|
* implement a simple echo function, for testing the usb connectivity
|
||||||
|
*/
|
||||||
} else if (req->bRequest == FUNC_ECHO) {
|
} else if (req->bRequest == FUNC_ECHO) {
|
||||||
buf[0] = req->wValue.bytes[0];
|
buf[0] = req->wValue.bytes[0];
|
||||||
buf[1] = req->wValue.bytes[1];
|
buf[1] = req->wValue.bytes[1];
|
||||||
len = 2;
|
len = 2;
|
||||||
#endif
|
#endif
|
||||||
} else if (req->bRequest >= USBASP_FUNC_READFLASH) {
|
} else if (req->bRequest >= USBASP_FUNC_READFLASH) {
|
||||||
/* && req->bRequest <= USBASP_FUNC_SETLONGADDRESS */
|
/*
|
||||||
/* extract address and length */
|
* && req->bRequest <= USBASP_FUNC_SETLONGADDRESS
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* extract address and length
|
||||||
|
*/
|
||||||
flash_address.word = req->wValue.word;
|
flash_address.word = req->wValue.word;
|
||||||
bytes_remaining = req->wLength.bytes[0];
|
bytes_remaining = req->wLength.bytes[0];
|
||||||
request = req->bRequest;
|
request = req->bRequest;
|
||||||
/* hand control over to usbFunctionRead()/usbFunctionWrite() */
|
/*
|
||||||
|
* hand control over to usbFunctionRead()/usbFunctionWrite()
|
||||||
|
*/
|
||||||
len = 0xff;
|
len = 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
uchar usbFunctionWrite(uchar *data, uchar len)
|
uchar usbFunctionWrite(uchar * data, uchar len)
|
||||||
{
|
{
|
||||||
if (len > bytes_remaining)
|
if (len > bytes_remaining)
|
||||||
len = bytes_remaining;
|
len = bytes_remaining;
|
||||||
bytes_remaining -= len;
|
bytes_remaining -= len;
|
||||||
if (request == USBASP_FUNC_WRITEEEPROM) {
|
if (request == USBASP_FUNC_WRITEEEPROM) {
|
||||||
for (uint8_t i = 0; i < len; i++)
|
for (uint8_t i = 0; i < len; i++)
|
||||||
eeprom_write_byte((uint8_t *)flash_address.word++, *data++);
|
eeprom_write_byte((uint8_t *) flash_address.word++, *data++);
|
||||||
}
|
} else {
|
||||||
else {
|
/*
|
||||||
/* data is handled wordwise, adjust len */
|
* data is handled wordwise, adjust len
|
||||||
|
*/
|
||||||
len /= 2;
|
len /= 2;
|
||||||
len -= 1;
|
len -= 1;
|
||||||
for (uint8_t i = 0; i <= len; i++) {
|
for (uint8_t i = 0; i <= len; i++) {
|
||||||
uint16_t *w = (uint16_t *)data;
|
uint16_t *w = (uint16_t *) data;
|
||||||
cli();
|
cli();
|
||||||
boot_page_fill(flash_address.word, *w);
|
boot_page_fill(flash_address.word, *w);
|
||||||
sei();
|
sei();
|
||||||
@ -291,9 +334,11 @@ uchar usbFunctionWrite(uchar *data, uchar len)
|
|||||||
next_address.word += 2;
|
next_address.word += 2;
|
||||||
data += 2;
|
data += 2;
|
||||||
|
|
||||||
/* write page if page boundary is crossed or this is the last page */
|
/*
|
||||||
if ( next_address.bytes[0] % SPM_PAGESIZE == 0 ||
|
* write page if page boundary is crossed or this is the last page
|
||||||
(bytes_remaining == 0 && i == len) ) {
|
*/
|
||||||
|
if (next_address.bytes[0] % SPM_PAGESIZE == 0 ||
|
||||||
|
(bytes_remaining == 0 && i == len)) {
|
||||||
cli();
|
cli();
|
||||||
boot_page_write(flash_address.word);
|
boot_page_write(flash_address.word);
|
||||||
sei();
|
sei();
|
||||||
@ -307,123 +352,157 @@ uchar usbFunctionWrite(uchar *data, uchar len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* flash led on activity */
|
/*
|
||||||
|
* flash led on activity
|
||||||
|
*/
|
||||||
DLED_TGL;
|
DLED_TGL;
|
||||||
|
|
||||||
return (bytes_remaining == 0);
|
return (bytes_remaining == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
uchar usbFunctionRead(uchar *data, uchar len)
|
uchar usbFunctionRead(uchar * data, uchar len)
|
||||||
{
|
{
|
||||||
if(len > bytes_remaining)
|
if (len > bytes_remaining)
|
||||||
len = bytes_remaining;
|
len = bytes_remaining;
|
||||||
bytes_remaining -= len;
|
bytes_remaining -= len;
|
||||||
|
|
||||||
for (uint8_t i = 0; i < len; i++) {
|
for (uint8_t i = 0; i < len; i++) {
|
||||||
if(request == USBASP_FUNC_READEEPROM)
|
if (request == USBASP_FUNC_READEEPROM)
|
||||||
*data = eeprom_read_byte((void *)flash_address.word);
|
*data = eeprom_read_byte((void *) flash_address.word);
|
||||||
else
|
else
|
||||||
*data = pgm_read_byte_near((void *)flash_address.word);
|
*data = pgm_read_byte_near((void *) flash_address.word);
|
||||||
data++;
|
data++;
|
||||||
flash_address.word++;
|
flash_address.word++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* flash led on activity */
|
/*
|
||||||
|
* flash led on activity
|
||||||
|
*/
|
||||||
DLED_TGL;
|
DLED_TGL;
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
void (*jump_to_app)(void) = 0x0000;
|
void (*jump_to_app) (void) = 0x0000;
|
||||||
void leave_bootloader(void)
|
void leave_bootloader(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
cli();
|
cli();
|
||||||
|
|
||||||
/* disconnect usb */
|
/*
|
||||||
|
* disconnect usb
|
||||||
|
*/
|
||||||
usbDeviceDisconnect();
|
usbDeviceDisconnect();
|
||||||
for (uint8_t i = 0; i < 50; i++)
|
for (uint8_t i = 0; i < 50; i++)
|
||||||
_delay_ms(10); /* 0 means 0x10000, 38*1/f*0x10000 =~ 498ms */
|
_delay_ms(10); /* 0 means 0x10000, 38*1/f*0x10000 =~ 498ms */
|
||||||
|
|
||||||
/* enable watchdog to soft-reset the uC for clean startup of new application */
|
/*
|
||||||
|
* enable watchdog to soft-reset the uC for clean startup of new application
|
||||||
|
*/
|
||||||
wdt_enable(WDTO_15MS);
|
wdt_enable(WDTO_15MS);
|
||||||
|
|
||||||
/* let watchdog kick in and reset uC */
|
/*
|
||||||
while(1);
|
* let watchdog kick in and reset uC
|
||||||
|
*/
|
||||||
|
while (1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int __attribute__ ((noreturn,OS_main)) main(void)
|
int __attribute__ ((noreturn, OS_main)) main(void)
|
||||||
{
|
{
|
||||||
/* start bootloader */
|
/*
|
||||||
|
* start bootloader
|
||||||
|
*/
|
||||||
|
|
||||||
#ifdef DEBUG_UART
|
#ifdef DEBUG_UART
|
||||||
/* init uart (115200 baud, at 20mhz) */
|
/*
|
||||||
|
* init uart (115200 baud, at 20mhz)
|
||||||
|
*/
|
||||||
UBRR0L = 10;
|
UBRR0L = 10;
|
||||||
UCSR0C = _BV(UCSZ00) | _BV(UCSZ01);
|
UCSR0C = _BV(UCSZ00) | _BV(UCSZ01);
|
||||||
UCSR0B = _BV(TXEN0);
|
UCSR0B = _BV(TXEN0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint8_t reset = MCUSR;
|
uint8_t reset = MCUSR;
|
||||||
uint16_t delay =0;
|
uint16_t delay = 0;
|
||||||
timeout = TIMEOUT;
|
timeout = TIMEOUT;
|
||||||
|
|
||||||
uart_puts("Snesram Bootloader v0.1\n\r");
|
uart_puts("Snesram Bootloader v0.1\n\r");
|
||||||
|
|
||||||
/* if power-on reset, quit bootloader via watchdog reset */
|
/*
|
||||||
if (reset & _BV(PORF)){
|
* if power-on reset, quit bootloader via watchdog reset
|
||||||
|
*/
|
||||||
|
if (reset & _BV(PORF)) {
|
||||||
uart_puts("Found power on reset\n\r");
|
uart_puts("Found power on reset\n\r");
|
||||||
MCUSR = 0;
|
MCUSR = 0;
|
||||||
leave_bootloader();
|
leave_bootloader();
|
||||||
}
|
}
|
||||||
/* if watchdog reset, disable watchdog and jump to app */
|
/*
|
||||||
else if(reset & _BV(WDRF)){
|
* if watchdog reset, disable watchdog and jump to app
|
||||||
|
*/
|
||||||
|
else if (reset & _BV(WDRF)) {
|
||||||
uart_puts("Found watchdog reset\n\r");
|
uart_puts("Found watchdog reset\n\r");
|
||||||
MCUSR = 0;
|
MCUSR = 0;
|
||||||
wdt_disable();
|
wdt_disable();
|
||||||
DLED_TGL;
|
DLED_TGL;
|
||||||
_delay_ms(500);
|
_delay_ms(500);
|
||||||
DLED_TGL;
|
DLED_TGL;
|
||||||
_delay_ms(500);
|
_delay_ms(500);
|
||||||
uart_puts("Jump to main\n\r");
|
uart_puts("Jump to main\n\r");
|
||||||
jump_to_app();
|
jump_to_app();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uart_puts("Enter programming mode\n\r");
|
uart_puts("Enter programming mode\n\r");
|
||||||
/* else: enter programming mode */
|
/*
|
||||||
|
* else: enter programming mode
|
||||||
|
*/
|
||||||
|
|
||||||
/* clear external reset flags */
|
/*
|
||||||
|
* clear external reset flags
|
||||||
|
*/
|
||||||
MCUSR = 0;
|
MCUSR = 0;
|
||||||
|
|
||||||
/* init exit request state */
|
/*
|
||||||
|
* init exit request state
|
||||||
|
*/
|
||||||
request_exit = 0;
|
request_exit = 0;
|
||||||
|
|
||||||
/* move interrupts to boot section */
|
/*
|
||||||
|
* move interrupts to boot section
|
||||||
|
*/
|
||||||
|
|
||||||
MCUCR = (1 << IVCE);
|
MCUCR = (1 << IVCE);
|
||||||
MCUCR = (1 << IVSEL);
|
MCUCR = (1 << IVSEL);
|
||||||
|
|
||||||
/* enable interrupts */
|
/*
|
||||||
|
* enable interrupts
|
||||||
|
*/
|
||||||
sei();
|
sei();
|
||||||
|
|
||||||
/* initialize usb pins */
|
/*
|
||||||
|
* initialize usb pins
|
||||||
|
*/
|
||||||
usbInit();
|
usbInit();
|
||||||
|
|
||||||
|
|
||||||
/* disconnect for ~500ms, so that the host re-enumerates this device */
|
/*
|
||||||
|
* disconnect for ~500ms, so that the host re-enumerates this device
|
||||||
|
*/
|
||||||
usbDeviceDisconnect();
|
usbDeviceDisconnect();
|
||||||
for (uint8_t i = 0; i < 50; i++)
|
for (uint8_t i = 0; i < 50; i++)
|
||||||
_delay_ms(10); /* 0 means 0x10000, 38*1/f*0x10000 =~ 498ms */
|
_delay_ms(10); /* 0 means 0x10000, 38*1/f*0x10000 =~ 498ms */
|
||||||
usbDeviceConnect();
|
usbDeviceConnect();
|
||||||
uart_puts("Wait for firmware");
|
uart_puts("Wait for firmware");
|
||||||
while(1) {
|
while (1) {
|
||||||
usbPoll();
|
usbPoll();
|
||||||
|
|
||||||
delay++;
|
delay++;
|
||||||
|
|
||||||
/* do some led blinking, so that it is visible that the bootloader is still running */
|
/*
|
||||||
|
* do some led blinking, so that it is visible that the bootloader is still running
|
||||||
|
*/
|
||||||
if (delay == 0) {
|
if (delay == 0) {
|
||||||
uart_putc('.');
|
uart_putc('.');
|
||||||
DLED_TGL;
|
DLED_TGL;
|
||||||
@ -438,5 +517,5 @@ int __attribute__ ((noreturn,OS_main)) main(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -407,6 +407,9 @@ int main(void)
|
|||||||
crc_check_bulk_memory(0x000000, req_addr_end, req_bank_size);
|
crc_check_bulk_memory(0x000000, req_addr_end, req_bank_size);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
snes_reset_hi();
|
||||||
|
snes_reset_off();
|
||||||
|
|
||||||
snes_irq_lo();
|
snes_irq_lo();
|
||||||
snes_irq_off();
|
snes_irq_off();
|
||||||
|
|
||||||
@ -424,6 +427,15 @@ int main(void)
|
|||||||
snes_bus_active();
|
snes_bus_active();
|
||||||
printf("Activate Snes bus\n");
|
printf("Activate Snes bus\n");
|
||||||
|
|
||||||
|
_delay_ms(100);
|
||||||
|
printf("Reset Snes\n");
|
||||||
|
snes_reset_on();
|
||||||
|
snes_reset_lo();
|
||||||
|
_delay_ms(2);
|
||||||
|
snes_reset_hi();
|
||||||
|
snes_reset_off();
|
||||||
|
|
||||||
|
printf("Poll\n");
|
||||||
while (req_state != REQ_STATUS_AVR){
|
while (req_state != REQ_STATUS_AVR){
|
||||||
usbPoll();
|
usbPoll();
|
||||||
#if 0
|
#if 0
|
||||||
|
|||||||
@ -84,6 +84,16 @@
|
|||||||
#define snes_irq_off() (SNES_IRQ_DIR &= ~(1 << SNES_IRQ_PIN))
|
#define snes_irq_off() (SNES_IRQ_DIR &= ~(1 << SNES_IRQ_PIN))
|
||||||
#define snes_irq_lo() (SNES_IRQ_PORT &= ~(1 << SNES_IRQ_PIN))
|
#define snes_irq_lo() (SNES_IRQ_PORT &= ~(1 << SNES_IRQ_PIN))
|
||||||
|
|
||||||
|
#define SNES_RESET_PORT PORTB
|
||||||
|
#define SNES_RESET_DIR DDRB
|
||||||
|
#define SNES_RESET_PIN PB4
|
||||||
|
|
||||||
|
|
||||||
|
#define snes_reset_on() (SNES_RESET_DIR |= (1 << SNES_RESET_PIN))
|
||||||
|
#define snes_reset_hi() (SNES_RESET_PORT |= (1 << SNES_RESET_PIN))
|
||||||
|
|
||||||
|
#define snes_reset_off() (SNES_RESET_DIR &= ~(1 << SNES_RESET_PIN))
|
||||||
|
#define snes_reset_lo() (SNES_RESET_PORT &= ~(1 << SNES_RESET_PIN))
|
||||||
|
|
||||||
|
|
||||||
/* ---------------------------- PORT C ---------------------------- */
|
/* ---------------------------- PORT C ---------------------------- */
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user