From 6d9fee1387fbffe38d6f96a0c8bb05b4c22df54e Mon Sep 17 00:00:00 2001 From: Michael Janssen Date: Wed, 17 Jul 2013 11:53:03 -0500 Subject: [PATCH 1/3] First support for XMEGA in CDC bootloader --- Bootloaders/CDC/BootloaderAPI.c | 30 ++ Bootloaders/CDC/BootloaderAPI.h | 6 +- Bootloaders/CDC/BootloaderCDC.c | 154 +++++- Bootloaders/CDC/BootloaderCDC.h | 8 + Bootloaders/CDC/Config/LUFAConfig.h | 33 ++ Bootloaders/CDC/Descriptors.h | 4 + Bootloaders/CDC/makefile | 21 +- Bootloaders/CDC/sp_driver.S | 793 ++++++++++++++++++++++++++++ Bootloaders/CDC/sp_driver.h | 293 ++++++++++ 9 files changed, 1310 insertions(+), 32 deletions(-) create mode 100644 Bootloaders/CDC/sp_driver.S create mode 100644 Bootloaders/CDC/sp_driver.h diff --git a/Bootloaders/CDC/BootloaderAPI.c b/Bootloaders/CDC/BootloaderAPI.c index a84ecf89b..0b905a57f 100644 --- a/Bootloaders/CDC/BootloaderAPI.c +++ b/Bootloaders/CDC/BootloaderAPI.c @@ -37,39 +37,69 @@ void BootloaderAPI_ErasePage(const uint32_t Address) { +#if (ARCH == ARCH_AVR8) boot_page_erase_safe(Address); boot_spm_busy_wait(); boot_rww_enable(); +#elif (ARCH == ARCH_XMEGA) + SP_EraseApplicationPage(Address); + SP_WaitForSPM(); +#endif } void BootloaderAPI_WritePage(const uint32_t Address) { +#if (ARCH == ARCH_AVR8) boot_page_write_safe(Address); boot_spm_busy_wait(); boot_rww_enable(); +#elif (ARCH == ARCH_XMEGA) + SP_WriteApplicationPage(Address); + SP_WaitForSPM(); +#endif } void BootloaderAPI_FillWord(const uint32_t Address, const uint16_t Word) { +#if (ARCH == ARCH_AVR8) boot_page_fill_safe(Address, Word); +#elif (ARCH == ARCH_XMEGA) + SP_LoadFlashWord(Address, Word); +#endif } uint8_t BootloaderAPI_ReadSignature(const uint16_t Address) { +#if (ARCH == ARCH_AVR8) return boot_signature_byte_get(Address); +#elif (ARCH == ARCH_XMEGA) + return SP_ReadUserSignatureByte(Address); +#endif } uint8_t BootloaderAPI_ReadFuse(const uint16_t Address) { +#if (ARCH == ARCH_AVR8) return boot_lock_fuse_bits_get(Address); +#elif (ARCH == ARCH_XMEGA) + return SP_ReadFuseByte(Address); +#endif } uint8_t BootloaderAPI_ReadLock(void) { +#if (ARCH == ARCH_AVR8) return boot_lock_fuse_bits_get(GET_LOCK_BITS); +#elif (ARCH == ARCH_XMEGA) + return SP_ReadLockBits(); +#endif } void BootloaderAPI_WriteLock(const uint8_t LockBits) { +#if (ARCH == ARCH_AVR8) boot_lock_bits_set_safe(LockBits); +#elif (ARCH == ARCH_XMEGA) + SP_WriteLockBits(LockBits); +#endif } diff --git a/Bootloaders/CDC/BootloaderAPI.h b/Bootloaders/CDC/BootloaderAPI.h index db6a068bc..cbedae73a 100644 --- a/Bootloaders/CDC/BootloaderAPI.h +++ b/Bootloaders/CDC/BootloaderAPI.h @@ -36,12 +36,16 @@ #ifndef _BOOTLOADER_API_H_ #define _BOOTLOADER_API_H_ + #include /* Includes: */ #include +#if (ARCH == ARCH_AVR8) #include +#elif (ARCH == ARCH_XMEGA) + #include "sp_driver.h" +#endif #include - #include #include "Config/AppConfig.h" diff --git a/Bootloaders/CDC/BootloaderCDC.c b/Bootloaders/CDC/BootloaderCDC.c index 74e406629..0503ebb5b 100644 --- a/Bootloaders/CDC/BootloaderCDC.c +++ b/Bootloaders/CDC/BootloaderCDC.c @@ -63,6 +63,33 @@ static bool RunBootloader = true; */ uint16_t MagicBootKey ATTR_NO_INIT; +/** Routine to check if the reset source was the watchdog. */ +static inline uint8_t Reset_Source_Was_Watchdog() { +#if (ARCH == ARCH_AVR8) + return (MCUSR & (1 << WDRF)); +#elif (ARCH == ARCH_XMEGA) + return (RST.STATUS & RST_WDRF_bm); +#endif +} + +/** Routine to turn off the watchdog reset status bit. */ +static inline void Turn_Off_Watchdog_Reset_Status() { +#if (ARCH == ARCH_AVR8) + MSUSR &= ~(1 << WDRF); +#elif (ARCH == ARCH_XMEGA) + RST.STATUS = RST_WDRF_bm; +#endif +} + +/** wdt_disable() is not defined by avr/wdt.h for XMEGA devices. */ +#if (ARCH == ARCH_XMEGA) +static inline void wdt_disable(void); +static inline void wdt_disable() { + uint8_t temp = (WDT.CTRL & ~WDT_ENABLE_bm) | WDT_CEN_bm; + CCP = CCP_IOREG_gc; + WDT.CTRL = temp; +} +#endif /** Special startup routine to check if the bootloader was started via a watchdog reset, and if the magic application * start key has been loaded into \ref MagicBootKey. If the bootloader started via the watchdog and the key is valid, @@ -88,14 +115,14 @@ void Application_Jump_Check(void) #endif /* If the reset source was the bootloader and the key is correct, clear it and jump to the application */ - if ((MCUSR & (1 << WDRF)) && (MagicBootKey == MAGIC_BOOT_KEY)) + if (Reset_Source_Was_Watchdog() && (MagicBootKey == MAGIC_BOOT_KEY)) JumpToApplication |= true; /* If a request has been made to jump to the user application, honor it */ if (JumpToApplication) { /* Turn off the watchdog */ - MCUSR &= ~(1< 0xFFFF) + LEDs_TurnOnLEDs(LEDS_LED3); WriteNextResponseByte(pgm_read_byte_far(CurrAddress | HighByte)); + LEDs_TurnOffLEDs(LEDS_LED3); #else WriteNextResponseByte(pgm_read_byte(CurrAddress | HighByte)); #endif @@ -300,13 +356,10 @@ static void ReadWriteMemoryBlock(const uint8_t Command) if (MemoryType == MEMORY_TYPE_FLASH) { +#if (ARCH == ARCH_AVR8) boot_page_erase(PageStartAddress); boot_spm_busy_wait(); - } - - while (BlockSize--) - { - if (MemoryType == MEMORY_TYPE_FLASH) + while (BlockSize--) { /* If both bytes in current word have been written, increment the address counter */ if (HighByte) @@ -324,28 +377,38 @@ static void ReadWriteMemoryBlock(const uint8_t Command) HighByte = !HighByte; } - else - { - /* Write the next EEPROM byte from the endpoint */ - eeprom_write_byte((uint8_t*)((intptr_t)(CurrAddress >> 1)), FetchNextCommandByte()); - - /* Increment the address counter after use */ - CurrAddress += 2; - } - } - - /* If in FLASH programming mode, commit the page after writing */ - if (MemoryType == MEMORY_TYPE_FLASH) - { /* Commit the flash page to memory */ boot_page_write(PageStartAddress); /* Wait until write operation has completed */ boot_spm_busy_wait(); +#elif (ARCH == ARCH_XMEGA) + uint8_t buffer[SPM_PAGESIZE]; + for (int i = 0; i < BlockSize; i++) { + buffer[i] = FetchNextCommandByte(); + } + uint32_t tempaddress = CurrAddress; + LEDs_TurnOnLEDs(LEDS_LED4); + SP_LoadFlashPage(buffer); + SP_EraseWriteApplicationPage(tempaddress); + SP_WaitForSPM(); + CurrAddress += BlockSize; + LEDs_TurnOffLEDs(LEDS_LED4); +#endif } + else + { + while (BlockSize--) { + /* Write the next EEPROM byte from the endpoint */ + eeprom_write_byte((uint8_t*)((intptr_t)(CurrAddress >> 1)), FetchNextCommandByte()); - /* Send response byte back to the host */ - WriteNextResponseByte('\r'); + /* Increment the address counter after use */ + CurrAddress += 1; + } + } + + /* Send response byte back to the host */ + WriteNextResponseByte('\r'); } } #endif @@ -417,6 +480,8 @@ static void CDC_Task(void) /* Read in the bootloader command (first byte sent from host) */ uint8_t Command = FetchNextCommandByte(); + uint16_t tmpword = 0; + if (Command == AVR109_COMMAND_ExitBootloader) { RunBootloader = false; @@ -484,10 +549,15 @@ static void CDC_Task(void) /* Clear the application section of flash */ for (uint32_t CurrFlashAddress = 0; CurrFlashAddress < (uint32_t)BOOT_START_ADDR; CurrFlashAddress += SPM_PAGESIZE) { +#if (ARCH == ARCH_AVR8) boot_page_erase(CurrFlashAddress); boot_spm_busy_wait(); boot_page_write(CurrFlashAddress); boot_spm_busy_wait(); +#elif (ARCH == ARCH_XMEGA) + SP_EraseApplicationSection(); + SP_WaitForSPM(); +#endif } /* Send confirmation byte back to the host */ @@ -497,27 +567,46 @@ static void CDC_Task(void) else if (Command == AVR109_COMMAND_WriteLockbits) { /* Set the lock bits to those given by the host */ +#if (ARCH == ARCH_AVR8) boot_lock_bits_set(FetchNextCommandByte()); - +#elif (ARCH == ARCH_XMEGA) + SP_WriteLockBits( FetchNextCommandByte()); +#endif /* Send confirmation byte back to the host */ WriteNextResponseByte('\r'); } #endif else if (Command == AVR109_COMMAND_ReadLockbits) { +#if (ARCH == ARCH_AVR8) WriteNextResponseByte(boot_lock_fuse_bits_get(GET_LOCK_BITS)); +#elif (ARCH == ARCH_XMEGA) + WriteNextResponseByte(SP_ReadLockBits()); +#endif } else if (Command == AVR109_COMMAND_ReadLowFuses) { +#if (ARCH == ARCH_AVR8) WriteNextResponseByte(boot_lock_fuse_bits_get(GET_LOW_FUSE_BITS)); +#elif (ARCH == ARCH_XMEGA) + WriteNextResponseByte(SP_ReadFuseByte(0)); +#endif } else if (Command == AVR109_COMMAND_ReadHighFuses) { +#if (ARCH == ARCH_AVR8) WriteNextResponseByte(boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS)); +#elif (ARCH == ARCH_XMEGA) + WriteNextResponseByte(SP_ReadFuseByte(1)); +#endif } else if (Command == AVR109_COMMAND_ReadExtendedFuses) { +#if (ARCH == ARCH_AVR8) WriteNextResponseByte(boot_lock_fuse_bits_get(GET_EXTENDED_FUSE_BITS)); +#elif (ARCH == ARCH_XMEGA) + WriteNextResponseByte(SP_ReadFuseByte(2)); +#endif } #if !defined(NO_BLOCK_SUPPORT) else if (Command == AVR109_COMMAND_GetBlockWriteSupport) @@ -537,30 +626,45 @@ static void CDC_Task(void) #if !defined(NO_FLASH_BYTE_SUPPORT) else if (Command == AVR109_COMMAND_FillFlashPageWordHigh) { +#if (ARCH == ARCH_AVR8) /* Write the high byte to the current flash page */ boot_page_fill(CurrAddress, FetchNextCommandByte()); +#elif (ARCH == ARCH_XMEGA) + tmpword |= FetchNextCommandByte() << 8; + /* Write the word to the flash */ + SP_LoadFlashWord(CurrAddress << 1, tmpword); + CurrAddress += 2; +#endif /* Send confirmation byte back to the host */ WriteNextResponseByte('\r'); } else if (Command == AVR109_COMMAND_FillFlashPageWordLow) { +#if (ARCH == ARCH_AVR8) /* Write the low byte to the current flash page */ boot_page_fill(CurrAddress | 0x01, FetchNextCommandByte()); - /* Increment the address */ CurrAddress += 2; +#elif (ARCH == ARCH_XMEGA) + tmpword = FetchNextCommandByte(); +#endif /* Send confirmation byte back to the host */ WriteNextResponseByte('\r'); } else if (Command == AVR109_COMMAND_WriteFlashPage) { +#if (ARCH == ARCH_AVR8) /* Commit the flash page to memory */ boot_page_write(CurrAddress); /* Wait until write operation has completed */ boot_spm_busy_wait(); +#elif (ARCH == ARCH_XMEGA) + SP_WriteApplicationPage(CurrAddress << 1); + SP_WaitForSPM(); +#endif /* Send confirmation byte back to the host */ WriteNextResponseByte('\r'); diff --git a/Bootloaders/CDC/BootloaderCDC.h b/Bootloaders/CDC/BootloaderCDC.h index 89f90a6a2..c276e28b9 100644 --- a/Bootloaders/CDC/BootloaderCDC.h +++ b/Bootloaders/CDC/BootloaderCDC.h @@ -36,10 +36,16 @@ #ifndef _CDC_H_ #define _CDC_H_ +#include + /* Includes: */ #include #include +#if (ARCH == ARCH_AVR8) #include +#elif (ARCH == ARCH_XMEGA) + #include "sp_driver.h" +#endif #include #include #include @@ -138,6 +144,8 @@ #endif static uint8_t FetchNextCommandByte(void); static void WriteNextResponseByte(const uint8_t Response); + static inline uint8_t Reset_Source_Was_Watchdog(void); + static inline void Turn_Off_Watchdog_Reset_Status(void); #endif #endif diff --git a/Bootloaders/CDC/Config/LUFAConfig.h b/Bootloaders/CDC/Config/LUFAConfig.h index 586bf7a35..eb7a3d5d4 100644 --- a/Bootloaders/CDC/Config/LUFAConfig.h +++ b/Bootloaders/CDC/Config/LUFAConfig.h @@ -85,6 +85,39 @@ // #define NO_AUTO_VBUS_MANAGEMENT // #define INVERTED_VBUS_ENABLE_LINE + #elif (ARCH == ARCH_XMEGA) + + /* Non-USB Related Configuration Tokens: */ +// #define DISABLE_TERMINAL_CODES + + /* USB Class Driver Related Tokens: */ +// #define HID_HOST_BOOT_PROTOCOL_ONLY +// #define HID_STATETABLE_STACK_DEPTH {Insert Value Here} +// #define HID_USAGE_STACK_DEPTH {Insert Value Here} +// #define HID_MAX_COLLECTIONS {Insert Value Here} +// #define HID_MAX_REPORTITEMS {Insert Value Here} +// #define HID_MAX_REPORT_IDS {Insert Value Here} +// #define NO_CLASS_DRIVER_AUTOFLUSH + + /* General USB Driver Related Tokens: */ + #define USE_STATIC_OPTIONS (USB_DEVICE_OPT_FULLSPEED | USB_OPT_RC32MCLKSRC | USB_OPT_BUSEVENT_PRIHIGH) +// #define USB_STREAM_TIMEOUT_MS {Insert Value Here} +// #define NO_LIMITED_CONTROLLER_CONNECT +// #define NO_SOF_EVENTS + + /* USB Device Mode Driver Related Tokens: */ + #define USE_RAM_DESCRIPTORS +// #define USE_FLASH_DESCRIPTORS +// #define USE_EEPROM_DESCRIPTORS + #define NO_INTERNAL_SERIAL + #define FIXED_CONTROL_ENDPOINT_SIZE 8 + #define DEVICE_STATE_AS_GPIOR 0 + #define FIXED_NUM_CONFIGURATIONS 1 +// #define CONTROL_ONLY_DEVICE + #define MAX_ENDPOINT_INDEX 4 + #define NO_DEVICE_REMOTE_WAKEUP + #define NO_DEVICE_SELF_POWER + #else #error Unsupported architecture for this LUFA configuration file. diff --git a/Bootloaders/CDC/Descriptors.h b/Bootloaders/CDC/Descriptors.h index 24d1a398e..0c4648bd0 100644 --- a/Bootloaders/CDC/Descriptors.h +++ b/Bootloaders/CDC/Descriptors.h @@ -86,6 +86,10 @@ #define AVR_SIGNATURE_1 0x1E #define AVR_SIGNATURE_2 0x94 #define AVR_SIGNATURE_3 0x82 + #elif defined(__AVR_ATxmega256A3BU__) + #define AVR_SIGNATURE_1 0x1E + #define AVR_SIGNATURE_2 0x98 + #define AVR_SIGNATURE_3 0x43 #else #error The selected AVR part is not currently supported by this bootloader. #endif diff --git a/Bootloaders/CDC/makefile b/Bootloaders/CDC/makefile index d636d64b8..6e44f0499 100644 --- a/Bootloaders/CDC/makefile +++ b/Bootloaders/CDC/makefile @@ -11,14 +11,17 @@ # Run "make help" for target help. -MCU = at90usb1287 -ARCH = AVR8 -BOARD = USBKEY -F_CPU = 8000000 -F_USB = $(F_CPU) +MCU = atxmega256a3bu +ARCH = XMEGA +BOARD = A3BU_XPLAINED +F_CPU = 32000000 +F_USB = 48000000 OPTIMIZATION = s TARGET = BootloaderCDC SRC = $(TARGET).c Descriptors.c BootloaderAPI.c BootloaderAPITable.S $(LUFA_SRC_USB) +ifeq ($(ARCH),XMEGA) +SRC += sp_driver.S +endif LUFA_PATH = ../../LUFA CC_FLAGS = -DUSE_LUFA_CONFIG_HEADER -IConfig/ -DBOOT_START_ADDR=$(BOOT_START_OFFSET) LD_FLAGS = -Wl,--section-start=.text=$(BOOT_START_OFFSET) $(BOOT_API_LD_FLAGS) @@ -26,14 +29,20 @@ LD_FLAGS = -Wl,--section-start=.text=$(BOOT_START_OFFSET) $(BOOT_API_LD_FLAG # Flash size and bootloader section sizes of the target, in KB. These must # match the target's total FLASH size and the bootloader size set in the # device's fuses. -FLASH_SIZE_KB = 128 +FLASH_SIZE_KB = 256 BOOT_SECTION_SIZE_KB = 8 # Bootloader address calculation formulas # Do not modify these macros, but rather modify the dependent values above. CALC_ADDRESS_IN_HEX = $(shell printf "0x%X" $$(( $(1) )) ) +ifeq ($(ARCH),XMEGA) +BOOT_START_OFFSET = $(call CALC_ADDRESS_IN_HEX, ($(FLASH_SIZE_KB)) * 1024 ) +BOOT_SEC_OFFSET = $(call CALC_ADDRESS_IN_HEX, ($(FLASH_SIZE_KB) * 1024) + ($(BOOT_SECTION_SIZE_KB) * 1024) - ($(strip $(1))) ) +else BOOT_START_OFFSET = $(call CALC_ADDRESS_IN_HEX, ($(FLASH_SIZE_KB) - $(BOOT_SECTION_SIZE_KB)) * 1024 ) BOOT_SEC_OFFSET = $(call CALC_ADDRESS_IN_HEX, ($(FLASH_SIZE_KB) * 1024) - ($(strip $(1))) ) +endif + # Bootloader linker section flags for relocating the API table sections to # known FLASH addresses - these should not normally be user-edited. diff --git a/Bootloaders/CDC/sp_driver.S b/Bootloaders/CDC/sp_driver.S new file mode 100644 index 000000000..5c158b701 --- /dev/null +++ b/Bootloaders/CDC/sp_driver.S @@ -0,0 +1,793 @@ +;****************************************************************************** +;* +;* XMEGA Self-programming driver assembly source file. +;* +;* This file contains the low-level implementations for the +;* XMEGA Self-programming driver. It is written for the GCC Assembler. +;* +;* If any SPM instructions are used, the linker file must define +;* a segment named bootloader which must be located in the device Boot section. +;* This can be done by passing "-Wl,--section-start=.BOOT=0x020000" to the +;* linker with the correct address for the boot section. +;* +;* None of these routines clean up the NVM Command Register after use. +;* It is therefore important to write NVM_CMD_NO_OPERATION_gc (0x00) to this +;* register when you are finished using any of the functions in this driver. +;* +;* For all routines, it is important that any interrupt handlers do not +;* perform any NVM operations. The user must implement a scheme for mutually +;* exclusive access to the NVM. However, the 4-cycle timeout will work fine, +;* since writing to the Configuration Change Protection register (CCP) +;* automatically disables interrupts for 4 instruction cycles. +;* +;* Note on IAR calling convention: +;* Scratch registers: R18-R27, R30-R31 +;* Preserved registers: R2-R17, R28-R29 +;* Parameter registers: R8-R25 (2-,4-, or 8- byte alignment) +;* Return registers: R18-R25 (up to 64-bit) +;* +;* Application note: +;* AVR1316: XMEGA Self-programming +;* +;* Documentation +;* For comprehensive code documentation, supported compilers, compiler +;* settings and supported devices see readme.html +;* +;* Atmel Corporation: http:;www.atmel.com \n +;* Support email: avr@atmel.com +;* +;* $Revision: 1153 $ +;* $Date: 2007-12-18 09:48:23 +0100 (ti, 18 des 2007) $ +;* +;* Copyright (c) 2007, Atmel Corporation All rights reserved. +;* +;* Redistribution and use in source and binary forms, with or without +;* modification, are permitted provided that the following conditions are met: +;* +;* 1. Redistributions of source code must retain the above copyright notice, +;* this list of conditions and the following disclaimer. +;* +;* 2. Redistributions in binary form must reproduce the above copyright notice, +;* this list of conditions and the following disclaimer in the documentation +;* and/or other materials provided with the distribution. +;* +;* 3. The name of ATMEL may not be used to endorse or promote products derived +;* from this software without specific prior written permission. +;* +;* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED +;* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +;* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND +;* SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, +;* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +;* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +;* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +;* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +;* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +;* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +;****************************************************************************** + +#include +;#include "Flash_Defines.h" + +/* Define the size of the flash page if not defined in the header files. */ +#ifndef APP_SECTION_PAGE_SIZE + #error APP_SECTION_PAGE_SIZE must be defined if not defined in header files. + //#define APP_SECTION_PAGE_SIZE 512 +#endif /*APP_SECTION_PAGE_SIZE*/ + +/* Defines not yet included in header file. */ +#define NVM_CMD_NO_OPERATION_gc (0x00<<0) // Noop/Ordinary LPM +#define NVM_CMD_READ_USER_SIG_ROW_gc (0x01<<0) // Read user signature row +#define NVM_CMD_READ_CALIB_ROW_gc (0x02<<0) // Read calibration row +#define NVM_CMD_READ_EEPROM_gc (0x06<<0) // Read EEPROM +#define NVM_CMD_READ_FUSES_gc (0x07<<0) // Read fuse byte +#define NVM_CMD_WRITE_LOCK_BITS_gc (0x08<<0) // Write lock bits +#define NVM_CMD_ERASE_USER_SIG_ROW_gc (0x18<<0) // Erase user signature row +#define NVM_CMD_WRITE_USER_SIG_ROW_gc (0x1A<<0) // Write user signature row +#define NVM_CMD_ERASE_APP_gc (0x20<<0) // Erase Application Section +#define NVM_CMD_ERASE_APP_PAGE_gc (0x22<<0) // Erase Application Section page +#define NVM_CMD_LOAD_FLASH_BUFFER_gc (0x23<<0) // Load Flash page buffer +#define NVM_CMD_WRITE_APP_PAGE_gc (0x24<<0) // Write Application Section page +#define NVM_CMD_ERASE_WRITE_APP_PAGE_gc (0x25<<0) // Erase-and-write Application Section page +#define NVM_CMD_ERASE_FLASH_BUFFER_gc (0x26<<0) // Erase/flush Flash page buffer +#define NVM_CMD_ERASE_BOOT_PAGE_gc (0x2A<<0) // Erase Boot Section page +#define NVM_CMD_WRITE_BOOT_PAGE_gc (0x2C<<0) // Write Boot Section page +#define NVM_CMD_ERASE_WRITE_BOOT_PAGE_gc (0x2D<<0) // Erase-and-write Boot Section page +#define NVM_CMD_ERASE_EEPROM_gc (0x30<<0) // Erase EEPROM +#define NVM_CMD_ERASE_EEPROM_PAGE_gc (0x32<<0) // Erase EEPROM page +#define NVM_CMD_LOAD_EEPROM_BUFFER_gc (0x33<<0) // Load EEPROM page buffer +#define NVM_CMD_WRITE_EEPROM_PAGE_gc (0x34<<0) // Write EEPROM page +#define NVM_CMD_ERASE_WRITE_EEPROM_PAGE_gc (0x35<<0) // Erase-and-write EEPROM page +#define NVM_CMD_ERASE_EEPROM_BUFFER_gc (0x36<<0) // Erase/flush EEPROM page buffer +#define NVM_CMD_APP_CRC_gc (0x38<<0) // Generate Application section CRC +#define NVM_CMD_BOOT_CRC_gc (0x39<<0) // Generate Boot Section CRC +#define NVM_CMD_FLASH_RANGE_CRC_gc (0x3A<<0) // Generate Flash Range CRC +#define CCP_SPM_gc (0x9D<<0) // SPM Instruction Protection +#define CCP_IOREG_gc (0xD8<<0) // IO Register Protection + + + +; --- +; This routine reads a byte from flash given by the address in +; R25:R24:R23:R22. +; +; Input: +; R25:R24:R23:R22. +; +; Returns: +; R24 - Read byte. +; --- + +.section .text +.global SP_ReadByte + +SP_ReadByte: + in r19, RAMPZ ; Save RAMPZ. + out RAMPZ, r24 ; Load RAMPZ with the MSB of the address. + movw ZL, r22 ; Move the low bytes to the Z pointer + elpm r24, Z ; Extended load byte from address pointed to by Z. + out RAMPZ, r19 ; Restore RAMPZ register. + ret + + + +; --- +; This routine reads a word from flash given by the address in +; R25:R24:R23:R22. +; +; Input: +; R25:R24:R23:R22. +; +; Returns: +; R25:R24 - Read word. +; --- + +.section .text +.global SP_ReadWord + +SP_ReadWord: + in r19, RAMPZ ; Save RAMPZ. + out RAMPZ, r24 ; Load RAMPZ with the MSB of the address. + movw ZL, r22 ; Move the low bytes to the Z pointer + elpm r24, Z+ ; Extended load byte from address pointed to by Z. + elpm r25, Z ; Extended load byte from address pointed to by Z. + out RAMPZ, r19 ; Restore RAMPZ register. + ret + + + +; --- +; This routine reads the calibration byte given by the index in R24. +; +; Input: +; R24 - Byte index. +; +; Returns: +; R24 - Calibration byte. +; --- + +.section .text +.global SP_ReadCalibrationByte + +SP_ReadCalibrationByte: + ldi r20, NVM_CMD_READ_CALIB_ROW_gc ; Prepare NVM command in R20. + rjmp SP_CommonLPM ; Jump to common LPM code. + + + +; --- +; This routine reads the user signature byte given by the index in R25:R24. +; +; Input: +; R25:R24 - Byte index. +; +; Returns: +; R24 - Signature byte. +; --- + +.section .text +.global SP_ReadUserSignatureByte + +SP_ReadUserSignatureByte: + ldi r20, NVM_CMD_READ_USER_SIG_ROW_gc ; Prepare NVM command in R20. + rjmp SP_CommonLPM ; Jump to common LPM code. + + + +; --- +; This routine reads the fuse byte given by the index in R24. +; +; Input: +; R24 - Byte index. +; +; Returns: +; R24 - Fuse byte. +; --- + +.section .text +.global SP_ReadFuseByte + +SP_ReadFuseByte: + sts NVM_ADDR0, r24 ; Load fuse byte index into NVM Address Register 0. + clr r24 ; Prepare a zero. + sts NVM_ADDR1, r24 ; Load zero into NVM Address Register 1. + sts NVM_ADDR2, r24 ; Load zero into NVM Address Register 2. + ldi r20, NVM_CMD_READ_FUSES_gc ; Prepare NVM command in R20. + rcall SP_CommonCMD ; Jump to common NVM Action code. + movw r24, r22 ; Move low byte to 1 byte return address. + ret + + + +; --- +; This routine sets the lock bits from R24. Note that unlocking is only +; possible by doing a full chip erase, not available from software. +; +; Input: +; R24 - Lock bits. +; +; Returns: +; Nothing. +; --- + +.section .text +.global SP_WriteLockBits + +SP_WriteLockBits: + sts NVM_DATA0, r24 ; Load lock bits into NVM Data Register 0. + ldi r20, NVM_CMD_WRITE_LOCK_BITS_gc ; Prepare NVM command in R20. + rjmp SP_CommonCMD ; Jump to common NVM Action code. + + + +; --- +; This routine reads the lock bits. +; +; Input: +; Nothing. +; +; Returns: +; R24 - Lock bits. +; --- + +.section .text +.global SP_ReadLockBits + +SP_ReadLockBits: + lds r24, NVM_LOCKBITS ; Read IO-mapped lock bits. + ret + + + +; --- +; This routine erases the user signature row. +; +; Input: +; Nothing. +; +; Returns: +; Nothing. +; --- + +.section .text +.global SP_EraseUserSignatureRow + +SP_EraseUserSignatureRow: + in r19, RAMPZ ; Save RAMPZ, which is restored in SP_CommonSPM. + ldi r20, NVM_CMD_ERASE_USER_SIG_ROW_gc ; Prepare NVM command in R20. + jmp SP_CommonSPM ; Jump to common SPM code. + + + +; --- +; This routine writes the flash buffer to the user signature row. +; +; Input: +; Nothing. +; +; Returns: +; Nothing. +; --- + +.section .text +.global SP_WriteUserSignatureRow + +SP_WriteUserSignatureRow: + in r19, RAMPZ ; Save RAMPZ, which is restored in SP_CommonSPM. + ldi r20, NVM_CMD_WRITE_USER_SIG_ROW_gc ; Prepare NVM command in R20. + jmp SP_CommonSPM ; Jump to common SPM code. + + + +; --- +; This routine erases the entire application section. +; +; Input: +; Nothing. +; +; Returns: +; Nothing. +; --- + +.section .text +.global SP_EraseApplicationSection + +SP_EraseApplicationSection: + in r19, RAMPZ ; Save RAMPZ, which is restored in SP_CommonSPM. + clr r24 ; Prepare a zero. + clr r25 + out RAMPZ, r24 ; Point into Application area. + ldi r20, NVM_CMD_ERASE_APP_gc ; Prepare NVM command in R20. + jmp SP_CommonSPM ; Jump to common SPM code. + + + +; --- +; This routine erases the page at address R25:R24:R23:R22 in the application +; section. The address can point anywhere inside the page. +; +; Input: +; R25:R24:R23:R22 - Byte address into Flash page. +; +; Returns: +; Nothing. +; --- + +.section .text +.global SP_EraseApplicationPage + +SP_EraseApplicationPage: + in r19, RAMPZ ; Save RAMPZ, which is restored in SP_CommonSPM. + out RAMPZ, r24 ; Load RAMPZ with the MSB of the address. + movw r24, r22 ; Move low bytes for ZH:ZL to R25:R24 + ldi r20, NVM_CMD_ERASE_APP_PAGE_gc ; Prepare NVM command in R20. + jmp SP_CommonSPM ; Jump to common SPM code. + + + +; --- +; This routine writes the word from R23:R22 into the Flash page buffer at +; address R25:R24. +; +; Input: +; R25:R24 - Byte address into Flash page. +; R23:R22 - Word to write. +; +; Returns: +; Nothing. +; --- + +.section .text +.global SP_LoadFlashWord + +SP_LoadFlashWord: + in r19, RAMPZ ; Save RAMPZ, which is restored in SP_CommonSPM. + movw r0, r22 ; Prepare flash word in R1:R0. + ldi r20, NVM_CMD_LOAD_FLASH_BUFFER_gc ; Prepare NVM command in R20. + jmp SP_CommonSPM ; Jump to common SPM code. + + + +; --- +; This routine writes an entire page from the SRAM buffer at +; address R25:R24 into the Flash page buffer. +; +; Note that you must define "-Wl,--section-start=.BOOT=0x020000" for the +; linker to place this function in the boot section with the correct address. +; +; Input: +; R25:R24 - 16-bit pointer to SRAM buffer. +; +; Returns: +; Nothing. +; --- + +.section .text +.global SP_LoadFlashPage + +SP_LoadFlashPage: + clr ZL ; Clear low byte of Z, to indicate start of page. + clr ZH ; Clear high byte of Z, to indicate start of page. + + out RAMPX, r1 ; Clear RAMPX pointer. + movw XL, r24 ; Load X with data buffer address. + + ldi r20, NVM_CMD_LOAD_FLASH_BUFFER_gc ; Prepare NVM command code in R20. + sts NVM_CMD, r20 ; Load it into NVM command register. + +#if APP_SECTION_PAGE_SIZE > 512 + ldi r22, ((APP_SECTION_PAGE_SIZE/2) >> 8) +#endif + + ldi r21, ((APP_SECTION_PAGE_SIZE/2)&0xFF) ; Load R21 with page word count. + ldi r18, CCP_SPM_gc ; Prepare Protect SPM signature in R16. + +SP_LoadFlashPage_1: + ld r0, X+ ; Load low byte from buffer into R0. + ld r1, X+ ; Load high byte from buffer into R1. + sts CCP, r18 ; Enable SPM operation (this disables interrupts for 4 cycles). + spm ; Self-program. + adiw ZL, 2 ; Move Z to next Flash word. + +#if APP_SECTION_PAGE_SIZE > 512 + subi r21, 1 ; Decrement word count. + sbci r22, 0 +#else + dec r21 ; Decrement word count. +#endif + + brne SP_LoadFlashPage_1 ; Repeat until word cont is zero. + + clr r1 ; Clear R1 for GCC _zero_reg_ to function properly. + ret + + + +; --- +; This routine reads an entire Flash page from address R23:R22:R21:R20 into the +; SRAM buffer at address R25:R24. +; +; +; Input: +; R23:R22:R21:R20 - Flash byte address. +; R25:R24 - 16-bit pointer to SRAM buffer. +; +; Returns: +; Nothing. +; --- + +.section .text +.global SP_ReadFlashPage + +SP_ReadFlashPage: + + in r19, RAMPZ ; Save RAMPZ during assembly. + out RAMPZ, r22 ; Load RAMPZ with MSB of address + movw ZL, r20 ; Load Z with Flash address. + + out RAMPX, r1 ; Load RAMPX with data pointer + movw XL, r24 ; Load X with data buffer address. + + ldi r20, NVM_CMD_NO_OPERATION_gc ; Prepare NVM command code in R20. + sts NVM_CMD, r20 ; Set NVM command to No Operation so that LPM reads Flash. + +#if APP_SECTION_PAGE_SIZE > 512 + ldi r22, ((APP_SECTION_PAGE_SIZE/2) >> 8) ; Load R22 with byte cont high if flash page is large. +#endif + + ldi r21, ((APP_SECTION_PAGE_SIZE)&0xFF) ; Load R21 with byte count. + +SP_ReadFlashPage_1: + elpm r24, Z+ ; Load Flash bytes into R18:r19 + elpm r25, Z+ + st X+, r24 ; Write bytes to buffer. + st X+, r25 + +#if APP_SECTION_PAGE_SIZE > 512 + subi r21, 1 ; Decrement word count. + sbci r22, 0 +#else + dec r21 ; Decrement word count. +#endif + + brne SP_ReadFlashPage_1 ; Repeat until byte count is zero. + + out RAMPZ, r19 + ret + + + +; --- +; This routine writes the page buffer to the Flash page at address R25:R24:R23:R22 +; in the application section. The address can point anywhere inside the page. +; +; Input: +; R25:R24:R23:R22 - Byte address into Flash page. +; +; Returns: +; Nothing. +; --- + +.section .text +.global SP_WriteApplicationPage + +SP_WriteApplicationPage: + in r19, RAMPZ ; Save RAMPZ, which is restored in SP_CommonSPM. + out RAMPZ, r24 ; Load RAMPZ with the MSB of the address. + movw r24, r22 ; Move low bytes of address to ZH:ZL from R23:R22 + ldi r20, NVM_CMD_WRITE_APP_PAGE_gc ; Prepare NVM command in R20. + jmp SP_CommonSPM ; Jump to common SPM code. + + + +; --- +; This routine erases first and then writes the page buffer to the +; Flash page at address R25:R24:R23:R22 in the application section. The address +; can point anywhere inside the page. +; +; Input: +; R25:R24:R23:R22 - Byte address into Flash page. +; +; Returns: +; Nothing. +; --- + +.section .text +.global SP_EraseWriteApplicationPage + +SP_EraseWriteApplicationPage: + in r19, RAMPZ ; Save RAMPZ, which is restored in SP_CommonSPM. + out RAMPZ, r24 ; Load RAMPZ with the MSB of the address. + movw r24, r22 ; Move low bytes of address to ZH:ZL from R23:R22 + ldi r20, NVM_CMD_ERASE_WRITE_APP_PAGE_gc ; Prepare NVM command in R20. + jmp SP_CommonSPM ; Jump to common SPM code. + + + +; --- +; This routine flushes the Flash page buffer. +; +; Input: +; Nothing. +; +; Returns: +; Nothing. +; --- + +.section .text +.global SP_EraseFlashBuffer + +SP_EraseFlashBuffer: + in r19, RAMPZ ; Save RAMPZ, which is restored in SP_CommonSPM. + ldi r20, NVM_CMD_ERASE_FLASH_BUFFER_gc ; Prepare NVM command in R20. + jmp SP_CommonSPM ; Jump to common SPM code. + + + +; --- +; This routine erases the page at address R25:R24:R23:R22 in the Boot section. The +; address can point anywhere inside the page. +; +; Input: +; R25:R24:R23:R22 - Byte address into Flash page. +; +; Returns: +; Nothing. +; --- + +.section .text +.global SP_EraseBootPage + +SP_EraseBootPage: + in r19, RAMPZ ; Save RAMPZ, which is restored in SP_CommonSPM. + out RAMPZ, r24 ; Load RAMPZ with the MSB of the address. + movw r24, r22 ; Move low bytes of address to ZH:ZL from R23:R22 + ldi r20, NVM_CMD_ERASE_BOOT_PAGE_gc ; Prepare NVM command in R20. + jmp SP_CommonSPM ; Jump to common SPM code. + + + +; --- +; This routine writes the page buffer to the Flash page at address R25:R24:R23:R22 +; in the BOOT section. The address can point anywhere inside the page. +; +; Input: +; R25:R24:R23:R22 - Byte address into Flash page. +; +; Returns: +; Nothing. +; --- + +.section .text +.global SP_WriteBootPage + +SP_WriteBootPage: + in r19, RAMPZ ; Save RAMPZ, which is restored in SP_CommonSPM. + out RAMPZ, r24 ; Load RAMPZ with the MSB of the address. + movw r24, r22 ; Move low bytes of address to ZH:ZL from R23:R22 + ldi r20, NVM_CMD_WRITE_BOOT_PAGE_gc ; Prepare NVM command in R20. + jmp SP_CommonSPM ; Jump to common SPM code. + + + +; --- +; This routine erases first and then writes the page buffer to the +; Flash page at address R25:R24:R23:R22 in the Boot section. The address +; can point anywhere inside the page. +; +; Input: +; R25:R24:R23:R22 - Byte address into Flash page. +; +; Returns: +; Nothing. +; --- + +.section .text +.global SP_EraseWriteBootPage + +SP_EraseWriteBootPage: + in r19, RAMPZ ; Save RAMPZ, which is restored in SP_CommonSPM. + out RAMPZ, r24 ; Load RAMPZ with the MSB of the address. + movw r24, r22 ; Move low bytes of address to ZH:ZL from R23:R22 + ldi r20, NVM_CMD_ERASE_WRITE_BOOT_PAGE_gc ; Prepare NVM command in R20. + jmp SP_CommonSPM ; Jump to common SPM code. + + + +; --- +; This routine calculates a CRC for the application section. +; +; Input: +; Nothing. +; +; Returns: +; R25:R24:R23:R22 - 32-bit CRC result (actually only 24-bit used). +; --- + +.section .text +.global SP_ApplicationCRC + +SP_ApplicationCRC: + ldi r20, NVM_CMD_APP_CRC_gc ; Prepare NVM command in R20. + rjmp SP_CommonCMD ; Jump to common NVM Action code. + + + +; --- +; This routine calculates a CRC for the Boot section. +; +; Input: +; Nothing. +; +; Returns: +; R25:R24:R23:R22 - 32-bit CRC result (actually only 24-bit used). +; --- + +.section .text +.global SP_BootCRC + +SP_BootCRC: + ldi r20, NVM_CMD_BOOT_CRC_gc ; Prepare NVM command in R20. + rjmp SP_CommonCMD ; Jump to common NVM Action code. + + + +; --- +; This routine locks all further access to SPM operations until next reset. +; +; Input: +; Nothing. +; +; Returns: +; Nothing. +; --- + +.section .text +.global SP_LockSPM + +SP_LockSPM: + ldi r18, CCP_IOREG_gc ; Prepare Protect IO-register signature in R18. + sts CCP, r18 ; Enable IO-register operation (this disables interrupts for 4 cycles). + ldi r18, NVM_SPMLOCK_bm ; Prepare bitmask for locking SPM into R18. + sts NVM_CTRLB, r18 ; Load bitmask into NVM Control Register B, which locks SPM. + ret + + + +; --- +; This routine wait for the SPM to finish and clears the command register. +; +; Note that this routine is blocking, and will halt any execution until the SPM +; is finished. +; +; Input: +; Nothing. +; +; Returns: +; Nothing. +; --- + +.section .text +.global SP_WaitForSPM + +SP_WaitForSPM: + lds r18, NVM_STATUS ; Load the NVM Status register. + sbrc r18, NVM_NVMBUSY_bp ; Check if bit is cleared. + rjmp SP_WaitForSPM ; Repeat check if bit is not cleared. + clr r18 + sts NVM_CMD, r18 ; Clear up command register to NO_OPERATION. + ret + + + +; --- +; This routine is called by several other routines, and contains common code +; for executing an NVM command, including the return statement itself. +; +; If the operation (NVM command) requires the NVM Address registers to be +; prepared, this must be done before jumping to this routine. +; +; Note that R25:R24:R23:R22 is used for returning results, even if the +; C-domain calling function only expects a single byte or even void. +; +; Input: +; R20 - NVM Command code. +; +; Returns: +; R25:R24:R23:R22 - 32-bit result from NVM operation. +; --- + +.section .text + +SP_CommonCMD: + sts NVM_CMD, r20 ; Load command into NVM Command register. + ldi r18, CCP_IOREG_gc ; Prepare Protect IO-register signature in R18. + ldi r19, NVM_CMDEX_bm ; Prepare bitmask for setting NVM Command Execute bit into R19. + sts CCP, r18 ; Enable IO-register operation (this disables interrupts for 4 cycles). + sts NVM_CTRLA, r19 ; Load bitmask into NVM Control Register A, which executes the command. + lds r22, NVM_DATA0 ; Load NVM Data Register 0 into R22. + lds r23, NVM_DATA1 ; Load NVM Data Register 1 into R23. + lds r24, NVM_DATA2 ; Load NVM Data Register 2 into R24. + clr r25 ; Clear R25 in order to return a clean 32-bit value. + ret + + + +; --- +; This routine is called by several other routines, and contains common code +; for executing an LPM command, including the return statement itself. +; +; Note that R24 is used for returning results, even if the +; C-domain calling function expects a void. +; +; Input: +; R25:R24 - Low bytes of Z pointer. +; R20 - NVM Command code. +; +; Returns: +; R24 - Result from LPM operation. +; --- + +.section .text + +SP_CommonLPM: + movw ZL, r24 ; Load index into Z. + sts NVM_CMD, r20 ; Load prepared command into NVM Command register. + lpm r24,Z + ret + + + +; --- +; This routine is called by several other routines, and contains common code +; for executing an SPM command, including the return statement itself. +; +; If the operation (SPM command) requires the R1:R0 registers to be +; prepared, this must be done before jumping to this routine. +; +; Note that you must define "-Wl,--section-start=.BOOT=0x020000" for the +; linker to place this function in the boot section with the correct address. +; +; Input: +; R1:R0 - Optional input to SPM command. +; R25:R24 - Low bytes of Z pointer. +; R20 - NVM Command code. +; +; Returns: +; Nothing. +; --- + +.section .text + +SP_CommonSPM: + movw ZL, r24 ; Load R25:R24 into Z. + sts NVM_CMD, r20 ; Load prepared command into NVM Command register. + ldi r18, CCP_SPM_gc ; Prepare Protect SPM signature in R18 + sts CCP, r18 ; Enable SPM operation (this disables interrupts for 4 cycles). + spm ; Self-program. + clr r1 ; Clear R1 for GCC _zero_reg_ to function properly. + out RAMPZ, r19 ; Restore RAMPZ register. + ret + + +; END OF FILE diff --git a/Bootloaders/CDC/sp_driver.h b/Bootloaders/CDC/sp_driver.h new file mode 100644 index 000000000..e98cabab1 --- /dev/null +++ b/Bootloaders/CDC/sp_driver.h @@ -0,0 +1,293 @@ +/* This file has been prepared for Doxygen automatic documentation generation.*/ +/*! \file ********************************************************************* + * + * \brief XMEGA Self-programming driver header file. + * + * This file contains the function prototypes for the + * XMEGA Self-programming driver. + * If any SPM instructions are used, the linker file must define + * a segment named BOOT which must be located in the device boot section. + * + * + * None of these functions clean up the NVM Command Register after use. + * It is therefore important to write NVMCMD_NO_OPERATION (0x00) to this + * register when you are finished using any of the functions in this driver. + * + * For all functions, it is important that no interrupt handlers + * perform any NVM operations. The user must implement a scheme for mutually + * exclusive access to the NVM. However, the 4-cycle timeout will work fine, + * since writing to the Configuration Change Protection register (CCP) + * automatically disables interrupts for 4 instruction cycles. + * + * \par Application note: + * AVR1316: XMEGA Self-programming + * + * \par Documentation + * For comprehensive code documentation, supported compilers, compiler + * settings and supported devices see readme.html + * + * \author + * Atmel Corporation: http://www.atmel.com \n + * Support email: avr@atmel.com + * + * $Revision: 1691 $ + * $Date: 2008-07-29 13:25:40 +0200 (ti, 29 jul 2008) $ \n + * + * Copyright (c) 2008, Atmel Corporation All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of ATMEL may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND + * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ +#ifndef SP_DRIVER_H +#define SP_DRIVER_H + +//#include "avr_compiler.h" +//#include "Flash_Defines.h" + + + +/* Define the size of the flash page if not defined in the header files. */ +#ifndef APP_SECTION_PAGE_SIZE + #error APP_SECTION_PAGE_SIZE must be defined if not defined in header files. + //#define APP_SECTION_PAGE_SIZE 512 +#endif /*FLASH_PAGE_SIZE*/ + +/* Define the Start of the application table if not defined in the header files. */ +#ifndef APPTABLE_SECTION_START + #error APPTABLE_SECTION_START must be defined if not defined in header files. + //#define APPTABLE_SECTION_START 0x01E000 //APPTABLE address for ATxmega128A1 +#endif /*APPTABLE_SECTION_START*/ + +/*! \brief Read a byte from flash. + * + * This function reads one byte from the flash. + * + * \note Both IAR and GCC have functions to do this, but + * we include the fucntions for easier use. + * + * \param address Address to the location of the byte to read. + * + * \retval Byte read from flash. + */ +uint8_t SP_ReadByte(uint32_t address); + +/*! \brief Read a word from flash. + * + * This function reads one word from the flash. + * + * \note Both IAR and GCC have functions to do this automatically, but + * we include the fucntions for easier use. + * + * \param address Address to the location of the word to read. + * + * \retval word read from flash. + */ +uint16_t SP_ReadWord(uint32_t address); + +/*! \brief Read calibration byte at given index. + * + * This function reads one calibration byte from the Calibration signature row. + * + * \param index Index of the byte in the calibration signature row. + * + * \retval Calibration byte + */ +uint8_t SP_ReadCalibrationByte(uint8_t index); + +/*! \brief Read fuse byte from given index. + * + * This function reads the fuse byte at the given index. + * + * \param index Index of the fuse byte. + * + * \retval Fuse byte + */ +uint8_t SP_ReadFuseByte(uint8_t index); + +/*! \brief Write lock bits. + * + * This function changes the lock bits. + * + * \note It is only possible to change the lock bits to a higher security level. + * + * \param data The new value of the lock bits. + */ +void SP_WriteLockBits(uint8_t data); + +/*! \brief Read lock bits. + * + * This function reads the lock bits. + * + * \retval Lock bits + */ +uint8_t SP_ReadLockBits(void); + +/*! \brief Read user signature at given index. + * + * This function reads one byte from the user signature row. + * + * \param index Index of the byte in the user signature row. + * + * \retval User signature byte + */ +uint8_t SP_ReadUserSignatureByte(uint16_t index); + +/*! \brief Erase user signature row. + * + * This function erase the entire user signature row. + */ +void SP_EraseUserSignatureRow(void); + +/*! \brief Write user signature row. + * + * This function write the flash buffer in the user signature row. + */ +void SP_WriteUserSignatureRow(void); + +/*! \brief Erase entire application section. + * + * This function erases the entire application and application table section + * + * \note If the lock bits is set to not allow spm in the application or + * application table section the erase is not done. + */ +void SP_EraseApplicationSection(void); + +/*! \brief Erase page at byte address in application or application table section. + * + * This function erase one page given by the byte address. + * + * \param address Byte address for flash page. + */ +void SP_EraseApplicationPage(uint32_t address); + +/*! \brief Erase and write page buffer to application or application table section at byte address. + * + * This function does a combined erase and write to a flash page in the application + * or application table section. + * + * \param address Byte address for flash page. + */ +void SP_EraseWriteApplicationPage(uint32_t address); + +/*! \brief Write page buffer to application or application table section at byte address. + * + * This function writes the Flash page buffer to a page in the application or + * application table section given by the byte address. + * + * \note The page that is written to must be erased before it is written to. + * + * \param address Byte address for flash page. + */ +void SP_WriteApplicationPage(uint32_t address); + +/*! \brief Load one word into Flash page buffer. + * + * This function Loads one word into the Flash page buffer. + * + * \param address Position in inside the flash page buffer. + * \param data Value to be put into the buffer. + */ +void SP_LoadFlashWord(uint16_t address, uint16_t data); + +/*! \brief Load entire page from SRAM buffer into Flash page buffer. + * + * This function load an entire page from SRAM. + * + * \param data Pointer to the data to put in buffer. + * + * \note The __near keyword limits the pointer to two bytes which means that + * only data up to 64K (internal SRAM) can be used. + */ +void SP_LoadFlashPage(const uint8_t * data); + +/*! \brief Read entire Flash page into SRAM buffer. + * + * This function reads an entire flash page and puts it to SRAM. + * + * \param data Pointer to where to store the data. + * \param address Address to page to read from flash. + */ +void SP_ReadFlashPage(const uint8_t * data, uint32_t address); + +/*! \brief Flush Flash page buffer. + * + * This function flush the Flash page buffer. + */ +void SP_EraseFlashBuffer(void); + +/*! \brief Erase page at byte address in boot section. + * + * This function erase one page given by the byte address. + * + * \param address Byte address for flash page. + */ +void SP_EraseBootPage(uint32_t address); + +/*! \brief Erase and write page buffer to boot section at byte address. + * + * This function does a combined erase and write to a flash page in the boot + * section. + * + * \param address Byte address for flash page. + */ +void SP_EraseWriteBootPage(uint32_t address); + +/*! \brief Write page buffer to boot section at byte address. + * + * This function writes the Flash page buffer to a page in the boot section + * given by the byte address. + * + * \note The page that is written to must be erased before it is written to. + * + * \param address Byte address for flash page. + */ +void SP_WriteBootPage(uint32_t address); + +/*! \brief Generate CRC from application section. + * + * \retval 24-bit CRC value + */ +uint32_t SP_ApplicationCRC(void); + +/*! \brief Generate CRC from boot section. + * + * \retval 24-bit CRC value + */ +uint32_t SP_BootCRC(void); + +/*! \brief Lock SPM instruction. + * + * This function locks the SPM instruction, and will disable the use of + * SPM until the next reset occurs. + */ +void SP_LockSPM(void); + +/*! \brief Wait for SPM to finish. + * + * This routine waits for the SPM to finish and clears the command register. + */ +void SP_WaitForSPM(void); + +#endif /* SP_DRIVER_H */ From 08760cc10df698c1cd66946e9218ba6d9cc2ea84 Mon Sep 17 00:00:00 2001 From: Michael Janssen Date: Thu, 18 Jul 2013 05:21:48 -0500 Subject: [PATCH 2/3] Button press to enter bootloader, whitespace --- Bootloaders/CDC/BootloaderCDC.c | 62 ++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/Bootloaders/CDC/BootloaderCDC.c b/Bootloaders/CDC/BootloaderCDC.c index 0503ebb5b..45d290083 100644 --- a/Bootloaders/CDC/BootloaderCDC.c +++ b/Bootloaders/CDC/BootloaderCDC.c @@ -66,18 +66,18 @@ uint16_t MagicBootKey ATTR_NO_INIT; /** Routine to check if the reset source was the watchdog. */ static inline uint8_t Reset_Source_Was_Watchdog() { #if (ARCH == ARCH_AVR8) - return (MCUSR & (1 << WDRF)); + return (MCUSR & (1 << WDRF)); #elif (ARCH == ARCH_XMEGA) - return (RST.STATUS & RST_WDRF_bm); + return (RST.STATUS & RST_WDRF_bm); #endif } /** Routine to turn off the watchdog reset status bit. */ static inline void Turn_Off_Watchdog_Reset_Status() { #if (ARCH == ARCH_AVR8) - MSUSR &= ~(1 << WDRF); + MSUSR &= ~(1 << WDRF); #elif (ARCH == ARCH_XMEGA) - RST.STATUS = RST_WDRF_bm; + RST.STATUS = RST_WDRF_bm; #endif } @@ -114,15 +114,20 @@ void Application_Jump_Check(void) JTAG_ENABLE(); #endif + #if (BOARD == BOARD_A3BU_XPLAINED) + /* Check if SW0 is pressed. If not, go into the application. */ + JumpToApplication |= (PORTE.IN & (1 << 5) == 1); + #endif + /* If the reset source was the bootloader and the key is correct, clear it and jump to the application */ if (Reset_Source_Was_Watchdog() && (MagicBootKey == MAGIC_BOOT_KEY)) - JumpToApplication |= true; + JumpToApplication |= true; /* If a request has been made to jump to the user application, honor it */ if (JumpToApplication) { /* Turn off the watchdog */ - Turn_Off_Watchdog_Reset_Status(); + Turn_Off_Watchdog_Reset_Status(); wdt_disable(); /* Clear the boot key and jump to the user application */ @@ -148,7 +153,6 @@ int main(void) /* Enable global interrupts so that the USB stack can function */ GlobalInterruptEnable(); - LEDs_SetAllLEDs(LEDS_LED2); while (RunBootloader) { CDC_Task(); @@ -182,18 +186,18 @@ static void SetupHardware(void) MCUCR = (1 << IVCE); MCUCR = (1 << IVSEL); #elif (ARCH == ARCH_XMEGA) - /** Set the frequency correctly */ - /* Start the PLL to multiply the 2MHz RC oscillator to 32MHz and switch the CPU core to run from it */ - XMEGACLK_StartPLL(CLOCK_SRC_INT_RC2MHZ, 2000000, F_CPU); - XMEGACLK_SetCPUClockSource(CLOCK_SRC_PLL); - /* Start the 32MHz internal RC oscillator and start the DFLL to increase it to 48MHz using the USB SOF as a reference */ - XMEGACLK_StartInternalOscillator(CLOCK_SRC_INT_RC32MHZ); - XMEGACLK_StartDFLL(CLOCK_SRC_INT_RC32MHZ, DFLL_REF_INT_USBSOF, F_USB); - PMIC.CTRL = PMIC_LOLVLEN_bm | PMIC_MEDLVLEN_bm | PMIC_HILVLEN_bm; - - uint8_t temp = PMIC.CTRL | PMIC_IVSEL_bm; - CCP = CCP_IOREG_gc; - PMIC.CTRL = temp; + /** Set the frequency correctly */ + /* Start the PLL to multiply the 2MHz RC oscillator to 32MHz and switch the CPU core to run from it */ + XMEGACLK_StartPLL(CLOCK_SRC_INT_RC2MHZ, 2000000, F_CPU); + XMEGACLK_SetCPUClockSource(CLOCK_SRC_PLL); + /* Start the 32MHz internal RC oscillator and start the DFLL to increase it to 48MHz using the USB SOF as a reference */ + XMEGACLK_StartInternalOscillator(CLOCK_SRC_INT_RC32MHZ); + XMEGACLK_StartDFLL(CLOCK_SRC_INT_RC32MHZ, DFLL_REF_INT_USBSOF, F_USB); + PMIC.CTRL = PMIC_LOLVLEN_bm | PMIC_MEDLVLEN_bm | PMIC_HILVLEN_bm; + + uint8_t temp = PMIC.CTRL | PMIC_IVSEL_bm; + CCP = CCP_IOREG_gc; + PMIC.CTRL = temp; #endif /* Initialize the USB and other board hardware drivers */ @@ -327,9 +331,9 @@ static void ReadWriteMemoryBlock(const uint8_t Command) { /* Read the next FLASH byte from the current FLASH page */ #if (FLASHEND > 0xFFFF) - LEDs_TurnOnLEDs(LEDS_LED3); + LEDs_TurnOnLEDs(LEDS_LED3); WriteNextResponseByte(pgm_read_byte_far(CurrAddress | HighByte)); - LEDs_TurnOffLEDs(LEDS_LED3); + LEDs_TurnOffLEDs(LEDS_LED3); #else WriteNextResponseByte(pgm_read_byte(CurrAddress | HighByte)); #endif @@ -359,7 +363,7 @@ static void ReadWriteMemoryBlock(const uint8_t Command) #if (ARCH == ARCH_AVR8) boot_page_erase(PageStartAddress); boot_spm_busy_wait(); - while (BlockSize--) + while (BlockSize--) { /* If both bytes in current word have been written, increment the address counter */ if (HighByte) @@ -630,10 +634,10 @@ static void CDC_Task(void) /* Write the high byte to the current flash page */ boot_page_fill(CurrAddress, FetchNextCommandByte()); #elif (ARCH == ARCH_XMEGA) - tmpword |= FetchNextCommandByte() << 8; - /* Write the word to the flash */ - SP_LoadFlashWord(CurrAddress << 1, tmpword); - CurrAddress += 2; + tmpword |= FetchNextCommandByte() << 8; + /* Write the word to the flash */ + SP_LoadFlashWord(CurrAddress << 1, tmpword); + CurrAddress += 2; #endif /* Send confirmation byte back to the host */ @@ -647,7 +651,7 @@ static void CDC_Task(void) /* Increment the address */ CurrAddress += 2; #elif (ARCH == ARCH_XMEGA) - tmpword = FetchNextCommandByte(); + tmpword = FetchNextCommandByte(); #endif /* Send confirmation byte back to the host */ @@ -662,8 +666,8 @@ static void CDC_Task(void) /* Wait until write operation has completed */ boot_spm_busy_wait(); #elif (ARCH == ARCH_XMEGA) - SP_WriteApplicationPage(CurrAddress << 1); - SP_WaitForSPM(); + SP_WriteApplicationPage(CurrAddress << 1); + SP_WaitForSPM(); #endif /* Send confirmation byte back to the host */ From a3c54e746703c65da44add1552fea6ffe47b95a9 Mon Sep 17 00:00:00 2001 From: Michael Janssen Date: Mon, 22 Jul 2013 18:43:10 -0500 Subject: [PATCH 3/3] Fix jump to application for XMegas The normal function-type evaluation does not work on XMega, gcc-avr compiles it into a "load and execute far pointer" combination. jmp 0 is what Atmel uses in it's bootloader assembly, and should be equivalent to the function pointer. --- Bootloaders/CDC/BootloaderCDC.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Bootloaders/CDC/BootloaderCDC.c b/Bootloaders/CDC/BootloaderCDC.c index 45d290083..78e700bd0 100644 --- a/Bootloaders/CDC/BootloaderCDC.c +++ b/Bootloaders/CDC/BootloaderCDC.c @@ -116,7 +116,7 @@ void Application_Jump_Check(void) #if (BOARD == BOARD_A3BU_XPLAINED) /* Check if SW0 is pressed. If not, go into the application. */ - JumpToApplication |= (PORTE.IN & (1 << 5) == 1); + JumpToApplication |= PORTE.IN & _BV(5); #endif /* If the reset source was the bootloader and the key is correct, clear it and jump to the application */ @@ -134,7 +134,7 @@ void Application_Jump_Check(void) MagicBootKey = 0; // cppcheck-suppress constStatement - ((void (*)(void))0x0000)(); + asm("jmp 0"); // Note: same as ((void (*)(void))0x0000)(); } }