root / trunk / toolbox / bootloader / bootloader.c @ 169
History | View | Annotate | Download (6.67 KB)
1 | 154 | bneuman | #include <avr/io.h> |
---|---|---|---|
2 | #include <avr/boot.h> |
||
3 | 165 | kwoo | #include <avr/pgmspace.h> |
4 | 154 | bneuman | |
5 | 156 | kwoo | #include "tooltron.h" |
6 | 154 | bneuman | #include "uart.h" |
7 | |||
8 | #define TRUE 0 |
||
9 | #define FALSE 1 |
||
10 | |||
11 | 156 | kwoo | #define ADDR 18 |
12 | |||
13 | |||
14 | 154 | bneuman | #define MAX_WAIT_IN_CYCLES 800000 |
15 | 158 | kwoo | #define MAX_TIMEOUT 60000 // Seconds to wait before exiting bootloader mode |
16 | 165 | kwoo | #define MAIN_ADDR 0x000 |
17 | 169 | kwoo | #define BOOT_START 0x400 |
18 | 154 | bneuman | |
19 | //Status LED
|
||
20 | #define LED_DDR DDRB
|
||
21 | #define LED_PORT PORTB
|
||
22 | #define LED PORTB1
|
||
23 | |||
24 | //Function prototypes
|
||
25 | 165 | kwoo | void __init(void) __attribute__((naked)); |
26 | 169 | kwoo | void (*main_start)(void) = BOOT_START/2 - 1; |
27 | 154 | bneuman | |
28 | 165 | kwoo | |
29 | 156 | kwoo | typedef enum { |
30 | sd, |
||
31 | src, |
||
32 | dest, |
||
33 | comd, |
||
34 | read, |
||
35 | cs, |
||
36 | ack |
||
37 | } state_t; |
||
38 | |||
39 | 168 | kwoo | typedef union { |
40 | uint8_t bytes[2];
|
||
41 | int16_t sword; |
||
42 | } rjump_t; |
||
43 | |||
44 | 165 | kwoo | // Redirect all unused interrupts to reti
|
45 | 169 | kwoo | //EMPTY_INTERRUPT(__vector_default);
|
46 | //extern void __ctors_end(void) __attribute__((__noreturn__));
|
||
47 | 165 | kwoo | |
48 | // macros for entering subprograms
|
||
49 | 169 | kwoo | //#define __JMP_INIT__ __asm__ __volatile__ ("rjmp __ctors_end" )
|
50 | 165 | kwoo | |
51 | 169 | kwoo | /*BOOTLOADER_SECTION*/ void init_uart(uint16_t baud) { |
52 | 164 | kwoo | // Set baud rate
|
53 | UBRRH = (uint8_t)(baud>>8);
|
||
54 | UBRRL = (uint8_t)baud; |
||
55 | |||
56 | 167 | kwoo | // Enable RX/TX
|
57 | 166 | kwoo | UCSRB = _BV(RXEN) | _BV(TXEN); |
58 | 164 | kwoo | |
59 | // Enable the TXEN pin as output
|
||
60 | DDRD |= TX_EN; |
||
61 | 166 | kwoo | uart_toggle_transmit(UART_TX_OFF); |
62 | 164 | kwoo | } |
63 | 156 | kwoo | |
64 | 169 | kwoo | /*BOOTLOADER_SECTION*/ int8_t uart_get_byte(uint8_t *output_byte) {
|
65 | 164 | kwoo | if (UCSRA & _BV(RXC)) {
|
66 | *output_byte = UDR; |
||
67 | return 0; |
||
68 | } else {
|
||
69 | return -1; |
||
70 | } |
||
71 | 158 | kwoo | } |
72 | |||
73 | 169 | kwoo | /*BOOTLOADER_SECTION*/ void uart_send_byte(uint8_t data) { |
74 | 164 | kwoo | //Waits until current transmit is done
|
75 | while (!(UCSRA & _BV(UDRE)));
|
||
76 | 167 | kwoo | //PORTB |= _BV(PORTB2);
|
77 | 164 | kwoo | |
78 | // Enable writes and send
|
||
79 | uart_toggle_transmit(UART_TX_ON); |
||
80 | UDR = data; |
||
81 | |||
82 | // Waits until the transmit is done
|
||
83 | 167 | kwoo | while(!(UCSRA & _BV(TXC)));
|
84 | 164 | kwoo | uart_toggle_transmit(UART_TX_OFF); |
85 | 167 | kwoo | UCSRA |= _BV(TXC); |
86 | 164 | kwoo | |
87 | 167 | kwoo | //PORTB |= _BV(PORTB1);
|
88 | |||
89 | |||
90 | 164 | kwoo | return;
|
91 | 158 | kwoo | } |
92 | |||
93 | 169 | kwoo | /*BOOTLOADER_SECTION*/ void uart_toggle_transmit(uint8_t state) { |
94 | 164 | kwoo | if (state == UART_TX_ON) {
|
95 | PORTD |= TX_EN; |
||
96 | } else {
|
||
97 | PORTD &= ~TX_EN; |
||
98 | } |
||
99 | 158 | kwoo | } |
100 | |||
101 | 169 | kwoo | /*BOOTLOADER_SECTION*/ char parse_packet(uint8_t *mbuf) { |
102 | 168 | kwoo | uint8_t r; // Byte from the network
|
103 | uint8_t crc; // Running checksum of the packet
|
||
104 | uint8_t cmd; // The command received
|
||
105 | uint8_t pos; // Position in the message buffer
|
||
106 | uint8_t lim; // Max number of bytes to read into the message buf
|
||
107 | state_t state; // State machine
|
||
108 | uint16_t count; |
||
109 | |||
110 | r = 0;
|
||
111 | crc = 0;
|
||
112 | cmd = 0;
|
||
113 | pos = 0;
|
||
114 | lim = 0;
|
||
115 | state = sd; |
||
116 | 158 | kwoo | count = 0;
|
117 | |||
118 | 156 | kwoo | while (1) { |
119 | // Wait for the next byte
|
||
120 | 158 | kwoo | while ((uart_get_byte(&r)) < 0) { |
121 | 161 | kwoo | if (count >= MAX_TIMEOUT) {
|
122 | return TT_BAD;
|
||
123 | } |
||
124 | 158 | kwoo | } |
125 | 156 | kwoo | |
126 | switch (state) {
|
||
127 | case sd:
|
||
128 | if (r == DELIM) {
|
||
129 | state = src; |
||
130 | } |
||
131 | break;
|
||
132 | |||
133 | case src:
|
||
134 | if (r == DELIM) {
|
||
135 | state = src; |
||
136 | } else {
|
||
137 | crc = r; |
||
138 | state = dest; |
||
139 | } |
||
140 | break;
|
||
141 | |||
142 | case dest:
|
||
143 | if (r == DELIM) {
|
||
144 | state = src; |
||
145 | } else if (r == ADDR) { |
||
146 | crc ^= r; |
||
147 | state = comd; |
||
148 | } else {
|
||
149 | state = sd; |
||
150 | } |
||
151 | break;
|
||
152 | |||
153 | case comd:
|
||
154 | cmd = r; |
||
155 | crc ^= r; |
||
156 | |||
157 | if (r == DELIM) {
|
||
158 | state = src; |
||
159 | } else if (r == TT_PROGM) { |
||
160 | lim = PROGM_PACKET_SIZE; |
||
161 | state = read; |
||
162 | } else if (r == TT_PROGD) { |
||
163 | lim = PROGD_PACKET_SIZE; |
||
164 | state = read; |
||
165 | } else {
|
||
166 | state = cs; |
||
167 | } |
||
168 | break;
|
||
169 | |||
170 | case read:
|
||
171 | mbuf[pos] = r; |
||
172 | crc ^= r; |
||
173 | pos++; |
||
174 | |||
175 | if (pos == lim) {
|
||
176 | state = cs; |
||
177 | } |
||
178 | |||
179 | break;
|
||
180 | |||
181 | case cs:
|
||
182 | if (r == crc) {
|
||
183 | return cmd;
|
||
184 | } else {
|
||
185 | return TT_BAD;
|
||
186 | } |
||
187 | |||
188 | break;
|
||
189 | |||
190 | default:
|
||
191 | return TT_BAD;
|
||
192 | } |
||
193 | } |
||
194 | } |
||
195 | |||
196 | 169 | kwoo | /*BOOTLOADER_SECTION*/ void send_packet(uint8_t cmd) { |
197 | 156 | kwoo | uart_send_byte(DELIM); |
198 | uart_send_byte(ADDR); |
||
199 | uart_send_byte(SERVER); |
||
200 | 158 | kwoo | uart_send_byte(cmd); |
201 | uart_send_byte(ACK_CRC ^ cmd); |
||
202 | 156 | kwoo | } |
203 | |||
204 | 164 | kwoo | //#define SPM_PAGESIZE 32
|
205 | 169 | kwoo | /*BOOTLOADER_SECTION*/ void onboard_program_write(uint16_t page, uint8_t *buf) { |
206 | 164 | kwoo | uint16_t i; |
207 | |||
208 | boot_page_erase (page); |
||
209 | boot_spm_busy_wait (); // Wait until the memory is erased.
|
||
210 | |||
211 | for (i=0; i < SPM_PAGESIZE; i+=2){ |
||
212 | // Set up little-endian word.
|
||
213 | 168 | kwoo | boot_page_fill (page + i, buf[i] | (buf[i+1] <<8)); |
214 | 164 | kwoo | } |
215 | |||
216 | boot_page_write (page); // Store buffer in flash page.
|
||
217 | boot_spm_busy_wait(); // Wait until the memory is written.
|
||
218 | } |
||
219 | |||
220 | 169 | kwoo | /*BOOTLOADER_SECTION*/ int main(void) { |
221 | 164 | kwoo | uint8_t mbuf[PROGD_PACKET_SIZE]; |
222 | 168 | kwoo | rjump_t jbuf; |
223 | 161 | kwoo | uint16_t caddr = MAIN_ADDR; |
224 | 168 | kwoo | uint8_t iteration; |
225 | 158 | kwoo | uint8_t resp; |
226 | 168 | kwoo | uint16_t prog_len; |
227 | 165 | kwoo | uint8_t i; |
228 | 168 | kwoo | |
229 | 169 | kwoo | //main_start = (void*)(BOOT_START - 2);
|
230 | 168 | kwoo | iteration = 0;
|
231 | 158 | kwoo | |
232 | 155 | bneuman | init_uart(51); //MAGIC NUMBER?? |
233 | 154 | bneuman | |
234 | //set LED pin as output
|
||
235 | 161 | kwoo | LED_DDR |= 0x07;
|
236 | 167 | kwoo | PORTB = 0x07;
|
237 | 154 | bneuman | |
238 | //Start bootloading process
|
||
239 | 158 | kwoo | send_packet(TT_BOOT); |
240 | 154 | bneuman | |
241 | 158 | kwoo | resp = parse_packet(mbuf); |
242 | if (resp == TT_PROGM) {
|
||
243 | prog_len = mbuf[0];
|
||
244 | prog_len |= mbuf[1] << 8; |
||
245 | } else {
|
||
246 | 168 | kwoo | //PORTB = 0;
|
247 | 161 | kwoo | main_start(); |
248 | 154 | bneuman | } |
249 | 158 | kwoo | send_packet(TT_ACK); |
250 | 154 | bneuman | |
251 | while(1) { |
||
252 | 158 | kwoo | resp = parse_packet(mbuf); |
253 | 154 | bneuman | |
254 | 161 | kwoo | if (resp == TT_PROGD) {
|
255 | 164 | kwoo | if (iteration == 0) { |
256 | 165 | kwoo | // Store the jump to user code
|
257 | 168 | kwoo | jbuf.bytes[0] = mbuf[0]; |
258 | jbuf.bytes[1] = mbuf[1]; |
||
259 | |||
260 | jbuf.sword &= 0x0FFF;
|
||
261 | 169 | kwoo | jbuf.sword -= (BOOT_START >> 1) - 1; |
262 | 168 | kwoo | jbuf.sword &= 0x0FFF;
|
263 | jbuf.sword |= 0xC000;
|
||
264 | 165 | kwoo | |
265 | 169 | kwoo | mbuf[0] = (BOOT_START/2 - 1) & 0xFF; |
266 | mbuf[1] = 0xC0 | (((BOOT_START/2 - 1) >> 8) & 0x0F); |
||
267 | //memcpy_P(mbuf, (PGM_VOID_P)MAIN_ADDR, 2);
|
||
268 | //mbuf[0] = pgm_read_byte(MAIN_ADDR);
|
||
269 | //mbuf[1] = pgm_read_byte(MAIN_ADDR + 1);
|
||
270 | 168 | kwoo | //PORTB &= ~_BV(PORTB0);
|
271 | //while(1);
|
||
272 | 165 | kwoo | |
273 | 164 | kwoo | iteration = 1;
|
274 | 168 | kwoo | } /*else {
|
275 | PORTB &= ~_BV(PORTB1);
|
||
276 | while(1);
|
||
277 | }*/
|
||
278 | 167 | kwoo | |
279 | 168 | kwoo | |
280 | 167 | kwoo | onboard_program_write(caddr, mbuf); |
281 | caddr += PROGD_PACKET_SIZE; |
||
282 | 161 | kwoo | } else {
|
283 | 166 | kwoo | //main_start();
|
284 | 168 | kwoo | PORTB &= ~_BV(PORTB2); |
285 | 166 | kwoo | while(1); |
286 | 161 | kwoo | } |
287 | |||
288 | 158 | kwoo | send_packet(TT_ACK); |
289 | 161 | kwoo | |
290 | if (prog_len <= PROGD_PACKET_SIZE) {
|
||
291 | 165 | kwoo | for (i = 0; i < PROGD_PACKET_SIZE; i++) { |
292 | mbuf[i]= 0;
|
||
293 | } |
||
294 | |||
295 | 168 | kwoo | mbuf[PROGD_PACKET_SIZE-2] = jbuf.bytes[0]; |
296 | mbuf[PROGD_PACKET_SIZE-1] = jbuf.bytes[1]; |
||
297 | 165 | kwoo | |
298 | 168 | kwoo | onboard_program_write(BOOT_START - SPM_PAGESIZE, mbuf); |
299 | 165 | kwoo | |
300 | 164 | kwoo | PORTB = 0;
|
301 | 161 | kwoo | main_start(); |
302 | } else {
|
||
303 | prog_len -= PROGD_PACKET_SIZE; |
||
304 | } |
||
305 | 154 | bneuman | } |
306 | 169 | kwoo | |
307 | return -1; |
||
308 | 154 | bneuman | } |
309 | |||
310 | 168 | kwoo | /*
|
311 | 165 | kwoo | int main (void) {
|
312 | while(1);
|
||
313 | 168 | kwoo | }*/ |