5
// This bootloader creates a composite Serial device
7
// The serial interface supports a STK500v1 protocol that is very similar to optiboot
9
// The bootloader will timeout and start the firmware after a few hundred milliseconds
10
// if a usb connection is not detected.
12
// The tweakier code is to keep the bootloader below 2k (no interrupt table, for example)
15
void entrypoint(void) __attribute__ ((naked)) __attribute__ ((section (".vectors")));
19
"eor r1, r1\n" // Zero register
20
"out 0x3F, r1\n" // SREG
23
"out 0x3E, r29\n" // SPH
24
"out 0x3D, r28\n" // SPL
25
"rjmp main" // Stack is all set up, start the main code
32
extern volatile u8 _ejected;
33
extern volatile u16 _timeout;
35
void Program(u8 ep, u16 page, u8 count)
37
u8 write = page < 30*1024; // Don't write over firmware please
39
boot_page_erase(page);
41
Recv(ep,_flashbuf,count); // Read while page is erasing
46
boot_spm_busy_wait(); // Wait until the memory is erased.
50
u16* b = (u16*)_flashbuf;
51
for (u8 i = 0; i < count; i++)
52
boot_page_fill(p++, b[i]);
54
boot_page_write(page);
61
#define getch USBGetChar
68
#define STK_INSYNC 0x14 // ' '
69
#define CRC_EOP 0x20 // 'SPACE'
70
#define STK_GET_SYNC 0x30 // '0'
72
#define STK_GET_PARAMETER 0x41 // 'A'
73
#define STK_SET_DEVICE 0x42 // 'B'
74
#define STK_SET_DEVICE_EXT 0x45 // 'E'
75
#define STK_LOAD_ADDRESS 0x55 // 'U'
76
#define STK_UNIVERSAL 0x56 // 'V'
77
#define STK_PROG_PAGE 0x64 // 'd'
78
#define STK_READ_PAGE 0x74 // 't'
79
#define STK_READ_SIGN 0x75 // 'u'
81
extern const u8 _readSize[] PROGMEM;
82
const u8 _readSize[] =
86
STK_SET_DEVICE_EXT, 5,
94
extern const u8 _consts[] PROGMEM;
100
HW_VER, // Hardware version
101
SW_MAJOR, // Software major version
102
SW_MINOR, // Software minor version
103
0x03, // Unknown but seems to be required by avr studio 3.56
109
int main(void) __attribute__ ((naked));
111
// STK500v1 main loop, very similar to optiboot in protocol and implementation
121
_inSync = STK_INSYNC;
124
if (pgm_read_word(0) != -1)
129
u8* packet = _flashbuf;
135
// Read packet contents
137
const u8* rs = _readSize;
140
u8 c = pgm_read_byte(rs++);
141
len = pgm_read_byte(rs++);
142
if (c == cmd || c == 0)
147
Recv(CDC_RX,packet,len);
151
const u8* pgm = _consts+7; // 0
152
if (STK_GET_PARAMETER == cmd)
154
u8 i = packet[0] - 0x80;
156
i = (i == 0x18) ? 3 : 4; // 0x80:HW_VER,0x81:SW_MAJOR,0x82:SW_MINOR,0x18:3 or 0
157
pgm = _consts + i + 3;
161
else if (STK_UNIVERSAL == cmd)
163
if (packet[0] == 0x30)
164
pgm = _consts + packet[2]; // read signature
168
// Read signature bytes
169
else if (STK_READ_SIGN == cmd)
175
else if (STK_LOAD_ADDRESS == cmd)
177
address = *((u16*)packet); // word addresses
181
else if (STK_PROG_PAGE == cmd)
183
Program(CDC_RX,address,packet[1]);
186
else if (STK_READ_PAGE == cmd)
189
pgm = (const u8*)address;
190
address += send; // not sure of this is required
196
Transfer(CDC_TX,&_inSync,1);
200
Transfer(CDC_TX|TRANSFER_PGM,pgm,send); // All from pgm memory
203
Transfer(CDC_TX|TRANSFER_RELEASE,&_ok,1);
208
_timeout = 500; // wait a moment before exiting the bootloader - may need to finish responding to 'Q' for example
213
// Nice breathing LED indicates we are in the firmware
222
if (((u8)_pulse) > p)
230
TXLED0; // switch off the RX and TX LEDs before starting the user sketch
232
UDCON = 1; // Detatch USB
234
asm volatile ( // Reset vector to run firmware