Project

General

Profile

Statistics
| Revision:

root / trunk / bootloader / bootloader.c @ 197

History | View | Annotate | Download (3.97 KB)

1
#include "bootloader.h"
2

    
3
// Setup the default fuses
4
// This seems to be broken for now...
5
/*
6
FUSES = {
7
    .low = (FUSE_SUT0 & FUSE_CKSEL3 & FUSE_CKSEL2 & FUSE_CKSEL0),
8
    .high = (FUSE_EESAVE & FUSE_SPIEN),
9
    .extended = (FUSE_SELFPRGEN)
10
};
11
*/
12

    
13

    
14

    
15
// Error thresholds
16
#define MAX_RETRIES 5       // Number of times to retry before giving up
17

    
18
//Status LED
19
#define LED_DDR  DDRB
20
#define LED_PORT PORTB
21
#define LED      PORTB1
22

    
23
/**
24
 * Where we store the jump to user code. The jump address is in words
25
 * due to how the rjmp instruction works. It is 1 word below the bootloader
26
 * We declare it as noreturn to save some space since we will never return
27
 * to the bootloader unless we do a system reset
28
 */
29
void (*main_start)(void) __attribute__((noreturn)) = BOOT_START/2 - 1;
30

    
31
typedef union {
32
    uint8_t bytes[2];
33
    int16_t sword;
34
} rjump_t;
35

    
36

    
37
// SPM_PAGESIZE is set to 32 bytes
38
void onboard_program_write(uint16_t page, uint8_t *buf) {
39
  uint16_t i;
40

    
41
  boot_page_erase (page);
42
  boot_spm_busy_wait ();      // Wait until the memory is erased.
43

    
44
  for (i=0; i < SPM_PAGESIZE; i+=2){
45
    // Set up little-endian word.
46
    boot_page_fill (page + i, buf[i] | (buf[i+1] <<8));
47
  }
48

    
49
  boot_page_write (page);     // Store buffer in flash page.
50
  boot_spm_busy_wait();       // Wait until the memory is written.
51
}
52

    
53
int main(void) {
54
  uint8_t mbuf[PROGD_PACKET_SIZE];
55
  rjump_t jbuf;
56
  uint16_t caddr = MAIN_ADDR;
57
  uint8_t iteration;
58
  uint8_t resp;
59
  uint16_t prog_len;
60
  uint8_t i;
61
  uint8_t retries;
62

    
63
retry_jpnt:
64
  iteration = 0;
65
  retries = 0;
66
  
67
  // Clear the watchdog timer
68
  MCUSR &= ~_BV(WDRF);
69
  wdt_disable();
70
  WDTCSR = 0;
71

    
72

    
73
  rs485_init(51); //MAGIC NUMBER??
74

    
75
  //set LED pin as output
76
  LED_DDR |= 0x07;
77
  PORTB = 0x07;
78

    
79
  //Start bootloading process
80
  send_packet(TT_BOOT);
81

    
82
  resp = parse_packet(mbuf);
83

    
84
  // Enter programming mode 
85
  if (resp == TT_PROGM) {
86
    prog_len = mbuf[0];
87
    prog_len |= mbuf[1] << 8;
88

    
89
    // This will insert a NOP into the user code jump in case
90
    // the programming fails
91
    for (i = 0; i < PROGD_PACKET_SIZE; i++) {
92
      mbuf[i]= 0;
93
    }
94
    onboard_program_write(BOOT_START - SPM_PAGESIZE, mbuf);
95

    
96
  // Run user code
97
  } else {
98
      main_start();
99
  }
100

    
101
  send_packet(TT_ACK);
102

    
103
  while(1) {
104
      resp = parse_packet(mbuf);
105

    
106
      if (resp == TT_PROGD) {
107
          // We need to muck with the reset vector jump in the first page
108
          if (iteration == 0) {
109
              // Store the jump to user code
110
              jbuf.bytes[0] = mbuf[0];
111
              jbuf.bytes[1] = mbuf[1];
112
             
113
              // Rewrite the user code jump to be correct since we are
114
              // using relative jumps (rjmp)
115
              jbuf.sword &= 0x0FFF;
116
              jbuf.sword -= (BOOT_START >> 1) - 1;
117
              jbuf.sword &= 0x0FFF;
118
              jbuf.sword |= 0xC000;
119

    
120
              // Rewrite the reset vector to jump to the bootloader
121
              mbuf[0] = (BOOT_START/2 - 1) & 0xFF;
122
              mbuf[1] = 0xC0 | (((BOOT_START/2 - 1) >> 8) & 0x0F);
123

    
124
              iteration = 1;
125
          }
126

    
127
          // Write the page to the flash
128
          onboard_program_write(caddr, mbuf);
129
          caddr += PROGD_PACKET_SIZE;
130
          retries = 0;
131
      } else {
132
          send_packet(TT_NACK);
133
          retries++;
134

    
135
          // If we failed too many times, reset. This goes to the start
136
          // of the bootloader function
137
          if (retries > MAX_RETRIES) {
138
              goto retry_jpnt;
139
          }
140
      }
141

    
142
      send_packet(TT_ACK);
143

    
144
      // Once we write the last packet we must override the jump to
145
      // user code to point to the correct address
146
      if (prog_len <= PROGD_PACKET_SIZE) {
147
          for (i = 0; i < PROGD_PACKET_SIZE; i++) {
148
              mbuf[i]= 0;
149
          }
150

    
151
          mbuf[PROGD_PACKET_SIZE-2] = jbuf.bytes[0];
152
          mbuf[PROGD_PACKET_SIZE-1] = jbuf.bytes[1];
153

    
154
          onboard_program_write(BOOT_START - SPM_PAGESIZE, mbuf);
155

    
156
          main_start();
157
      } else { 
158
          prog_len -= PROGD_PACKET_SIZE;
159
      }
160
  }
161

    
162
  // Should never get here
163
  return -1;
164
}