boot.c

来自「MANTIS是由科罗拉多大学开发的传感器网络嵌入式操作系统。 这是mantis」· C语言 代码 · 共 651 行

C
651
字号
//  This file is part of MANTIS OS, Operating System//  See http://mantis.cs.colorado.edu/////  Copyright (C) 2003,2004,2005 University of Colorado, Boulder////  This program is free software; you can redistribute it and/or//  modify it under the terms of the mos license (see file LICENSE)/*  Project Mantis  File: boot.c  Author: Jeff Rose  Date: 3-15-03  A boot loader for the atmega128.  Connects to a program over a serial  connection to allow programming directly over the serial port.*/#include "mos.h"#include <string.h>#include "boot.h"#include "mcs.h"#include "led.h"#include "com.h"#include "boot_serial.h"#include "crc.h"#include <avr/interrupt.h>#include <avr/pgmspace.h>#include <avr/io.h>#include <avr/boot.h>#include "atmel-flash.h"static comBuf in_pkt, out_pkt;static uint16_t crc, crc_index;static uint16_t addr;static uint16_t image_size;static uint16_t page_index, image_index;#define LOOP_VAL 50uint8_t pagebuf[PAGE_SIZE_BYTES]; // A memory buffer for flash page databoot_control_block_t boot_cblock;/** @brief Stub to allow compilation with i2c_eeprom.c. * * This doesn't really do anything. */inline void enable_ints(uint8_t handle){   SREG = handle;}/** @brief Stub to allow compilation with i2c_eeprom.c. * * This doesn't really do anything. */inline uint8_t disable_ints(){   uint8_t sreg = SREG;   cli();   return sreg;}uint16_t avr_eeprom_read_polling (void *buf, uint16_t addr, uint8_t count){   //set up state for interrupt state machine   uint8_t buffer_index = 0;   while (buffer_index < count) {      while (EECR & (1 << EEWE)) //busy wait on EEWE	 ;      EEAR = addr + buffer_index; // Setup the address      EECR |= (1 << EERE); // Set the read strobe           ((uint8_t *)buf)[buffer_index++] = EEDR; // Now read the data   }   return 0;}uint16_t avr_eeprom_write_polling (void *buf, uint16_t addr, uint8_t count){   //set up state for interrupt state machine   uint8_t buffer_index = 0;   while (buffer_index < count) {      while (EECR & (1 << EEWE)) //busy wait on EEWE	 ;      while (SPMCSR & (1 << SPMEN)) // busy wait on SPMEN	 ;      EEAR = addr + buffer_index; // Setup the address      EEDR = ((uint8_t *)buf)[buffer_index++];    // Now write the data      EECR = (1 << EEMWE); //EEMWE bit of the EECR      EECR = (1 << EEMWE) | (1 << EEWE); // Set the write strobe   }   return 0;}void mos_udelay(uint16_t usec){   while(usec > 0) {      asm volatile("nop" ::);      asm volatile("nop" ::);      asm volatile("nop" ::);      asm volatile("nop" ::);      usec--;   }}void atmel_flash_init (){   // set the flash select pin   DDRA |= 1 << ATMEL_FLASH_SELECT_PIN;   // set the pin high   ATMEL_FLASH_SELECT |= 1 << ATMEL_FLASH_SELECT_PIN;   // clear flash clock   ATMEL_FLASH_PORT &= ~(1 << ATMEL_FLASH_CLK);   // set flash clock output direction   ATMEL_FLASH_DIRE |= 1 << ATMEL_FLASH_CLK;   // clear flash out pin   ATMEL_FLASH_PORT &= ~(1 << ATMEL_FLASH_OUT);   // set flash out pin direction   ATMEL_FLASH_DIRE &= ~(1 << ATMEL_FLASH_OUT);   // clear flash in pin   ATMEL_FLASH_PORT |= 1 << ATMEL_FLASH_IN;   // set flash in pin direction   ATMEL_FLASH_DIRE |= 1 << ATMEL_FLASH_IN;   // must wait 20 ms before device is ready to use   mos_udelay (20000);}inline void atmel_flash_low (void) {   // clear flash clock   ATMEL_FLASH_PORT &= ~(1 << ATMEL_FLASH_CLK);   // clear select pin   ATMEL_FLASH_SELECT &= ~(1 << ATMEL_FLASH_SELECT_PIN);}inline void atmel_flash_high (void){   // set the pin high   ATMEL_FLASH_SELECT |= 1 << ATMEL_FLASH_SELECT_PIN;}// 0x11010111, 3 and 5 pin, pull low FLASH_IN and FLASH_CLK  #define BITINIT  uint8_t clrClkAndData = PORTD & ~0x28 // first of all, the data is shifted in in rising edge and out in falling// The I/O address for PORTD is 18, for PIND is 16// first set the clk to low and the input to low, then // check the #n bit in spiOut.  //  if 0,    then skip the step of writing the #n bit in FLASH_IN to high //           else pull the flash_in to high// then set  clk to rising edge// then check whether the FLASH_OUT in PIND is 0// if yes, then skip (i.e. set the spiIn's bit to 0) //         else set the spiIn's bit to 1#define WRITEBIT(n)					\   PORTD = clrClkAndData;				\   asm __volatile__					\   (  "sbrc %2," #n "\n"				\      "\tsbi 18,3\n"					\      "\tsbi 18,5\n"					\      : "=d" (spiIn) : "0" (spiIn), "r" (spiOut))#define READBIT(n)				\   PORTD = clrClkAndData;			\   asm __volatile__				\   ("\tsbi 18,5\n"				\    "\tsbic 16,2\n"				\    "\tori %0,1<<" #n "\n"			\    : "=d" (spiIn) : "0" (spiIn))uint8_t atmel_flash_get_byte (void){   uint8_t spiIn = 0;   BITINIT;   READBIT(7);   READBIT(6);   READBIT(5);   READBIT(4);   READBIT(3);   READBIT(2);   READBIT(1);   READBIT(0);       return spiIn;}uint8_t atmel_flash_send_byte (uint8_t spiOut){   uint8_t spiIn = 0;   BITINIT;   WRITEBIT(7);   WRITEBIT(6);   WRITEBIT(5);   WRITEBIT(4);   WRITEBIT(3);   WRITEBIT(2);   WRITEBIT(1);   WRITEBIT(0);       return spiIn;}/* Directly Read Through the Memory, doesn't change the buffer * It works when writing/reading the characters, but doesn't work * when writing the long data.  Sometimes it just doesn't work * need to use logic analysis figure out later.  */void atmel_flash_read_memory(uint16_t page,			     uint16_t offset, 			     void *reqData, uint32_t len){   uint8_t cmd[8], *reqPtr;   uint32_t i;   cmd[0] = C_READ_THROUGH_MEMORY; // 8 bit of op code   cmd[1] = (page >> 7);           // 4 bit reserve and high 4 MSB   cmd[2] = (page << 1) | offset >> 8;// 7 bit page and 1 bit offset MSB   cmd[3] = offset;         // low-order 8 address bits   cmd[4] = 0x00;   cmd[5] = 0x00;   cmd[6] = 0x00;   cmd[7] = 0x00;   reqPtr = (uint8_t *)reqData;   atmel_flash_low();       for (i = 0; i < sizeof (cmd); i++)      atmel_flash_send_byte(cmd[i]);   for (i = 0; i < len; i++)      reqPtr[i] = atmel_flash_get_byte();       atmel_flash_high();  }uint8_t send_packet(comBuf *pkt){   uint8_t i;   // Send the preamble   for(i = 0; i < PREAMBLE_SIZE; i++)      send_byte(PREAMBLE);   // Now send size and data   send_byte(pkt->size);   for(i = 0; i < pkt->size; i++)      send_byte(pkt->data[i]);   return 0;}uint8_t recv_packet(comBuf *pkt){   uint8_t i;   for(i = 0; i < PREAMBLE_SIZE; i++)      recv_byte();   pkt->size = recv_byte();   for(i = 0; i < pkt->size; i++)      pkt->data[i] = recv_byte();   return 0;}/** @brief Get an address. * * Receives two bytes, sends ADDRESS_RECVD. * @return Address received  */void *flash_address(uint32_t addr){   // Now set RAMPZ if necessary   if(addr > 0xFFFF)      RAMPZ = addr >> 16;   else      RAMPZ = 0;   addr = addr & 0xFFFF;   return (void *)(uint16_t)addr;}/** @brief Receives an image and writes it to flash. */void load_image(comBuf *packet){   uint8_t j;      LED_ON (2);      image_size = *(uint16_t *)(&packet->data[1]);   out_pkt.size = 1;   out_pkt.data[0] = LOAD_ACK;   send_packet (&out_pkt);      image_index = 0; //image index is how many bytes written from the image                    //image size is the total number of bytes in the image   addr = 0;   while (image_index < image_size) {      uint8_t size = 0;      recv_packet(&in_pkt);      //addr = *(uint16_t *)(&in_pkt.data[0]);      addr = image_index /*/ 2*/;      crc = *(uint16_t *)(&in_pkt.data[0]);            // Now get the data packets      page_index = 0; //how many bytes from the current page we've received            while (page_index < PAGE_SIZE_BYTES) { //loop until we have a full page         recv_packet (&in_pkt); //get the packet from the computer	 	 //out_pkt.data[0] = PACKET_ACK;	 //out_pkt.size=1;	 //send_packet (&out_pkt);	 //copy page into buffer         for (j = 0; j < in_pkt.size; j++)             pagebuf[page_index + j] = in_pkt.data[j];          page_index += in_pkt.size;         // If this is the last packet then we break out.         if (in_pkt.size < COM_DATA_SIZE) {            size = in_pkt.size;            break;         }      }            // actually write the page       flash_write_page ((void *)flash_address (addr), pagebuf);      out_pkt.size = 1;            // find out the proper index to pass to crc_compute      if (in_pkt.size < COM_DATA_SIZE)         crc_index = image_size - image_index;      else         crc_index = page_index;            // perform the crc calculation and send off the result             if (crc_compute (pagebuf, crc_index) != crc)         out_pkt.data[0] = CRC_ERROR;      else	 out_pkt.data[0] = CRC_OK;            //out_pkt.data[0] = CRC_OK;      send_packet (&out_pkt);      // finally update the image index       image_index += page_index;   }   out_pkt.size = 1;   out_pkt.data[0] = IMAGE_ACK;   send_packet (&out_pkt);   LED_OFF (2);}/** @brief Sends a byte for each fuse value. */void read_fuses(void){   comBuf pkt;      RAMPZ = 0;      flash_enable_rww(); // Make sure the RWW section is enabled   pkt.size = 4;   pkt.data[0] = flash_read_fuse((void *)0x0000); // Low   pkt.data[1] = flash_read_fuse((void *)0x0003); // High   pkt.data[2] = flash_read_fuse((void *)0x0002); // Extended   pkt.data[3] = flash_read_fuse((void *)0x0001); // Lock bits   send_packet(&pkt);}/** @brief Get a page from flash. */void read_image(void){   comBuf packet;   uint16_t i;   uint16_t addr = 0;   uint16_t word;   flash_address(0x0000); // Set the flash flag to the beginning   flash_enable_rww(); // Make sure the RWW section is enabled   packet.size = 2;   for(i = 0; i < PAGE_SIZE_BYTES; i += 2) {      word = flash_read_word((void *)addr);      send_byte ((uint8_t)(word >> 8));      send_byte ((uint8_t)word);      addr += 2;   }}/** @brief Send a byte as two hex characters. * @param byte The byte to send */void puthex(uint8_t byte){   uint8_t val;   val = byte >> 4;   if(val >= 9)      send_byte('0'+ val);   else      send_byte('A'+ (val - 10));   val = byte & 0x0f;   if(val >= 9)      send_byte('0'+ val);   else      send_byte('A'+ (val - 10));}/** @brief Read the control block in at startup. * @param cb Control block will be read in here */void read_control_block(boot_control_block_t *cb){   // Read from the eeprom boot control block   avr_eeprom_read_polling(cb, CONTROL_BLOCK_ADDR, CONTROL_BLOCK_SIZE);}/** @brief Write control block out to flash. * @param cb Control block to write */void write_control_block(boot_control_block_t *cb){   // Write the page into eeprom   avr_eeprom_write_polling(cb, CONTROL_BLOCK_ADDR,			    CONTROL_BLOCK_SIZE);}void clear_control_block(boot_control_block_t *cb){   cb->reprogram = 0;   write_control_block(cb);}uint8_t control_block_is_sane(boot_control_block_t *cb){   	if (cb->start_addr + cb->byte_count > ATMEL_FLASH_SIZE)   		return 0;   	if (cb->byte_count > 120 * (uint32_t)1024)   		return 0;   	if (cb->reprogram != 0 && cb->reprogram != 1)   		return 0;   	return 1;}/** @brief Copies an image from one part of flash to another. * @param cb The control block */void image_copy(boot_control_block_t *cb){   uint32_t i = 0, size, addr;   atmel_flash_init();   LED_ON (2);   i = 0;   addr = cb->start_addr;   while(i < cb->byte_count) {      uint16_t page = addr / ATMEL_FLASH_PAGE_SIZE;      uint16_t offset = addr % ATMEL_FLASH_PAGE_SIZE;      // read page into page buffer from eeprom      if((cb->byte_count - i) >= PAGE_SIZE_BYTES)	 size = PAGE_SIZE_BYTES;      else 	 size = cb->byte_count - i;      atmel_flash_read_memory(page, offset, pagebuf, size);            // write page into flash memory      boot_spm_busy_wait();      flash_write_page(flash_address(i /*/ 2*/), pagebuf);            i += size;      addr += size;   }   LED_OFF(2);}void send_byte_packet(comBuf *pkt, uint8_t byte){   pkt->size = 1;   pkt->data[0] = byte;   send_packet(pkt);}void send_word_packet(comBuf *pkt, uint16_t word){   pkt->size = 3;   pkt->data[0] = WORD_PRINT;   *((uint16_t *)&pkt->data[0]) = word;   send_packet(pkt);}comBuf pkt;int main(void){   uint8_t val;   uint16_t loop = 0;   uint8_t loop_flag = 0;   void (*reset_func)(void) = (void*)0x00000; // Pointer to normal RESET vector   cli();         // Disable interrupts for the whole boot loader      LED_INIT_HARDWARE();   LED_OFF(0);   LED_OFF(1);   LED_ON(2);   init_serial();      // Send a message to let the shell know we are connected   send_byte_packet(&pkt, LOADER_PRESENT);   // wait for the shell to respond   while(!(val = check_recv())) {      if(loop > 0xf000)	 loop_flag++;      if(loop_flag > LOOP_VAL)	 break;      loop++;   }   LED_OFF(0);   LED_ON(1);   LED_OFF(2);   // see if we need to reprogram   read_control_block(&boot_cblock);   if (!control_block_is_sane(&boot_cblock)) {   		boot_cblock.start_addr = (uint32_t)0;   		boot_cblock.byte_count = (uint32_t)0;   		boot_cblock.reprogram = 0;   		write_control_block(&boot_cblock);   } else if(boot_cblock.reprogram == 1 && val != CLEAR_CB) {      // time to reprogram      boot_lock_bits_set(0);      image_copy(&boot_cblock);      clear_control_block(&boot_cblock);      write_control_block(&boot_cblock);            while(boot_rww_busy())	 boot_rww_enable();      boot_spm_busy_wait();            LED_OFF(0);      LED_OFF(1);      LED_OFF(2);      reset_func();   }   if(loop_flag < LOOP_VAL) { //recvd a byte in the uart      recv_packet(&pkt);        //get the packet      //LED_ON(2);      val = pkt.data[0];        //get the value      if(val != SHELL_PRESENT && val != CLEAR_CB) { //see if byte was shell	 flash_enable_rww();	 while(boot_rww_busy())	    boot_rww_enable();	 boot_spm_busy_wait();	 LED_OFF(0);	 LED_OFF(1);	 LED_OFF(2);	 reset_func();          //start the app if shell not present      } else	 ;//LED_ON(2);   }      if(loop_flag > LOOP_VAL) {      while(boot_rww_busy())	 boot_rww_enable();      boot_spm_busy_wait();      LED_OFF(0);      LED_OFF(1);      LED_OFF(2);      reset_func();   }   // shell must be present   while(1) {      recv_packet(&pkt);      val = pkt.data[0];      switch(val) {      case LOAD_IMAGE: // load a new image	 LED_ON(0);         load_image(&pkt);	 break;      case READ_FUSES:         read_fuses();	 break;      case READ_FLASH:	 read_image();	 break;      case CLEAR_CB:	 read_control_block(&boot_cblock);         clear_control_block(&boot_cblock);	 send_byte_packet(&pkt, CLEAR_CB_PONG);	 break;      case START:         flash_enable_rww (); // Make sure the RWW section is enabled	 while(boot_rww_busy())	    boot_rww_enable();	 boot_spm_busy_wait();	 send_byte_packet(&pkt, START);	 LED_OFF(0);	 LED_OFF(1);	 LED_OFF(2);	 reset_func();      //jump to the application	 break;      case SHELL_PRESENT:	 LED_ON (1);	 send_byte_packet(&pkt, LOADER_PRESENT_PONG);	 break;      default:	 send_byte_packet(&pkt, UNKNOWN);	 break;      }   }   LED_OFF(0);   LED_OFF(1);   LED_OFF(2);      return 0;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?