Project

General

Profile

Statistics
| Revision:

root / trunk / bootloader / bootloader.c @ 195

History | View | Annotate | Download (4.34 KB)

1
#include "bootloader.h"
2

    
3
// Setup the default fuses
4
FUSES = {
5
    .low = (FUSE_SUT0 & FUSE_CKSEL3 & FUSE_CKSEL2 & FUSE_CKSEL0),
6
    .high = (FUSE_EESAVE & FUSE_SPIEN),
7
    .extended = (FUSE_SELFPRGEN),
8
};
9

    
10

    
11

    
12
// Error thresholds
13
#define MAX_RETRIES 5       // Number of times to retry before giving up
14

    
15
//Status LED
16
#define LED_DDR  DDRB
17
#define LED_PORT PORTB
18
#define LED      PORTB1
19

    
20
/**
21
 * Where we store the jump to user code. The jump address is in words
22
 * due to how the rjmp instruction works. It is 1 word below the bootloader
23
 */
24
void (*main_start)(void) = BOOT_START/2 - 1;
25

    
26
/**
27
 * We declare main as naked so that there is no overhead for entering
28
 * and returning from this function since we don't really care about
29
 * what happens to it after we leave it
30
 */
31
int main(void) __attribute__ ((naked));
32

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

    
38
/** 
39
 * Restore the reset vector to point to the end of ctors. This
40
 * is because we are stripping out the interrupt vector table
41
 * from the bootloader as we don't use it.
42
 */
43
void ResetVector (void) __attribute__((naked))
44
                        __attribute__((section(".reset")));
45
void ResetVector(void) {
46
    asm("rjmp __ctors_end");
47
}
48

    
49

    
50
// SPM_PAGESIZE is set to 32 bytes
51
void onboard_program_write(uint16_t page, uint8_t *buf) {
52
  uint16_t i;
53

    
54
  boot_page_erase (page);
55
  boot_spm_busy_wait ();      // Wait until the memory is erased.
56

    
57
  for (i=0; i < SPM_PAGESIZE; i+=2){
58
    // Set up little-endian word.
59
    boot_page_fill (page + i, buf[i] | (buf[i+1] <<8));
60
  }
61

    
62
  boot_page_write (page);     // Store buffer in flash page.
63
  boot_spm_busy_wait();       // Wait until the memory is written.
64
}
65

    
66
int main(void) {
67
  uint8_t mbuf[PROGD_PACKET_SIZE];
68
  rjump_t jbuf;
69
  uint16_t caddr = MAIN_ADDR;
70
  uint8_t iteration;
71
  uint8_t resp;
72
  uint16_t prog_len;
73
  uint8_t i;
74
  uint8_t retries;
75

    
76
retry_jpnt:
77
  iteration = 0;
78
  retries = 0;
79
  
80
  // Clear the watchdog timer
81
  MCUSR &= ~_BV(WDRF);
82
  wdt_disable();
83
  WDTCSR = 0;
84

    
85

    
86
  rs485_init(51); //MAGIC NUMBER??
87

    
88
  //set LED pin as output
89
  LED_DDR |= 0x07;
90
  PORTB = 0x07;
91

    
92
  //Start bootloading process
93
  send_packet(TT_BOOT);
94

    
95
  resp = parse_packet(mbuf);
96

    
97
  // Enter programming mode 
98
  if (resp == TT_PROGM) {
99
    prog_len = mbuf[0];
100
    prog_len |= mbuf[1] << 8;
101

    
102
    // This will insert a NOP into the user code jump in case
103
    // the programming fails
104
    for (i = 0; i < PROGD_PACKET_SIZE; i++) {
105
      mbuf[i]= 0;
106
    }
107
    onboard_program_write(BOOT_START - SPM_PAGESIZE, mbuf);
108

    
109
  // Run user code
110
  } else {
111
      main_start();
112
  }
113

    
114
  send_packet(TT_ACK);
115

    
116
  while(1) {
117
      resp = parse_packet(mbuf);
118

    
119
      if (resp == TT_PROGD) {
120
          // We need to muck with the reset vector jump in the first page
121
          if (iteration == 0) {
122
              // Store the jump to user code
123
              jbuf.bytes[0] = mbuf[0];
124
              jbuf.bytes[1] = mbuf[1];
125
             
126
              // Rewrite the user code jump to be correct since we are
127
              // using relative jumps (rjmp)
128
              jbuf.sword &= 0x0FFF;
129
              jbuf.sword -= (BOOT_START >> 1) - 1;
130
              jbuf.sword &= 0x0FFF;
131
              jbuf.sword |= 0xC000;
132

    
133
              // Rewrite the reset vector to jump to the bootloader
134
              mbuf[0] = (BOOT_START/2 - 1) & 0xFF;
135
              mbuf[1] = 0xC0 | (((BOOT_START/2 - 1) >> 8) & 0x0F);
136

    
137
              iteration = 1;
138
          }
139

    
140
          // Write the page to the flash
141
          onboard_program_write(caddr, mbuf);
142
          caddr += PROGD_PACKET_SIZE;
143
          retries = 0;
144
      } else {
145
          send_packet(TT_NACK);
146
          retries++;
147

    
148
          // If we failed too many times, reset. This goes to the start
149
          // of the bootloader function
150
          if (retries > MAX_RETRIES) {
151
              goto retry_jpnt;
152
          }
153
      }
154

    
155
      send_packet(TT_ACK);
156

    
157
      // Once we write the last packet we must override the jump to
158
      // user code to point to the correct address
159
      if (prog_len <= PROGD_PACKET_SIZE) {
160
          for (i = 0; i < PROGD_PACKET_SIZE; i++) {
161
              mbuf[i]= 0;
162
          }
163

    
164
          mbuf[PROGD_PACKET_SIZE-2] = jbuf.bytes[0];
165
          mbuf[PROGD_PACKET_SIZE-1] = jbuf.bytes[1];
166

    
167
          onboard_program_write(BOOT_START - SPM_PAGESIZE, mbuf);
168

    
169
          main_start();
170
      } else { 
171
          prog_len -= PROGD_PACKET_SIZE;
172
      }
173
  }
174

    
175
  // Should never get here
176
  return -1;
177
}