Project

General

Profile

Statistics
| Revision:

root / trunk / bootloader / bootloader.c @ 287

History | View | Annotate | Download (5.14 KB)

1 189 kwoo
#include "bootloader.h"
2 154 bneuman
3 194 kwoo
// Setup the default fuses
4 197 kwoo
// This seems to be broken for now...
5 196 kwoo
/*
6 194 kwoo
FUSES = {
7
    .low = (FUSE_SUT0 & FUSE_CKSEL3 & FUSE_CKSEL2 & FUSE_CKSEL0),
8
    .high = (FUSE_EESAVE & FUSE_SPIEN),
9 197 kwoo
    .extended = (FUSE_SELFPRGEN)
10
};
11
*/
12 156 kwoo
13 173 kwoo
// Error thresholds
14
#define MAX_RETRIES 5       // Number of times to retry before giving up
15 154 bneuman
16 195 kwoo
/**
17
 * Where we store the jump to user code. The jump address is in words
18
 * due to how the rjmp instruction works. It is 1 word below the bootloader
19 196 kwoo
 * We declare it as noreturn to save some space since we will never return
20
 * to the bootloader unless we do a system reset
21 195 kwoo
 */
22 217 kwoo
void (*main_start)(void) __attribute__((noreturn)) = (void*)(BOOT_START/2 - 1);
23 195 kwoo
24 168 kwoo
typedef union {
25
    uint8_t bytes[2];
26
    int16_t sword;
27
} rjump_t;
28
29 156 kwoo
30 171 kwoo
// SPM_PAGESIZE is set to 32 bytes
31
void onboard_program_write(uint16_t page, uint8_t *buf) {
32 164 kwoo
  uint16_t i;
33
34
  boot_page_erase (page);
35
  boot_spm_busy_wait ();      // Wait until the memory is erased.
36
37
  for (i=0; i < SPM_PAGESIZE; i+=2){
38
    // Set up little-endian word.
39 168 kwoo
    boot_page_fill (page + i, buf[i] | (buf[i+1] <<8));
40 164 kwoo
  }
41
42
  boot_page_write (page);     // Store buffer in flash page.
43
  boot_spm_busy_wait();       // Wait until the memory is written.
44
}
45
46 171 kwoo
int main(void) {
47 217 kwoo
  uint8_t mbuf[MAX_PAYLOAD_SIZE];
48 168 kwoo
  rjump_t jbuf;
49 201 kwoo
  uint16_t caddr;
50
  uint16_t prog_len;
51 158 kwoo
  uint8_t resp;
52 165 kwoo
  uint8_t i;
53 173 kwoo
  uint8_t retries;
54 199 kwoo
  uint8_t addr;
55 200 kwoo
  uint8_t boot;
56 176 kwoo
57 201 kwoo
  // This is where we jump to if we fail out because of retries
58
  retry_jpnt:
59
60
  // We set the variables here
61
  caddr = MAIN_ADDR;
62 173 kwoo
  retries = 0;
63 201 kwoo
  boot = FALSE;
64 200 kwoo
65 201 kwoo
  // Grab the address from EEPROM
66 287 kwoo
  addr = read_addr();
67 201 kwoo
68
  // Initialize the Pins
69
  DDRB = LED_GREEN | LED_YELLOW | LED_RED;  // Set the LED pins as outputs
70
  PORTB = 0x00;                             // LEDs on == in bootloader
71
  DDRD = RELAY;                             // Set Relay as an output
72
  PORTD = 0x00;                             // Turn relay off
73
74 176 kwoo
  // Clear the watchdog timer
75 200 kwoo
  if (MCUSR & _BV(WDRF)) {
76
      MCUSR &= ~_BV(WDRF);
77
      wdt_disable();
78
      WDTCSR = 0;
79 201 kwoo
      boot = TRUE;
80 200 kwoo
  }
81 158 kwoo
82 287 kwoo
  // External override at bootup to enter bootloading mode
83 201 kwoo
  if (!(BUT_PORT & (BUT_RED | BUT_BLACK))) {
84
      boot = TRUE;
85 200 kwoo
  }
86
87 201 kwoo
  // Initialize the RS485
88 198 kwoo
  rs485_init(BAUD9600);
89 154 bneuman
90 201 kwoo
  //Execute user code if we aren't supposed to enter bootloading mode
91
  if (boot == FALSE) {
92
      goto run_user_code;
93 200 kwoo
  }
94 154 bneuman
95 201 kwoo
  // Send the boot packet
96 217 kwoo
  // We're not using the loop variable i right now and we are ignoring the
97
  // packet length so we're just going to "capture" the length and ignore it
98
  send_packet(TT_BOOT, addr, NULL, 0);
99
  resp = parse_packet(mbuf, &i, addr);
100 173 kwoo
101
  // Enter programming mode
102 158 kwoo
  if (resp == TT_PROGM) {
103
    prog_len = mbuf[0];
104
    prog_len |= mbuf[1] << 8;
105 173 kwoo
106
    // This will insert a NOP into the user code jump in case
107
    // the programming fails
108
    for (i = 0; i < PROGD_PACKET_SIZE; i++) {
109
      mbuf[i]= 0;
110
    }
111
    onboard_program_write(BOOT_START - SPM_PAGESIZE, mbuf);
112
113
  // Run user code
114 158 kwoo
  } else {
115 201 kwoo
      run_user_code:
116
      LED_PORT = LED_GREEN | LED_YELLOW | LED_RED;
117 161 kwoo
      main_start();
118 154 bneuman
  }
119 173 kwoo
120 217 kwoo
  send_packet(TT_ACK, addr, NULL, 0);
121 154 bneuman
122
  while(1) {
123 217 kwoo
      // We are ignoring the length of the packet so we are reusing the loop
124
      // variable i which is not being used right now to throw away the value
125
      resp = parse_packet(mbuf, &i, addr);
126 154 bneuman
127 161 kwoo
      if (resp == TT_PROGD) {
128 173 kwoo
          // We need to muck with the reset vector jump in the first page
129 201 kwoo
          if (caddr == MAIN_ADDR) {
130 165 kwoo
              // Store the jump to user code
131 168 kwoo
              jbuf.bytes[0] = mbuf[0];
132
              jbuf.bytes[1] = mbuf[1];
133
134 173 kwoo
              // Rewrite the user code jump to be correct since we are
135
              // using relative jumps (rjmp)
136 168 kwoo
              jbuf.sword &= 0x0FFF;
137 169 kwoo
              jbuf.sword -= (BOOT_START >> 1) - 1;
138 168 kwoo
              jbuf.sword &= 0x0FFF;
139
              jbuf.sword |= 0xC000;
140 165 kwoo
141 173 kwoo
              // Rewrite the reset vector to jump to the bootloader
142 169 kwoo
              mbuf[0] = (BOOT_START/2 - 1) & 0xFF;
143
              mbuf[1] = 0xC0 | (((BOOT_START/2 - 1) >> 8) & 0x0F);
144 171 kwoo
          }
145 167 kwoo
146 173 kwoo
          // Write the page to the flash
147 167 kwoo
          onboard_program_write(caddr, mbuf);
148
          caddr += PROGD_PACKET_SIZE;
149 173 kwoo
          retries = 0;
150 161 kwoo
      } else {
151 217 kwoo
          send_packet(TT_NACK, addr, NULL, 0);
152 173 kwoo
          retries++;
153
154 174 kwoo
          // If we failed too many times, reset. This goes to the start
155
          // of the bootloader function
156 173 kwoo
          if (retries > MAX_RETRIES) {
157 174 kwoo
              goto retry_jpnt;
158 209 kwoo
          } else {
159
              continue;
160 173 kwoo
          }
161 161 kwoo
      }
162
163 217 kwoo
      send_packet(TT_ACK, addr, NULL, 0);
164 161 kwoo
165 173 kwoo
      // Once we write the last packet we must override the jump to
166
      // user code to point to the correct address
167 161 kwoo
      if (prog_len <= PROGD_PACKET_SIZE) {
168 217 kwoo
          //for (i = 0; i < MAX_PAYLOAD_SIZE; i++) {
169
          //    mbuf[i]= 0;
170
          //}
171 165 kwoo
172 168 kwoo
          mbuf[PROGD_PACKET_SIZE-2] = jbuf.bytes[0];
173
          mbuf[PROGD_PACKET_SIZE-1] = jbuf.bytes[1];
174 165 kwoo
175 168 kwoo
          onboard_program_write(BOOT_START - SPM_PAGESIZE, mbuf);
176 200 kwoo
177 201 kwoo
          // Jump to user code that we just wrote
178
          goto run_user_code;
179 161 kwoo
      } else {
180
          prog_len -= PROGD_PACKET_SIZE;
181
      }
182 154 bneuman
  }
183 171 kwoo
184
  // Should never get here
185 169 kwoo
  return -1;
186 154 bneuman
}