Exemple #1
0
/* 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 pagelen_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__");
#if defined(__AVR_ATmega8__) || defined (__AVR_ATmega32__)
  SP=RAMEND;  // This is done by hardware reset
#endif

  /*
   * modified Adaboot no-wait mod.
   * Pass the reset reason to app.  Also, it appears that an Uno poweron
   * can leave multiple reset flags set; we only want the bootloader to
   * run on an 'external reset only' status
   */
  ch = MCUSR;
  MCUSR = 0;
  if (ch & (_BV(WDRF) | _BV(BORF) | _BV(PORF)))
      appStart(ch);

#if LED_START_FLASHES > 0
  // Set up Timer 1 for timeout counter
  TCCR1B = _BV(CS12) | _BV(CS10); // div 1024
#endif

#ifndef SOFT_UART
#if defined(__AVR_ATmega8__) || defined (__AVR_ATmega32__)
  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
  UART_SRA = _BV(U2X0); //Double speed mode USART0
  UART_SRB = _BV(RXEN0) | _BV(TXEN0);
  UART_SRC = _BV(UCSZ00) | _BV(UCSZ01);
  UART_SRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 );
#endif
#endif

  // Set up watchdog to trigger after 1s
  watchdogConfig(WATCHDOG_1S);

#if (LED_START_FLASHES > 0) || defined(LED_DATA_FLASH)
  /* Set LED pin as output */
  LED_DDR |= _BV(LED);
#endif

