Project

General

Profile

Revision 158

Added by Kevin Woo about 14 years ago

Bootloader state machine and rudimentary programming, can receive program but doesn't actually program

View differences:

bootloader.c
14 14

  
15 15

  
16 16
#define MAX_WAIT_IN_CYCLES 800000
17
#define MAX_TIMEOUT 60000        // Seconds to wait before exiting bootloader mode
17 18

  
18 19
//Status LED
19 20
#define LED_DDR  DDRB
......
24 25

  
25 26
//Function prototypes
26 27
void flash_led(uint8_t);
27
void onboard_program_write(uint32_t page, uint8_t *buf);
28
void onboard_program_write(uint32_t page, uint8_t *buf, uint8_t offset);
28 29
void (*main_start)(void) = 0x0000;
29 30

  
30 31
//Variables
......
32 33
uint8_t page_length;
33 34
uint8_t retransmit_flag = FALSE;
34 35

  
36
uint8_t sec;
37
uint8_t min;
38

  
35 39
union page_address_union {
36 40
  uint16_t word;
37 41
  uint8_t  byte[2];
......
49 53
    ack
50 54
} state_t;
51 55

  
56
void init_timer(void) {
57
    // Clear timmer on OCRA1 Compare match
58
    // No prescale
59
    TCCR1B |= _BV(WGM12) | _BV(CS12);
60
    
61
    // 1 second @ 8MHz clock
62
    OCR1AH =0x7A;
63
    OCR1AL =0x12;
52 64

  
53
char parse_packet(char *mbuf) {
54
  uint8_t r;        // Byte from the network
55
  uint8_t crc;      // Running checksum of the packet
56
  uint8_t cmd;      // The command received
57
  uint8_t pos;      // Position in the message buffer
58
  uint8_t lim;      // Max number of bytes to read into the message buf
59
  state_t state;    // State machine
65
    TIMSK = _BV(OCIE1A);
60 66

  
67
    sec = 0;
68
    min = 0;
69
}
70

  
71
void reset_timer(void) {
72
    sec = 0;
73
    min = 0;
74
}
75

  
76
ISR(TIMER1_COMPA_vect) {
77
    if (sec == 59) {
78
        sec = 0;
79
        min++;
80
    } else {
81
        sec++;
82
    }
83
}
84

  
85
char parse_packet(uint8_t *mbuf) {
86
  uint8_t r = 0;        // Byte from the network
87
  uint8_t crc = 0;      // Running checksum of the packet
88
  uint8_t cmd = 0;      // The command received
89
  uint8_t pos = 0;      // Position in the message buffer
90
  uint8_t lim = 0;      // Max number of bytes to read into the message buf
91
  state_t state = sd;    // State machine
92
    uint16_t count;
93
  //reset_timer();
94
  count = 0;
95

  
61 96
  while (1) {
62 97
    // Wait for the next byte
63
    while ((uart_get_byte(&r)) < 0);
98
    while ((uart_get_byte(&r)) < 0) {
99
        //if (count >= MAX_TIMEOUT) {
100
        //    return TT_BAD;
101
       //}
102
    }
64 103

  
65 104
    switch (state) {
66 105
        case sd:
......
132 171
  }
133 172
}
134 173

  
135
void send_ack(void) {
174
void send_packet(uint8_t cmd) {
136 175
    uart_send_byte(DELIM);
137 176
    uart_send_byte(ADDR);
138 177
    uart_send_byte(SERVER);
139
    uart_send_byte(TT_ACK);
140
    uart_send_byte(ACK_CRC);
178
    uart_send_byte(cmd);
179
    uart_send_byte(ACK_CRC ^ cmd);
141 180
}
142 181

  
143 182
int main(void)
144 183
{
184
    uint8_t mbuf[PROGD_PACKET_SIZE];
145 185
  uint8_t check_sum = 0;
146 186
  uint16_t i;
147 187

  
188
  uint8_t resp;
189
  uint16_t prog_len;
190

  
148 191
  init_uart(51); //MAGIC NUMBER??
192
  init_timer();
193
  sei();
149 194

  
150 195
  //set LED pin as output
151 196
  LED_DDR |= _BV(LED);
197
  PORTB |= _BV(LED);
152 198

  
153 199
  //flash onboard LED to signal entering of bootloader
154
  flash_led(1);
200
  //flash_led(1);
155 201

  
156 202
  //Start bootloading process
157
   uart_send_byte(5); //Tell the world we can be bootloaded
203
  send_packet(TT_BOOT);
158 204

  
159
  //Check to see if the computer responded
160
  uint32_t count = 0;
161
  uint8_t resp;
162

  
163
  while(uart_get_byte(&resp) == -1) {
164
    count++;
165
    if (count > MAX_WAIT_IN_CYCLES)
166
      //TODO: flash some leds or something
167
      main_start();
205
  resp = parse_packet(mbuf);
206
  if (resp == TT_PROGM) {
207
    prog_len = mbuf[0];
208
    prog_len |= mbuf[1] << 8;
209
  } else {
210
      while(1) {
211
          flash_led(1);
212
      }
213
      //main_start();
168 214
  }
215
  send_packet(TT_ACK);
169 216

  
170
  /* If the computer did not respond correctly with a ACK, we jump to
171
   * user's program
172
   */
173
  if(resp != 6)
174
    main_start(); 
175

  
176 217
  while(1) {
177
    //Determine if the last received data was good or bad
178
    if (check_sum != 0) //If the check sum does not compute, tell computer to resend same line
179
    RESTART:
180
      uart_send_byte(7); //Ascii character BELL
181
    else            
182
      uart_send_byte('T'); //Tell the computer that we are ready for the next line
183
        
184
    while(1) {//Wait for the computer to initiate transfer
185
      if (getch() == ':') break; //This is the "gimme the next chunk" command
186
      if (retransmit_flag == TRUE) goto RESTART;
187
    }
218
      resp = parse_packet(mbuf);
188 219

  
189
    page_length = getch(); //Get the length of this block
190
    if (retransmit_flag == TRUE) goto RESTART;
191
    if(page_length > PAGE_SIZE) {
192
      while(1) {
193
	flash_led(1);
194
      }
195
    }
196

  
197
    if (page_length == 'S') {//Check to see if we are done - this is the "all done" command
198
      //boot_rww_enable (); //Wait for any flash writes to complete?
199
      main_start(); 
200
    }
201
	
202
    //Get the memory address at which to store this block of data
203
    page_address.byte[0] = getch(); if (retransmit_flag == TRUE) goto RESTART;
204
    page_address.byte[1] = getch(); if (retransmit_flag == TRUE) goto RESTART;
205

  
206
    check_sum = getch(); //Pick up the check sum for error dectection
207
    if (retransmit_flag == TRUE) goto RESTART;
208
		
209
    for(i = 0 ; i < page_length ; i++) {//Read the program data
210
      incoming_page_data[i] = getch();
211
      if (retransmit_flag == TRUE) goto RESTART;
212
    }
213
        
214
    //Calculate the checksum
215
    for(i = 0 ; i < page_length ; i++)
216
      check_sum = check_sum + incoming_page_data[i];
217
        
218
    check_sum = check_sum + page_length;
219
    check_sum = check_sum + page_address.byte[0];
220
    check_sum = check_sum + page_address.byte[1];
221
		
222
    if(check_sum == 0) //If we have a good transmission, put it in ink
223
      onboard_program_write((uint32_t)page_address.word, incoming_page_data);
220
      //if (resp == TT_PROGD) {
221
      //    onboard_program_write((uint32_t)page_address.word, incoming_page_data);
222
      //}
223
      send_packet(TT_ACK);
224 224
  }
225 225

  
226 226
}
227 227

  
228 228
//#define SPM_PAGESIZE 128
229
void onboard_program_write(uint32_t page, uint8_t *buf)
229
void onboard_program_write(uint32_t page, uint8_t *buf, uint8_t offset)
230 230
{
231 231
  uint16_t i;
232
	//uint8_t sreg;
233 232

  
234
	// Disable interrupts.
235

  
236
	//sreg = SREG;
237
	//cli();
238

  
239
	//eeprom_busy_wait ();
240

  
241 233
  boot_page_erase (page);
242 234
  boot_spm_busy_wait ();      // Wait until the memory is erased.
243 235

  
244
  for (i=0; i<SPM_PAGESIZE; i+=2){
236
  for (i=offset; i < SPM_PAGESIZE; i+=2){
245 237
    // Set up little-endian word.
246 238

  
247 239
    uint16_t w = *buf++;
......
252 244

  
253 245
  boot_page_write (page);     // Store buffer in flash page.
254 246
  boot_spm_busy_wait();       // Wait until the memory is written.
255

  
256
	// Reenable RWW-section again. We need this if we want to jump back
257
	// to the application after bootloading.
258

  
259
	//boot_rww_enable ();
260

  
261
	// Re-enable interrupts (if they were ever enabled).
262

  
263
	//SREG = sreg;
264 247
}
265 248

  
266 249
char getch(void) {

Also available in: Unified diff