diff options
Diffstat (limited to 'bootloaders/diskloader/src/DiskLoader.cpp')
-rw-r--r-- | bootloaders/diskloader/src/DiskLoader.cpp | 304 |
1 files changed, 145 insertions, 159 deletions
diff --git a/bootloaders/diskloader/src/DiskLoader.cpp b/bootloaders/diskloader/src/DiskLoader.cpp index 2792bc6..6580618 100644 --- a/bootloaders/diskloader/src/DiskLoader.cpp +++ b/bootloaders/diskloader/src/DiskLoader.cpp @@ -1,67 +1,64 @@ -/* - * DiskLoader.cpp - */ + #include "Platform.h" +// This bootloader creates a composite Serial device +// +// The serial interface supports a STK500v1 protocol that is very similar to optiboot +// +// The bootloader will timeout and start the firmware after a few hundred milliseconds +// if a usb connection is not detected. +// +// The tweakier code is to keep the bootloader below 2k (no interrupt table, for example) + extern "C" void entrypoint(void) __attribute__ ((naked)) __attribute__ ((section (".vectors"))); void entrypoint(void) { asm volatile ( - "eor r1, r1\n" // Zero register - "out 0x3F, r1\n" // SREG - "ldi r28, 0xFF\n" // Y-register - "ldi r29, 0x0A\n" // Y-register - "out 0x3E, r29\n" // SPH - "out 0x3D, r28\n" // SPL - "rjmp main" // Stack is all set up, start the main code - ::); + "eor r1, r1\n" // Zero register + "out 0x3F, r1\n" // SREG + "ldi r28, 0xFF\n" + "ldi r29, 0x0A\n" + "out 0x3E, r29\n" // SPH + "out 0x3D, r28\n" // SPL + "rjmp main" // Stack is all set up, start the main code + ::); } u8 _flashbuf[128]; u8 _inSync; u8 _ok; -u16 do_reset = 0; -volatile u16 _timeout = 0; +extern volatile u8 _ejected; +extern volatile u16 _timeout; void Program(u8 ep, u16 page, u8 count) { - u8 write = page < 28*1024; // Don't write over bootloader please + u8 write = page < 30*1024; // Don't write over firmware please if (write) boot_page_erase(page); - - USB_Recv_block(ep,_flashbuf,count); // Read while page is erasing - + + Recv(ep,_flashbuf,count); // Read while page is erasing + if (!write) return; - + boot_spm_busy_wait(); // Wait until the memory is erased. - + count >>= 1; u16* p = (u16*)page; u16* b = (u16*)_flashbuf; for (u8 i = 0; i < count; i++) boot_page_fill(p++, b[i]); - + boot_page_write(page); boot_spm_busy_wait(); boot_rww_enable (); } -u16 _pulse; -void LEDPulse() -{ - _pulse += 1; - u8 p = _pulse >> 9; - if (p > 63) - p = 127-p; - p += p; - if (((u8)_pulse) > p) - L_LED_OFF(); - else - L_LED_ON(); -} + +int USBGetChar(); +#define getch USBGetChar #define HW_VER 0x02 #define SW_MAJOR 0x01 @@ -107,147 +104,136 @@ const u8 _consts[] = 0x00, // }; -void start_sketch() -{ - if (pgm_read_word(0) == -1) // no sketch has been uploaded yet - stay in bootloader - return; - - L_LED_OFF(); - RX_LED_OFF(); - TX_LED_OFF(); - /* move interrupts to application section: - * uses inline assembly because the procedure must be completed in four cycles. - */ - cli(); // disable interrupts first - asm volatile ( - "ldi r16, 0x01\n" // (1<<IVCE) /* Enable change of interrupt vectors */ - "out 0x35, r16\n" // MCUCR - "ldi r16, 0x00\n" // (1<<IVSEL) /* Move interrupts to application flash section */ - "out 0x35, r16\n" // MCUCR - ); - UDCON = 1; // Detatch USB - UDIEN = 0; - asm volatile ( // Reset vector to run firmware - "clr r30\n" - "clr r31\n" - "ijmp\n" - ::); -} +void USBInit(void); int main(void) __attribute__ ((naked)); -int main() -{ + +// STK500v1 main loop, very similar to optiboot in protocol and implementation +int main() +{ wdt_disable(); + TXLED0; + RXLED0; + LED0; BOARD_INIT(); - /* move interrupts to boot section: - * uses inline assembly because the procedure must be completed in four cycles. - * seems to fail if called before disabling WDT and calling BOARD_INIT() - */ - asm volatile ( - "ldi r16, 0x01\n" // (1<<IVCE) /* Enable change of interrupt vectors */ - "out 0x35, r16\n" // MCUCR - "ldi r16, 0x02\n" // (1<<IVSEL) /* Move interrupts to boot flash section */ - "out 0x35, r16\n" // MCUCR - ); - TX_LED_OFF(); - RX_LED_OFF(); - L_LED_OFF(); - USB.attach(); - sei(); - + USBInit(); + _inSync = STK_INSYNC; _ok = STK_OK; - - for (;;) + + if (pgm_read_word(0) != -1) + _ejected = 1; + + for(;;) { u8* packet = _flashbuf; u16 address = 0; for (;;) - { - if (USB_Available(CDC_RX)) + { + u8 cmd = getch(); + + // Read packet contents + u8 len; + const u8* rs = _readSize; + for(;;) { - u8 cmd = USB_Recv(CDC_RX); - - // Read packet contents - u8 len; - const u8* rs = _readSize; - for (;;) - { - u8 c = pgm_read_byte(rs++); - len = pgm_read_byte(rs++); - if (c == cmd || c == 0) - break; - } - _timeout = 0; - // Read params - USB_Recv_block(CDC_RX, packet, len); - - // Send a response - u8 send = 0; - const u8* pgm = _consts+7; - if (STK_GET_PARAMETER == cmd) - { - u8 i = packet[0] - 0x80; - if (i > 2) - i = (i==0x18) ? 3 : 4; - pgm = _consts + i + 3; - send = 1; - } - else if (STK_UNIVERSAL == cmd) - { - if (packet[0] == 0x30) - pgm = _consts + packet[2]; - send = 1; - } - else if (STK_READ_SIGN == cmd) - { - pgm = _consts; - send = 3; - } - else if (STK_LOAD_ADDRESS == cmd) - { - address = *((u16*)packet); // word address - address += address; - } - else if (STK_PROG_PAGE == cmd) - { - Program(CDC_RX, address, packet[1]); - } - else if (STK_READ_PAGE == cmd) - { - send = packet[1]; - pgm = (const u8*)address; - address += send; - } - - u16 countdown = 5000; - while (countdown-- > 10 && !USB_Available(CDC_RX)) - ; - int x = USB_Recv(CDC_RX); - if (x != -1 && x != ' ') + u8 c = pgm_read_byte(rs++); + len = pgm_read_byte(rs++); + if (c == cmd || c == 0) break; - - USB_Send(CDC_TX, &_inSync, 1); - - if (send) - USB_Send(CDC_TX|TRANSFER_PGM, pgm, send); - - // Send ok - USB_Send(CDC_TX|TRANSFER_RELEASE, &_ok, 1); - - if ('Q' == cmd) - { - _delay_ms(100); - start_sketch(); - } } - else + _timeout = 0; + // Read params + Recv(CDC_RX,packet,len); + + // Send a response + u8 send = 0; + const u8* pgm = _consts+7; // 0 + if (STK_GET_PARAMETER == cmd) + { + u8 i = packet[0] - 0x80; + if (i > 2) + i = (i == 0x18) ? 3 : 4; // 0x80:HW_VER,0x81:SW_MAJOR,0x82:SW_MINOR,0x18:3 or 0 + pgm = _consts + i + 3; + send = 1; + } + + else if (STK_UNIVERSAL == cmd) { - LEDPulse(); - _delay_us(100); - if (_timeout-- == 1) - start_sketch(); + if (packet[0] == 0x30) + pgm = _consts + packet[2]; // read signature + send = 1; } + + // Read signature bytes + else if (STK_READ_SIGN == cmd) + { + pgm = _consts; + send = 3; + } + + else if (STK_LOAD_ADDRESS == cmd) + { + address = *((u16*)packet); // word addresses + address += address; + } + + else if (STK_PROG_PAGE == cmd) + { + Program(CDC_RX,address,packet[1]); + } + + else if (STK_READ_PAGE == cmd) + { + send = packet[1]; + pgm = (const u8*)address; + address += send; // not sure of this is required + } + + // Check sync + if (getch() != ' ') + break; + Transfer(CDC_TX,&_inSync,1); + + // Send result + if (send) + Transfer(CDC_TX|TRANSFER_PGM,pgm,send); // All from pgm memory + + // Send ok + Transfer(CDC_TX|TRANSFER_RELEASE,&_ok,1); + + if (cmd == 'Q') + break; } + _timeout = 500; // wait a moment before exiting the bootloader - may need to finish responding to 'Q' for example + _ejected = 1; } } + +// Nice breathing LED indicates we are in the firmware +u16 _pulse; +void LEDPulse() +{ + _pulse += 4; + u8 p = _pulse >> 9; + if (p > 63) + p = 127-p; + p += p; + if (((u8)_pulse) > p) + LED0; + else + LED1; +} + +void Reboot() +{ + TXLED0; // switch off the RX and TX LEDs before starting the user sketch + RXLED0; + UDCON = 1; // Detatch USB + UDIEN = 0; + asm volatile ( // Reset vector to run firmware + "clr r30\n" + "clr r31\n" + "ijmp\n" + ::); +} |