#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: exits by causing WDT reset */
  for (;;) {
    /* get character from UART */
    ch = getch();

    if(ch == STK_GET_PARAMETER) {
      unsigned char which = getch();
      verifySpace();
      /*
       * Send optiboot version as "SW version"
       * Note that the references to memory are optimized away.
       */
      if (which == 0x82) {
	  putch(optiboot_version & 0xFF);
      } else if (which == 0x81) {
	  putch(optiboot_version >> 8);
      } else {
void getNch(uint8_t count) {
  do getch(); while (--count);
  verifySpace();
}
/* 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

    }
/* main program starts here */
int main(void) {
  // 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();
  SP=RAMEND;  // This is done by hardware reset
  asm volatile ("clr __zero_reg__");

  uint8_t ch;


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

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

  	DDRD = 0;
	PORTD = 0;
	PORTC = 0;
	DDRC = C3_WR | C2_RD;


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

    if(ch == STK_GET_PARAMETER) {
      // GET PARAMETER returns a generic 0x03 reply - enough to keep Avrdude happy
      getNch(1);
      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
      address = getch();
      address = (address & 0xff) | (getch() << 8);
      address += address; // Convert from word address to byte address
      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;

      getLen();

      // Immediately start page erase - this will 4.5ms
      boot_page_erase((uint16_t)(void*)address);

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

      // 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();


      // 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((uint16_t)(void*)addrPtr,a);
        addrPtr += 2;
      } while (--ch);
      
      // Write from programming buffer
      boot_page_write((uint16_t)(void*)address);
      boot_spm_busy_wait();

      // Reenable read access to flash
      boot_rww_enable();


    }
    /* Read memory block mode, length is big endian.  */
    else if(ch == STK_READ_PAGE) {
      // READ PAGE - we only read flash
      getLen();
      verifySpace();

      do putch(pgm_read_byte_near(address++));
      while (--length);
    }

    /* Get device signature bytes  */
    else if(ch == STK_READ_SIGN) {
      // READ SIGN - return what Avrdude wants to hear
      verifySpace();
      putch(SIGNATURE_0);
      putch(SIGNATURE_1);
      putch(SIGNATURE_2);
    }
    else if (ch == 'Q') {
      // Adaboot no-wait mod
      watchdogConfig(WATCHDOG_16MS);
      verifySpace();
    }
    else {
      // This covers the response to commands like STK_ENTER_PROGMODE
      verifySpace();
    }
    putch(STK_OK);
  }
}
Exemple #5
0
/* main program starts here */
int main(void) {
  uint8_t ch;
  uint8_t WaitTime = WATCHDOG_1S;  // Set watchdog to trigger after 1 second by default - value set to the watchdog later!


  /*
   * 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 pagelen_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:

  // Following lines enabled by Mark Griffiths to allow jumping directly to the boot loader from user code.
  cli();
  asm volatile ("clr __zero_reg__");
//#if defined(__AVR_ATmega8__) || defined (__AVR_ATmega32__)
  SP=RAMEND;  // This is done by hardware reset
//#endif

  /*
   * modified Adaboot no-wait mod.
   * Pass the reset reason to app.  Also, it appears that an Uno poweron
   * can leave multiple reset flags set; we only want the bootloader to
   * run on an 'external reset only' status
   */
//  ch = MCUSR;
//  MCUSR = 0;
//  if (ch & (_BV(WDRF) | _BV(BORF) | _BV(PORF)))
//      appStart(ch);

  // Modified no wait mod by Mark Griffiths 8th of April 2015
  // This modification allows the majority of the reset flags to be kept 
  // unmodified in the MCUSR register for use by user sketches!

  // Previous method saved the MCUSR data in r2, but because it cleared 
  // MCUSR before attempting to update the flash memory, there was no way
  // for user code to distinguish between an external reset and a watchdog 
  // reset.  It also required extra code and an extra byte of RAM in the 
  // user sketch.

  ch = MCUSR;

  if (ch == 0) {
      WaitTime = WATCHDOG_8S;   // If no Reset Flags are set, it must mean that the user code jumped to the boot loader!  Wait 8 seconds for the firmware to be updated!
  } else {
      if ((ch & (_BV(WDRF) | _BV(EXTRF))) != _BV(EXTRF)) {    // To run the boot loader, External Reset Flag must be set and the Watchdog Flag MUST be cleared!  Otherwise jump straight to user code.
          MCUSR = ~(_BV(WDRF));
          appStart(ch);
      }
  }

#if LED_START_FLASHES > 0
  // Set up Timer 1 for timeout counter
  TCCR1B = _BV(CS12) | _BV(CS10); // div 1024
#endif

#ifndef SOFT_UART
#if defined(__AVR_ATmega8__) || defined (__AVR_ATmega32__)
  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
  UART_SRA = _BV(U2X0); //Double speed mode USART0
  UART_SRB = _BV(RXEN0) | _BV(TXEN0);
  UART_SRC = _BV(UCSZ00) | _BV(UCSZ01);
  UART_SRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 );
#endif
#endif

  
  watchdogConfig(WaitTime);

#if (LED_START_FLASHES > 0) || defined(LED_DATA_FLASH)
  /* Set LED pin as output */
  LED_DDR |= _BV(LED);
#endif

#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: exits by causing WDT reset */
  for (;;) {
    /* get character from UART */
    ch = getch();

    if(ch == STK_GET_PARAMETER) {
      unsigned char which = getch();
      verifySpace();
      /*
       * Send optiboot version as "SW version"
       * Note that the references to memory are optimized away.
       */
      if (which == 0x82) {
	  putch(optiboot_version & 0xFF);
      } else if (which == 0x81) {
	  putch(optiboot_version >> 8);
      } else {
uint8_t proccessCommand()
{
	uint8_t ch;

	ch = getch();

	if(ch == STK_GET_PARAMETER) {
		unsigned char which = getch();
		verifySpace();
		if(which == 0x82) {
			/*
			 * Send tftpboot version as "minor SW version"
			 */
			putch(ARIADNE_MINVER);
		} else if(which == 0x81) {
			putch(ARIADNE_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(4);
	} 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) {
		// This should probably go somewhere but I don't yet know it's place
		//eeprom_write_byte(EEPROM_IMG_STAT, EEPROM_IMG_BAD_VALUE);
		// PROGRAM PAGE - we support flash programming only, not EEPROM
		uint8_t  buff[256];
		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((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((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();

		// 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((uint16_t)(void*)addrPtr, a);
			addrPtr += 2;
		} while(--ch);

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

#if defined(RWWSRE)
		// Reenable read access to flash
		boot_rww_enable();
#endif
	}
	/* Read memory block mode, length is big endian.  */
	else if(ch == STK_READ_PAGE) {
		// READ PAGE - we only read flash
		getch();			/* getlen() */
		length = getch();
		getch();

		verifySpace();

#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560)
		//      do putch(pgm_read_byte_near(address++));
		//      while (--length);
		do {
			uint8_t result;
			__asm__("elpm %0,Z\n":"=r"(result):"z"(address));
			putch(result);
			address++;
		} while(--length);
#else
		do putch(pgm_read_byte_near(address++));
		while(--length);
#endif
	}
Exemple #7
0
/* main program starts here */
int main(void) {
  uint8_t ch;
  uint16_t pmask;

  /*
   * 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 uint16_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__");
  SP=RAMEND;  // This is done by hardware reset

  // Adaboot no-wait mod
  ch = MCUSR;
  MCUSR = 0;
  if (ch & (_BV(WDRF) | _BV(BORF) | _BV(PORF)))
	appStart(ch);

  // WDT clock by 32KHz IRC
  PMCR = 0x80;
  PMCR = 0x93;

#if EXT_OSC == 1
#warning Using external crystal now!!!
  // for case of 16MHz crystall, no clock divider
  PMCR = 0x80;
  PMCR = 0x97;
  for(ch = 0xf; ch > 0; --ch);
  PMCR = 0x80;
  PMCR = 0xb7;

  CLKPR = 0x80;
  CLKPR = 0x00;

  // external crsyall flag
  VDTCR = 0x80;
  VDTCR = 0x4C;
#else
  // system clock: 16MHz system clock
  CLKPR = 0x80;
  CLKPR = 0x01;
#endif

#if LED_START_FLASHES > 0
  // Set up Timer 1 for timeout counter
  TCCR1B = _BV(CS12) | _BV(CS10); // div 1024
#endif

#ifndef SOFT_UART
#if defined(__AVR_ATmega8__) || defined (__AVR_ATmega32__)
  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
  //UART_SRA = _BV(U2X0); //Double speed mode USART0
  ch = PMXCR | 0x03;
  PMXCR = 0x80;
  PMXCR = ch;

  UART_SRB = _BV(RXEN0) | _BV(TXEN0);
  UART_SRC = _BV(UCSZ00) | _BV(UCSZ01);
  UART_SRL = (uint8_t)( F_CPU / (BAUD_RATE * 16L) - 1 );
  //UART_SRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 );
#endif
#endif

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

#if (LED_START_FLASHES > 0) || defined(LED_DATA_FLASH)
  /* Set LED pin as output */
  LED_DDR |= _BV(LED);
#endif

#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

  // page erased flag
  pmask = 0;

  /* 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;
      uint8_t bval;
      uint16_t len;
      length = (uint16_t)getch() << 8; /* getlen() */
      length += getch();
      bval = 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;
      len = length;
      do *bufPtr++ = getch();
      while (--len);

      EEARL = 0; 
      EEARH = address >> 8;
      ch = EEARH >> 2;	// 1KB page size

      if((0 == (pmask & (((uint16_t)1 << ch)))) && bval == 'F') { 
	pmask |= ((uint16_t)1 << ch);
      	// do page erase here
      	EECR = 0x94;
      	EECR = 0x92;
      	asm("nop"); asm("nop");      
      }

      // 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();
      if (bval == 'E') {
	  for(len = 0; len < length; len++) {
	    if(address >= 512)
		    break;
	    EEARL = address++;
	    EEARH = address >> 8;
	    EEDR = buff[len];
	    EECR = 0x04;
	    EECR = 0x02;
	  }
      } else {
#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;
	  buff[8] = vect & 0xff;
	  buff[9] = vect >> 8;

	  // Add jump to bootloader at RESET vector
	  buff[0] = 0xff;
	  buff[1] = 0xcd; // jmp 
	}
#endif
      	// Write from programming buffer
	bufPtr = buff;
      	for(length = 0; length < SPM_PAGESIZE; length+=2) {
	      EEARL = 0; EEDR = *bufPtr++;
	      EEARL = 1; EEDR = *bufPtr++;
	      EEARL = (address + length) & 0xff;
	      EECR = 0xA4;
	      EECR = 0xA2;
	}
      }
Exemple #8
0
/* main program starts here */
void optiboot(void) {
	uint8_t ch;

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

		if(ch == STK_GET_PARAMETER) {
			// GET PARAMETER returns a generic 0x03 reply - enough to keep Avrdude happy
			getNch(1);
			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 address = getch();
			address = (address & 0xff) | (getch() << 8);
			verifySpace();

			// address is in words right now
			if (address % (SPM_PAGESIZE / 2)) {
				reply = STK_FAILED;
			}
			else {
				// Convert to page address
				page = address / (SPM_PAGESIZE / 2);
			}
		}
		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
			uint8_t *bufPtr = buff;

			// we support flash programming only, not EEPROM
			if ((getLen() == 'E') ||
				(length > SPM_PAGESIZE) ||
				(page >= (CONFIG_BOOTLDR_START_ADDR / SPM_PAGESIZE)))
			{
				reply = STK_FAILED;
			}

			// Clear the buffer
			memset(buff, 0xff, sizeof(buff));

			// Read in page contents
			do *bufPtr++ = getch();
			while (--length);

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

			if (reply == STK_OK) {
				// Write the page
				stubboot_write_page(page, buff);
			}
		}
		/* Read memory block mode, length is big endian.  */
		else if(ch == STK_READ_PAGE) {
			// READ PAGE - we only read flash
			if (getLen() == 'E') {
				reply = STK_FAILED;
			}
			verifySpace();

#if (FLASHEND > USHRT_MAX)
			uint_farptr_t address = (uint_farptr_t)page * SPM_PAGESIZE;
#else
			uint16_t address = page * SPM_PAGESIZE;
#endif

			while (length--) {
#if (FLASHEND > USHRT_MAX)
				putch(pgm_read_byte_far(address++));
#else
				putch(pgm_read_byte_near(address++));
#endif
			}
		}
		/* Get device signature bytes  */
		else if(ch == STK_READ_SIGN) {
			// READ SIGN - return what Avrdude wants to hear
			verifySpace();
			putch(SIGNATURE_0);
			putch(SIGNATURE_1);
			putch(SIGNATURE_2);
		}
		else {
			// This covers the response to commands like STK_ENTER_PROGMODE
			verifySpace();
		}

		putch(reply);
	}
}