Example #1
0
static void programPage(uint16_t page, uint8_t *buf) {
	// these function calls use "out" commands: save some bytes and cycles :)
	__boot_page_erase_short(page);
	boot_spm_busy_wait();
	for (uint16_t i = 0; i < SPM_PAGESIZE; i += 2) {
		uint16_t data_word = *buf++;
		data_word += (*buf++) << 8;
		__boot_page_fill_short(page + i, data_word);
	}
	__boot_page_write_short(page);
	boot_spm_busy_wait();
	__boot_rww_enable_short();
}
/* main program starts here */
int main(void) {
  uint8_t ch;

  /*
   * Making these local and in registers prevents the need for initializing
   * them, and also saves space because code no longer stores to memory.
   * (initializing address keeps the compiler happy, but isn't really
   *  necessary, and uses 4 bytes of flash.)
   */
  register uint16_t address = 0;
  register uint8_t  length;

  // After the zero init loop, this is the first code to run.
  //
  // This code makes the following assumptions:
  //  No interrupts will execute
  //  SP points to RAMEND
  //  r1 contains zero
  //
  // If not, uncomment the following instructions:
  // cli();
  asm volatile ("clr __zero_reg__");
#ifdef __AVR_ATmega8__
  SP=RAMEND;  // This is done by hardware reset
#endif

  // Adaboot no-wait mod
  ch = MCUSR;
  MCUSR = 0;
  if (!(ch & _BV(EXTRF))) appStart();

#if LED_START_FLASHES > 0
  // Set up Timer 1 for timeout counter
  TCCR1B = _BV(CS12) | _BV(CS10); // div 1024
#endif
#ifndef SOFT_UART
#ifdef __AVR_ATmega8__
  UCSRA = _BV(U2X); //Double speed mode USART
  UCSRB = _BV(RXEN) | _BV(TXEN);  // enable Rx & Tx
  UCSRC = _BV(URSEL) | _BV(UCSZ1) | _BV(UCSZ0);  // config USART; 8N1
  UBRRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 );
#else
  UCSR0A = _BV(U2X0); //Double speed mode USART0
  UCSR0B = _BV(RXEN0) | _BV(TXEN0);
  UCSR0C = _BV(UCSZ00) | _BV(UCSZ01);
  UBRR0L = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 );
#endif
#endif

  // Set up watchdog to trigger after 500ms
  watchdogConfig(WATCHDOG_1S);

  /* Set LED pin as output */
  LED_DDR |= _BV(LED);

#ifdef SOFT_UART
  /* Set TX pin as output */
  UART_DDR |= _BV(UART_TX_BIT);
#endif

#if LED_START_FLASHES > 0
  /* Flash onboard LED to signal entering of bootloader */
  flash_led(LED_START_FLASHES * 2);
