diff --git a/avr/bootloader/bootloader.c b/avr/bootloader/bootloader.c index a2ba389..76ac1c8 100644 --- a/avr/bootloader/bootloader.c +++ b/avr/bootloader/bootloader.c @@ -1,24 +1,11 @@ -/* simple USBasp compatible bootloader - * by Alexander Neumann - * - * 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 the terms of the GNU General Public License version 2 as - * 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 +/* + * simple USBasp compatible bootloader by Alexander Neumann 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 + * the terms of the GNU General Public License version 2 as 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 @@ -33,7 +20,9 @@ #include "config.h" #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_DISCONNECT 2 #define USBASP_FUNC_TRANSMIT 3 @@ -44,10 +33,14 @@ #define USBASP_FUNC_WRITEEEPROM 8 #define USBASP_FUNC_SETLONGADDRESS 9 -/* additional functions */ +/* + * additional functions + */ #define FUNC_ECHO 0x17 -/* atmel isp commands */ +/* + * atmel isp commands + */ #define ISP_CHIP_ERASE1 0xAC #define ISP_CHIP_ERASE2 0x80 #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] = { #ifdef SIGNATURE_BYTES SIGNATURE_BYTES @@ -96,41 +91,45 @@ static const uint8_t signature[4] = { #endif #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 - we limit the erase section by 0x1000 - */ - #define ERASE_SECTION 0xe000 + /* + * Due arvdude limitations we can't erase the whole progmem without running into an usb timeount on cleint side. So we we limit the + * erase section by 0x1000 + */ +#define ERASE_SECTION 0xe000 #else - #define ERASE_SECTION BOOT_SECTION_START +#define ERASE_SECTION BOOT_SECTION_START #endif #ifdef DEBUG_UART -static __attribute__ (( __noinline__ )) void uart_putc(uint8_t data) { - while(!(UCSR0A & _BV(UDRE0))); +static __attribute__ ((__noinline__)) + void uart_putc(uint8_t data) +{ + while (!(UCSR0A & _BV(UDRE0))); UDR0 = data; } #else - #define uart_putc(x) +#define uart_putc(x) #endif #ifdef DEBUG_UART -static __attribute__ (( __noinline__ )) void uart_puts(uint8_t *data) { - while(*data){ +static __attribute__ ((__noinline__)) + void uart_puts(uint8_t * data) +{ + while (*data) { uart_putc(*data); data++; } } #else - #define uart_puts(x) +#define uart_puts(x) #endif -/* supply custom usbDeviceConnect() and usbDeviceDisconnect() macros - * which turn the interrupt on and off at the right times, - * and prevent the execution of an interrupt while the pullup resistor - * is switched off */ +/* + * supply custom usbDeviceConnect() and usbDeviceDisconnect() macros which turn the interrupt on and off at the right times, and prevent + * the execution of an interrupt while the pullup resistor is switched off + */ #ifdef USB_CFG_PULLUP_IOPORTNAME #undef usbDeviceConnect @@ -147,24 +146,30 @@ static __attribute__ (( __noinline__ )) void uart_puts(uint8_t *data) { } while(0); #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: - * http://www.obdev.at/products/avrusb/usbasploader.html */ +/* + * 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 + */ #if FLASHEND > 0xffff # error "usbload only supports up to 64kb of flash!" #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 # error "SPM_PAGESIZE is too big (just checking lower byte)" #endif -/* start flash (byte address) read/write at this address */ +/* + * start flash (byte address) read/write at this address + */ usbWord_t flash_address; uint8_t bytes_remaining; uint8_t request; @@ -176,66 +181,93 @@ uint8_t timeout; usbMsgLen_t usbFunctionSetup(uchar data[8]) { - usbRequest_t *req = (void *)data; + usbRequest_t *req = (void *) data; uint8_t len = 0; static uint8_t buf[4]; - /* set global data pointer to local buffer */ + /* + * set global data pointer to local buffer + */ 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) { buf[0] = 0; len = 1; timeout = 255; } else if (req->bRequest == USBASP_FUNC_CONNECT) { - /* turn on led */ + /* + * turn on led + */ DLED_ON; } else if (req->bRequest == USBASP_FUNC_DISCONNECT) { - /* turn off led */ + /* + * turn off led + */ DLED_OFF; 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) { - /* reset buffer with zeroes */ + /* + * reset buffer with zeroes + */ memset(buf, '\0', sizeof(buf)); - /* read the address for eeprom operations */ + /* + * read the address for eeprom operations + */ usbWord_t address; - address.bytes[0] = data[4]; /* low byte is data[4] */ - address.bytes[1] = data[3]; /* high byte is data[3] */ + address.bytes[0] = data[4]; /* low byte is data[4] */ + 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) { - /* 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]; #ifdef ENABLE_CATCH_EEPROM_ISP - /* catch eeprom read */ + /* + * catch eeprom read + */ } 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) { - /* 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 - /* catch a chip erase */ + /* + * catch a chip erase + */ } else if (data[2] == ISP_CHIP_ERASE1 && data[3] == ISP_CHIP_ERASE2) { uart_puts("\n\rErase Flash"); for (flash_address.word = 0; flash_address.word < ERASE_SECTION; flash_address.word += SPM_PAGESIZE) { - /* wait and erase page */ + /* + * wait and erase page + */ boot_spm_busy_wait(); - if (flash_address.word && flash_address.word%1024 == 0 ) + if (flash_address.word && flash_address.word % 1024 == 0) uart_putc('.'); cli(); boot_page_erase(flash_address.word); @@ -244,44 +276,55 @@ usbMsgLen_t usbFunctionSetup(uchar data[8]) 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; #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) { buf[0] = req->wValue.bytes[0]; buf[1] = req->wValue.bytes[1]; len = 2; #endif } 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; bytes_remaining = req->wLength.bytes[0]; request = req->bRequest; - /* hand control over to usbFunctionRead()/usbFunctionWrite() */ + /* + * hand control over to usbFunctionRead()/usbFunctionWrite() + */ len = 0xff; } return len; } -uchar usbFunctionWrite(uchar *data, uchar len) +uchar usbFunctionWrite(uchar * data, uchar len) { if (len > bytes_remaining) len = bytes_remaining; bytes_remaining -= len; if (request == USBASP_FUNC_WRITEEEPROM) { for (uint8_t i = 0; i < len; i++) - eeprom_write_byte((uint8_t *)flash_address.word++, *data++); - } - else { - /* data is handled wordwise, adjust len */ + eeprom_write_byte((uint8_t *) flash_address.word++, *data++); + } else { + /* + * data is handled wordwise, adjust len + */ len /= 2; len -= 1; for (uint8_t i = 0; i <= len; i++) { - uint16_t *w = (uint16_t *)data; + uint16_t *w = (uint16_t *) data; cli(); boot_page_fill(flash_address.word, *w); sei(); @@ -291,9 +334,11 @@ uchar usbFunctionWrite(uchar *data, uchar len) next_address.word += 2; data += 2; - /* write page if page boundary is crossed or this is the last page */ - if ( next_address.bytes[0] % SPM_PAGESIZE == 0 || - (bytes_remaining == 0 && i == len) ) { + /* + * write page if page boundary is crossed or this is the last page + */ + if (next_address.bytes[0] % SPM_PAGESIZE == 0 || + (bytes_remaining == 0 && i == len)) { cli(); boot_page_write(flash_address.word); sei(); @@ -307,123 +352,157 @@ uchar usbFunctionWrite(uchar *data, uchar len) } } - /* flash led on activity */ + /* + * flash led on activity + */ DLED_TGL; 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; bytes_remaining -= len; for (uint8_t i = 0; i < len; i++) { - if(request == USBASP_FUNC_READEEPROM) - *data = eeprom_read_byte((void *)flash_address.word); + if (request == USBASP_FUNC_READEEPROM) + *data = eeprom_read_byte((void *) flash_address.word); else - *data = pgm_read_byte_near((void *)flash_address.word); + *data = pgm_read_byte_near((void *) flash_address.word); data++; flash_address.word++; } - /* flash led on activity */ + /* + * flash led on activity + */ DLED_TGL; return len; } -void (*jump_to_app)(void) = 0x0000; +void (*jump_to_app) (void) = 0x0000; void leave_bootloader(void) { cli(); - /* disconnect usb */ + /* + * disconnect usb + */ usbDeviceDisconnect(); 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); - /* 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 - /* init uart (115200 baud, at 20mhz) */ + /* + * init uart (115200 baud, at 20mhz) + */ UBRR0L = 10; UCSR0C = _BV(UCSZ00) | _BV(UCSZ01); UCSR0B = _BV(TXEN0); #endif uint8_t reset = MCUSR; - uint16_t delay =0; + uint16_t delay = 0; timeout = TIMEOUT; - + 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"); - MCUSR = 0; + MCUSR = 0; 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"); - MCUSR = 0; - wdt_disable(); - DLED_TGL; - _delay_ms(500); - DLED_TGL; - _delay_ms(500); + MCUSR = 0; + wdt_disable(); + DLED_TGL; + _delay_ms(500); + DLED_TGL; + _delay_ms(500); uart_puts("Jump to main\n\r"); - jump_to_app(); + jump_to_app(); } 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; - /* init exit request state */ + /* + * init exit request state + */ request_exit = 0; - /* move interrupts to boot section */ - + /* + * move interrupts to boot section + */ + MCUCR = (1 << IVCE); MCUCR = (1 << IVSEL); - /* enable interrupts */ + /* + * enable interrupts + */ sei(); - /* initialize usb pins */ + /* + * initialize usb pins + */ usbInit(); - /* disconnect for ~500ms, so that the host re-enumerates this device */ + /* + * disconnect for ~500ms, so that the host re-enumerates this device + */ usbDeviceDisconnect(); 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(); uart_puts("Wait for firmware"); - while(1) { + while (1) { 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) { uart_putc('.'); DLED_TGL; @@ -438,5 +517,5 @@ int __attribute__ ((noreturn,OS_main)) main(void) } } - + } diff --git a/avr/usbload/main.c b/avr/usbload/main.c index da6092e..2c1ab5b 100644 --- a/avr/usbload/main.c +++ b/avr/usbload/main.c @@ -407,6 +407,9 @@ int main(void) crc_check_bulk_memory(0x000000, req_addr_end, req_bank_size); #endif + snes_reset_hi(); + snes_reset_off(); + snes_irq_lo(); snes_irq_off(); @@ -424,6 +427,15 @@ int main(void) snes_bus_active(); 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){ usbPoll(); #if 0 diff --git a/avr/usbload/sram.h b/avr/usbload/sram.h index 8d44eed..169c8bd 100644 --- a/avr/usbload/sram.h +++ b/avr/usbload/sram.h @@ -84,6 +84,16 @@ #define snes_irq_off() (SNES_IRQ_DIR &= ~(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 ---------------------------- */