aboutsummaryrefslogtreecommitdiff
path: root/bootloaders/diskloader/src/DiskLoader.cpp
diff options
context:
space:
mode:
authorZach Eveland <zeveland@blacklabel-development.com>2011-11-09 14:04:59 -0500
committerZach Eveland <zeveland@blacklabel-development.com>2011-11-09 14:04:59 -0500
commit4b7771a8159f47891311bbac6d97eac33868bc65 (patch)
tree729f0940bad89ec074aeb4cdb189f1b2839e744a /bootloaders/diskloader/src/DiskLoader.cpp
parentbca358b9739c8bf7e4dd9808b97acc90cf0b6ab3 (diff)
restored original non-interrupt-driven DiskLoader
Interrupt-driven version was a dead-end - too many bugs with that approach.
Diffstat (limited to 'bootloaders/diskloader/src/DiskLoader.cpp')
-rw-r--r--bootloaders/diskloader/src/DiskLoader.cpp304
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"
+ ::);
+}