#endif

  /* Forever loop */
  for (;;) {
    /* get character from UART */
    ch = getch();

    if(ch == STK_GET_PARAMETER) {
      unsigned char which = getch();
      verifySpace();
      if (which == 0x82) {
        /*
         * Send optiboot version as "minor SW version"
         */
        putch(OPTIBOOT_MINVER);
      } else if (which == 0x81) {
          putch(OPTIBOOT_MAJVER);
      } else {
        /*
         * GET PARAMETER returns a generic 0x03 reply for
         * other parameters - enough to keep Avrdude happy
         */
        putch(0x03);
      }
    }
    else if(ch == STK_SET_DEVICE) {
      // SET DEVICE is ignored
      getNch(20);
    }
    else if(ch == STK_SET_DEVICE_EXT) {
      // SET DEVICE EXT is ignored
      getNch(5);
    }
    else if(ch == STK_LOAD_ADDRESS) {
      // LOAD ADDRESS
      uint16_t newAddress;
      newAddress = getch();
      newAddress = (newAddress & 0xff) | (getch() << 8);
#ifdef RAMPZ
      // Transfer top bit to RAMPZ
      RAMPZ = (newAddress & 0x8000) ? 1 : 0;
#endif
      newAddress += newAddress; // Convert from word address to byte address
      address = newAddress;
      verifySpace();
    }
    else if(ch == STK_UNIVERSAL) {
      // UNIVERSAL command is ignored
      getNch(4);
      putch(0x00);
    }
    /* Write memory, length is big endian and is in bytes */
    else if(ch == STK_PROG_PAGE) {
      // PROGRAM PAGE - we support flash programming only, not EEPROM
      uint8_t *bufPtr;
      uint16_t addrPtr;

      getch();                  /* getlen() */
      length = getch();
      getch();

      // If we are in RWW section, immediately start page erase
      if (address < NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address);

      // While that is going on, read in page contents
      bufPtr = buff;
      do *bufPtr++ = getch();
      while (--length);

      // If we are in NRWW section, page erase has to be delayed until now.
      // Todo: Take RAMPZ into account
      if (address >= NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address);

      // Read command terminator, start reply
      verifySpace();

      // If only a partial page is to be programmed, the erase might not be complete.
      // So check that here
      boot_spm_busy_wait();

#ifdef VIRTUAL_BOOT_PARTITION
      if ((uint16_t)(void*)address == 0) {
        // This is the reset vector page. We need to live-patch the code so the
        // bootloader runs.
        //
        // Move RESET vector to WDT vector
        uint16_t vect = buff[0] | (buff[1]<<8);
        rstVect = vect;
        wdtVect = buff[8] | (buff[9]<<8);
        vect -= 4; // Instruction is a relative jump (rjmp), so recalculate.
        buff[8] = vect & 0xff;
        buff[9] = vect >> 8;

        // Add jump to bootloader at RESET vector
        buff[0] = 0x7f;
        buff[1] = 0xce; // rjmp 0x1d00 instruction
      }
#endif

      // Copy buffer into programming buffer
      bufPtr = buff;
      addrPtr = (uint16_t)(void*)address;
      ch = SPM_PAGESIZE / 2;
      do {
        uint16_t a;
        a = *bufPtr++;
        a |= (*bufPtr++) << 8;
        __boot_page_fill_short((uint16_t)(void*)addrPtr,a);
        addrPtr += 2;
      } while (--ch);

      // Write from programming buffer
      __boot_page_write_short((uint16_t)(void*)address);
      boot_spm_busy_wait();

#if defined(RWWSRE)
      // Reenable read access to flash
      boot_rww_enable();
#endif

    }
Example #3
0
void CheckFlashImage() {
	#ifdef DEBUG_ON
	putch('F');
	#endif
	watchdogConfig(WATCHDOG_OFF);

	
	#ifdef ANARDUINO
	#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__)
	DDRB |= _BV(SS) | _BV(PINB3) | _BV(PINB5); //OUTPUTS for SS, MOSI, SCK
	DDRD |= _BV(FLASHSS); //OUTPUTS for FLASH_SS
	FLASH_UNSELECT; //unselect FLASH chip
	PORTB |= _BV(SS); //set SS HIGH
	#elif defined (__AVR_ATmega1284P__) || defined (__AVR_ATmega644P__)
	DDRC |= _BV(FLASHSS); //OUTPUT for FLASH_SS
	DDRB |= _BV(SS) | _BV(PB5) | _BV(PB7); //OUTPUTS for SS, MOSI, SCK
	FLASH_UNSELECT; //unselect FLASH chip
	PORTB |= _BV(SS); //set SS HIGH
	#endif
	#else	//MOTEINO
	//SPI INIT
	#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__)
	DDRB |= _BV(FLASHSS) | _BV(SS) | _BV(PINB3) | _BV(PINB5); //OUTPUTS for FLASH_SS and SS, MOSI, SCK
	FLASH_UNSELECT; //unselect FLASH chip
	PORTB |= _BV(SS); //set SS HIGH
	#elif defined (__AVR_ATmega1284P__) || defined (__AVR_ATmega644P__)
	DDRC |= _BV(FLASHSS); //OUTPUT for FLASH_SS
	DDRB |= _BV(SS) | _BV(PB5) | _BV(PB7); //OUTPUTS for SS, MOSI, SCK
	FLASH_UNSELECT; //unselect FLASH chip
	PORTB |= _BV(SS); //set SS HIGH
	#endif
	#endif	// MOTEINO*/
	
	//SPCR &= ~(_BV(DORD)); //MSB first
	//SPCR = (SPCR & ~SPI_MODE_MASK) | SPI_MODE0 ; //SPI MODE 0
	//SPCR = (SPCR & ~SPI_CLOCK_MASK) | (SPI_CLOCK_DIV2 & SPI_CLOCK_MASK); //clock divider = 2
	//SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((SPI_CLOCK_DIV2 >> 2) & SPI_2XCLOCK_MASK);

	// Warning: if the SS pin ever becomes a LOW INPUT then SPI automatically switches to Slave, so the data direction of the SS pin MUST be kept as OUTPUT.
	SPCR |= _BV(MSTR) | _BV(SPE); //enable SPI and set SPI to MASTER mode

	//read first byte of JEDECID, if chip is present it should return a non-0 and non-FF value
	//FLASH_SELECT;
	FLASH_command(SPIFLASH_JEDECID,1);
	uint8_t deviceId = SPI_transfer(0);
	FLASH_UNSELECT;
	#ifdef DEBUG_ON
		putch(deviceId);
	#endif
	// Disabled check, as it only returns 0xFF or 0x00 for some reasons
	if (deviceId==0 || deviceId==0xFF) return;
	
	//global unprotect
	FLASH_command(SPIFLASH_STATUSWRITE, 1);
	SPI_transfer(0);
	FLASH_UNSELECT;
	#ifdef DEBUG_ON
	putch('I');
	#endif
	//check if any flash image exists on external FLASH chip
	if (FLASH_readByte(0)=='F' && FLASH_readByte(1)=='L' && FLASH_readByte(2)=='X' && FLASH_readByte(6)==':' && FLASH_readByte(9)==':')
	{
		#ifdef DEBUG_ON
		putch('L');
		#endif
		
		uint16_t imagesize = (FLASH_readByte(7)<<8) | FLASH_readByte(8);
		if (imagesize%2!=0) return; //basic check that we got even # of bytes
		
		uint16_t b, i, nextAddress=0;
		
		LED_PIN |= _BV(LED);
		for (i=0; i<imagesize; i+=2)
		{
			#ifdef DEBUG_ON
			putch('*');
			#endif
			
			//read 2 bytes (16 bits) from flash image, transfer them to page buffer
			b = FLASH_readByte(i+10); // flash image starts at position 10 on the external flash memory: FLX:XX:FLASH_IMAGE_BYTES_HERE...... (XX = two size bytes)
			b |= FLASH_readByte(i+11) << 8; //bytes are stored big endian on external flash, need to flip the bytes to little endian for transfer to internal flash
			__boot_page_fill_short((uint16_t)(void*)i,b);

			//when 1 page is full (or we're on the last page), write it to the internal flash memory
			if ((i+2)%SPM_PAGESIZE==0 || (i+2==imagesize))
			{
				__boot_page_erase_short((uint16_t)(void*)nextAddress); //(i+2-SPM_PAGESIZE)
				boot_spm_busy_wait();
				// Write from programming buffer
				__boot_page_write_short((uint16_t)(void*)nextAddress ); //(i+2-SPM_PAGESIZE)
				boot_spm_busy_wait();
				nextAddress += SPM_PAGESIZE;
			}
		}
		LED_PIN &= ~_BV(LED);

		#if defined(RWWSRE)
		// Reenable read access to flash
		boot_rww_enable();
		#endif

		#ifdef DEBUG_ON
		putch('E');
		#endif

		#ifdef ANARDUINO
		// Anarduino doesn't support 32K block erase. Do it, with 8 pages of 4k each
		int page;
		long address;
		for (page = 0, address=0; page< 8; page++) {
			FLASH_command(SPIFLASH_BLOCKERASE_4K, 1);
			SPI_transfer(address >> 16);
			SPI_transfer(address >> 8);
			SPI_transfer(address);
			FLASH_UNSELECT;
			
			while (FLASH_busy());

			address += 0x1000;
		}
		#else // MOTEINO
		//erase the first 32/64K block where flash image resided (atmega328 should be less than 31K, and atmega1284 can be up to 64K)
		if (imagesize+10<=32768) FLASH_command(SPIFLASH_BLOCKERASE_32K, 1);
		else FLASH_command(SPIFLASH_BLOCKERASE_64K, 1);
		SPI_transfer(0);
		SPI_transfer(0);
		SPI_transfer(0);
		#endif
		FLASH_UNSELECT;


		//now trigger a watchdog reset
		watchdogConfig(WATCHDOG_16MS);  // short WDT timeout
		while (1); 		                  // and busy-loop so that WD causes a reset and app start
	}
Example #4
0
void CheckFlashImage() {
#ifdef DEBUG_ON
  putch('F');
#endif
  watchdogConfig(WATCHDOG_OFF);
  
  //SPI INIT
  FLASHSS_DDR |= _BV(FLASHSS) | _BV(SS) | _BV(PB3) | _BV(PB5); //OUTPUTS for D8 and D10, MOSI, SCK
  FLASH_UNSELECT; //unselect FLASH chip
  PINB |= _BV(SS); //set D10 HIGH
  
  //SPCR &= ~(_BV(DORD)); //MSB first
  //SPCR = (SPCR & ~SPI_MODE_MASK) | SPI_MODE0 ; //SPI MODE 0
  //SPCR = (SPCR & ~SPI_CLOCK_MASK) | (SPI_CLOCK_DIV2 & SPI_CLOCK_MASK); //clock divider = 2
  //SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((SPI_CLOCK_DIV2 >> 2) & SPI_2XCLOCK_MASK);

  // Warning: if the SS pin ever becomes a LOW INPUT then SPI automatically switches to Slave, so the data direction of the SS pin MUST be kept as OUTPUT.
  SPCR |= _BV(MSTR) | _BV(SPE); //enable SPI and set SPI to MASTER mode

  //read first byte of JEDECID, if chip is present it should return a non-0 and non-FF value
  FLASH_SELECT;
  SPI_transfer(SPIFLASH_JEDECID);
  uint8_t deviceId = SPI_transfer(0);
  FLASH_UNSELECT;
  if (deviceId==0 || deviceId==0xFF) return;
  
  //global unprotect  
  FLASH_command(SPIFLASH_STATUSWRITE, 1);
  SPI_transfer(0);
  FLASH_UNSELECT;
  
  //check if any flash image exists on external FLASH chip
  if (FLASH_readByte(0)=='F' && FLASH_readByte(1)=='L' && FLASH_readByte(2)=='X' && FLASH_readByte(6)==':' && FLASH_readByte(9)==':')
  {
#ifdef DEBUG_ON
    putch('L');
#endif
    
    uint16_t imagesize = (FLASH_readByte(7)<<8) | FLASH_readByte(8);
    if (imagesize%2!=0) return; //basic check that we got even # of bytes
    
    uint16_t b, i, nextAddress=0;
    
    LED_PIN |= _BV(LED);
    for (i=0; i<imagesize; i+=2)
    {
#ifdef DEBUG_ON
      putch('*');
#endif
      
      //read 2 bytes (16 bits) from flash image, transfer them to page buffer
      b = FLASH_readByte(i+10); // flash image starts at position 10 on the external flash memory: FLX:XX:FLASH_IMAGE_BYTES_HERE...... (XX = two size bytes)
      b |= FLASH_readByte(i+11) << 8; //bytes are stored big endian on external flash, need to flip the bytes to little endian for transfer to internal flash
      __boot_page_fill_short((uint16_t)(void*)i,b);

      //when 1 page is full (or we're on the last page), write it to the internal flash memory
      if ((i+2)%SPM_PAGESIZE==0 || (i+2==imagesize))
      {
        __boot_page_erase_short((uint16_t)(void*)nextAddress); //(i+2-SPM_PAGESIZE)
        boot_spm_busy_wait();
        // Write from programming buffer
        __boot_page_write_short((uint16_t)(void*)nextAddress ); //(i+2-SPM_PAGESIZE)
        boot_spm_busy_wait();
        nextAddress += SPM_PAGESIZE;
      }
    }
    LED_PIN &= ~_BV(LED);

#if defined(RWWSRE)
    // Reenable read access to flash
    boot_rww_enable();
#endif

#ifdef DEBUG_ON
    putch('E');
#endif

    //erase the first 32K block where flash image resided
    FLASH_command(SPIFLASH_BLOCKERASE_32K, 1);
    SPI_transfer(0);
    SPI_transfer(0);
    SPI_transfer(0);
    FLASH_UNSELECT;
    
    //now trigger a watchdog reset
    watchdogConfig(WATCHDOG_16MS);  // short WDT timeout
    while (1); 		                  // and busy-loop so that WD causes a reset and app start
  }
#ifdef DEBUG_ON
  putch('X');
#endif
}