add reset line to snes

This commit is contained in:
David Voswinkel 2009-07-21 22:57:21 +02:00
parent 68d4ffc7f1
commit 8670300642
3 changed files with 230 additions and 129 deletions

View File

@ -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)
} }
} }
} }

View File

@ -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

View File

@ -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 ---------------------------- */