From 3e070526afcc76e314c7d3111b952ef19acdf89c Mon Sep 17 00:00:00 2001 From: Joseph Coffland Date: Sat, 14 Jan 2017 00:54:20 -0800 Subject: [PATCH] Cleaned up bootloader code --- avr/src/xboot/eeprom_driver.c | 58 --- avr/src/xboot/eeprom_driver.h | 56 --- avr/src/xboot/protocol.h | 102 ----- avr/src/xboot/sp_driver.S | 829 +++++++++------------------------- avr/src/xboot/sp_driver.h | 233 +++------- avr/src/xboot/uart.c | 72 --- avr/src/xboot/uart.h | 43 -- avr/src/xboot/watchdog.c | 51 --- avr/src/xboot/watchdog.h | 42 -- avr/src/xboot/xboot.c | 485 ++++++++++---------- avr/src/xboot/xboot.h | 262 +++++------ 11 files changed, 620 insertions(+), 1613 deletions(-) delete mode 100644 avr/src/xboot/eeprom_driver.c delete mode 100644 avr/src/xboot/eeprom_driver.h delete mode 100644 avr/src/xboot/protocol.h delete mode 100644 avr/src/xboot/uart.c delete mode 100644 avr/src/xboot/uart.h delete mode 100644 avr/src/xboot/watchdog.c delete mode 100644 avr/src/xboot/watchdog.h diff --git a/avr/src/xboot/eeprom_driver.c b/avr/src/xboot/eeprom_driver.c deleted file mode 100644 index 38b6eea..0000000 --- a/avr/src/xboot/eeprom_driver.c +++ /dev/null @@ -1,58 +0,0 @@ -/************************************************************************/ -/* XMEGA EEPROM Driver */ -/* */ -/* eeprom.c */ -/* */ -/* Alex Forencich */ -/* */ -/* Copyright (c) 2011 Alex Forencich */ -/* */ -/* Permission is hereby granted, free of charge, to any person */ -/* obtaining a copy of this software and associated documentation */ -/* files(the "Software"), to deal in the Software without restriction, */ -/* including without limitation the rights to use, copy, modify, merge, */ -/* publish, distribute, sublicense, and/or sell copies of the Software, */ -/* and to permit persons to whom the Software is furnished to do so, */ -/* subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ -/* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS */ -/* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN */ -/* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN */ -/* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ -/* SOFTWARE. */ -/* */ -/************************************************************************/ - -#include "eeprom_driver.h" - - -static inline void NVM_EXEC(void) { - void *z = (void *)&NVM_CTRLA; - - __asm__ volatile("out %[ccp], %[ioreg]" "\n\t" - "st z, %[cmdex]" - : - : [ccp] "I" (_SFR_IO_ADDR(CCP)), - [ioreg] "d" (CCP_IOREG_gc), - [cmdex] "r" (NVM_CMDEX_bm), - [z] "z" (z) - ); -} - - -void wait_for_nvm() { - while (NVM.STATUS & NVM_NVMBUSY_bm) continue; -} - - -void EEPROM_erase_all() { - wait_for_nvm(); - NVM.CMD = NVM_CMD_ERASE_EEPROM_gc; - NVM_EXEC(); -} diff --git a/avr/src/xboot/eeprom_driver.h b/avr/src/xboot/eeprom_driver.h deleted file mode 100644 index c139a43..0000000 --- a/avr/src/xboot/eeprom_driver.h +++ /dev/null @@ -1,56 +0,0 @@ -/************************************************************************/ -/* XMEGA EEPROM Driver */ -/* */ -/* eeprom.h */ -/* */ -/* Alex Forencich */ -/* */ -/* Copyright (c) 2011 Alex Forencich */ -/* */ -/* Permission is hereby granted, free of charge, to any person */ -/* obtaining a copy of this software and associated documentation */ -/* files(the "Software"), to deal in the Software without restriction, */ -/* including without limitation the rights to use, copy, modify, merge, */ -/* publish, distribute, sublicense, and/or sell copies of the Software, */ -/* and to permit persons to whom the Software is furnished to do so, */ -/* subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ -/* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS */ -/* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN */ -/* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN */ -/* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ -/* SOFTWARE. */ -/* */ -/************************************************************************/ - -#pragma once - -#include -#include -#include - -#include "xboot.h" - -#ifndef EEPROM_PAGE_SIZE -#define EEPROM_PAGE_SIZE E2PAGESIZE -#endif - -#define EEPROM_read_byte(addr) \ - eeprom_read_byte((const uint8_t *)((uint16_t)(addr))) - -#define EEPROM_write_byte(addr, value) \ - eeprom_write_byte((uint8_t *)((uint16_t)(addr)), (value)) - -#define EEPROM_read_block(addr, dest, len) \ - eeprom_read_block((dest), (void *)((uint16_t)(addr)), (len)) - -#define EEPROM_write_block(addr, src, len) \ - eeprom_write_block((src), (void *)((uint16_t)(addr)), (len)) - -void EEPROM_erase_all(); diff --git a/avr/src/xboot/protocol.h b/avr/src/xboot/protocol.h deleted file mode 100644 index 4336094..0000000 --- a/avr/src/xboot/protocol.h +++ /dev/null @@ -1,102 +0,0 @@ -/************************************************************************/ -/* XBoot Extensible AVR Bootloader */ -/* */ -/* XBoot Protocol Definition */ -/* */ -/* protocol.h */ -/* */ -/* Alex Forencich */ -/* */ -/* Copyright (c) 2010 Alex Forencich */ -/* */ -/* Permission is hereby granted, free of charge, to any person */ -/* obtaining a copy of this software and associated documentation */ -/* files(the "Software"), to deal in the Software without restriction, */ -/* including without limitation the rights to use, copy, modify, merge, */ -/* publish, distribute, sublicense, and/or sell copies of the Software, */ -/* and to permit persons to whom the Software is furnished to do so, */ -/* subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ -/* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS */ -/* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN */ -/* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN */ -/* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ -/* SOFTWARE. */ -/* */ -/************************************************************************/ - -#pragma once - -#include "xboot.h" - -// General Commands -#define CMD_SYNC '\x1b' - -// Informational Commands -#define CMD_CHECK_AUTOINCREMENT 'a' -#define CMD_CHECK_BLOCK_SUPPORT 'b' -#define CMD_PROGRAMMER_TYPE 'p' -#define CMD_DEVICE_CODE 't' -#define CMD_PROGRAM_ID 'S' -#define CMD_VERSION 'V' -#define CMD_READ_SIGNATURE 's' - -// Addressing -#define CMD_SET_ADDRESS 'A' -#define CMD_SET_EXT_ADDRESS 'H' - -// Erase -#define CMD_CHIP_ERASE 'e' - -// Block Access -#define CMD_BLOCK_LOAD 'B' -#define CMD_BLOCK_READ 'g' - -// Byte Access -#define CMD_READ_BYTE 'R' -#define CMD_WRITE_LOW_BYTE 'c' -#define CMD_WRITE_HIGH_BYTE 'C' -#define CMD_WRITE_PAGE 'm' -#define CMD_WRITE_EEPROM_BYTE 'D' -#define CMD_READ_EEPROM_BYTE 'd' - -// Lock and Fuse Bits -#define CMD_WRITE_LOCK_BITS 'l' -#define CMD_READ_LOCK_BITS 'r' -#define CMD_READ_LOW_FUSE_BITS 'F' -#define CMD_READ_HIGH_FUSE_BITS 'N' -#define CMD_READ_EXT_FUSE_BITS 'Q' - -// Bootloader Commands -#define CMD_ENTER_PROG_MODE 'P' -#define CMD_LEAVE_PROG_MODE 'L' -#define CMD_EXIT_BOOTLOADER 'E' -#define CMD_SET_LED 'x' -#define CMD_CLEAR_LED 'y' -#define CMD_SET_TYPE 'T' - -#define CMD_CRC 'h' - -// Memory types for block access -#define MEM_EEPROM 'E' -#define MEM_FLASH 'F' -#define MEM_USERSIG 'U' -#define MEM_PRODSIG 'P' - -// Sections for CRC checks -#define SECTION_FLASH 'F' -#define SECTION_APPLICATION 'A' -#define SECTION_BOOT 'B' -#define SECTION_APP 'a' -#define SECTION_APP_TEMP 't' - -// Command Responses -#define REPLY_ACK '\r' -#define REPLY_YES 'Y' -#define REPLY_ERROR '?' diff --git a/avr/src/xboot/sp_driver.S b/avr/src/xboot/sp_driver.S index e6fff99..bbb1ee7 100644 --- a/avr/src/xboot/sp_driver.S +++ b/avr/src/xboot/sp_driver.S @@ -1,41 +1,4 @@ ;****************************************************************************** -;* -;* 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) $ ;* @@ -65,643 +28,307 @@ ;* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ;* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ;****************************************************************************** +;* +;* 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 finished using any of the functions in this driver. +;* +;* For all routines, it is important that any interrupt handlers do not +;* perform NVM operations. The user must implement a scheme for mutually +;* exclusive access to 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 #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. -; --- +; Defines not yet included in header file. +#define NVM_CMD_NO_OPERATION_gc 0x00 +#define NVM_CMD_READ_USER_SIG_ROW_gc 0x01 +#define NVM_CMD_READ_CALIB_ROW_gc 0x02 +#define NVM_CMD_READ_EEPROM_gc 0x06 +#define NVM_CMD_READ_FUSES_gc 0x07 +#define NVM_CMD_WRITE_LOCK_BITS_gc 0x08 +#define NVM_CMD_ERASE_USER_SIG_ROW_gc 0x18 +#define NVM_CMD_WRITE_USER_SIG_ROW_gc 0x1a +#define NVM_CMD_ERASE_APP_gc 0x20 +#define NVM_CMD_ERASE_APP_PAGE_gc 0x22 +#define NVM_CMD_LOAD_FLASH_BUFFER_gc 0x23 +#define NVM_CMD_WRITE_APP_PAGE_gc 0x24 +#define NVM_CMD_ERASE_WRITE_APP_PAGE_gc 0x25 +#define NVM_CMD_ERASE_FLASH_BUFFER_gc 0x26 +#define NVM_CMD_ERASE_BOOT_PAGE_gc 0x2a +#define NVM_CMD_WRITE_BOOT_PAGE_gc 0x2c +#define NVM_CMD_ERASE_WRITE_BOOT_PAGE_gc 0x2d +#define NVM_CMD_ERASE_EEPROM_gc 0x30 +#define NVM_CMD_ERASE_EEPROM_PAGE_gc 0x32 +#define NVM_CMD_LOAD_EEPROM_BUFFER_gc 0x33 +#define NVM_CMD_WRITE_EEPROM_PAGE_gc 0x34 +#define NVM_CMD_ERASE_WRITE_EEPROM_PAGE_gc 0x35 +#define NVM_CMD_ERASE_EEPROM_BUFFER_gc 0x36 +#define NVM_CMD_APP_CRC_gc 0x38 +#define NVM_CMD_BOOT_CRC_gc 0x39 +#define NVM_CMD_FLASH_RANGE_CRC_gc 0x3a +#define CCP_SPM_gc 0x9d +#define CCP_IOREG_gc 0xd8 + + +; 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 + 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. +; Reads a word from flash given by the address in R25:R24:R23:R22. ; -; Returns: -; R25:R24 - Read word. -; --- - +; 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 + 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. +; Reads the calibration byte given by the index in R24. ; -; Returns: -; R24 - Calibration byte. -; --- - +; Input: R24 - Byte index. +; Returns: R24 - Calibration byte. .section .text -.global SP_ReadCalibrationByte +.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. + 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. +; Reads the user signature byte given by the index in R25:R24. ; -; Returns: -; R24 - Signature byte. -; --- - -.section .text +; 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. + 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. +; Reads the fuse byte given by the index in R24. ; -; Input: -; R24 - Byte index. -; -; Returns: -; R24 - Fuse byte. -; --- - -.section .text +; 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 + sts NVM_ADDR0, r24 ; Load fuse index into NVM Address Reg 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 -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. -; --- +; Erases the user signature row. .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. + in r19, RAMPZ ; Save RAMPZ, 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. -; --- - +; Writes the flash buffer to the user signature row. .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. - - + in r19, RAMPZ ; Save RAMPZ, 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. -; --- +; Erases the entire application section. .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. - + in r19, RAMPZ ; Save RAMPZ, 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. +; 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. - + in r19, RAMPZ ; Save RAMPZ, 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 +; 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. -; --- - +; Input: R25:R24 - 16-bit pointer to SRAM buffer. .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. + 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. + 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. + 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) + 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. + ldi r21, ((APP_SECTION_PAGE_SIZE / 2) & 0xff) ; Load R21 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. + 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 (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 + subi r21, 1 ; Decrement word count. + sbci r22, 0 #else - dec r21 ; Decrement word count. + 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 + 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 +; Writes the page buffer to Flash 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 +; Input: R25:R24:R23:R22 - Byte address into Flash page. +.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. + in r19, RAMPZ ; Save RAMPZ, 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 +; 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. -; --- - +; Input: R25:R24:R23:R22 - Byte address into Flash page. .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 + in r19, RAMPZ ; Save RAMPZ, 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. -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. -; --- - +; Locks all further access to SPM operations until next reset. .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 - + ldi r18, CCP_IOREG_gc ; Prepare Protect IO-register signature in R18. + sts CCP, r18 ; Enable IO-register operation + ; (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. +; 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 +.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 + 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 +; 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 @@ -710,31 +337,27 @@ SP_WaitForSPM: ; 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 +; 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 + 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 + ; (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 + + +; 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 @@ -744,22 +367,17 @@ SP_CommonCMD: ; R25:R24 - Low bytes of Z pointer. ; R20 - NVM Command code. ; -; Returns: -; R24 - Result from LPM operation. -; --- - -.section .text +; 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 - + 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 +; 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 @@ -772,23 +390,14 @@ SP_CommonLPM: ; 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 - + 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 (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 diff --git a/avr/src/xboot/sp_driver.h b/avr/src/xboot/sp_driver.h index 0bcbce9..01aeaee 100644 --- a/avr/src/xboot/sp_driver.h +++ b/avr/src/xboot/sp_driver.h @@ -1,36 +1,4 @@ -/* 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 * @@ -59,36 +27,57 @@ * 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" +/*! \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 + * Support email: avr@atmel.com + ******************************************************************************/ +#pragma once +#include + +#include -/* 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*/ +#error APP_SECTION_PAGE_SIZE must be defined if not defined in header files. +#endif -// 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*/ +#error APPTABLE_SECTION_START must be defined if not defined in header files. +#endif + /*! \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); @@ -97,9 +86,6 @@ uint8_t SP_ReadByte(uint32_t address); * * 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. @@ -121,76 +107,33 @@ uint8_t SP_ReadCalibrationByte(uint8_t 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 l - * evel. - * - * \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); +/// Erase user signature row. +void SP_EraseUserSignatureRow(); -/*! \brief Write user signature row. - * - * This function write the flash buffer in the user signature row. - */ -void SP_WriteUserSignatureRow(void); +/// Write user signature row. +void SP_WriteUserSignatureRow(); /*! \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 + * \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); +void SP_EraseApplicationSection(); /*! \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); @@ -198,9 +141,6 @@ 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. @@ -208,8 +148,6 @@ void SP_EraseWriteApplicationPage(uint32_t address); 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. @@ -217,82 +155,19 @@ void SP_WriteApplicationPage(uint32_t address); 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); +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); +/// Flush Flash page buffer. +void SP_EraseFlashBuffer(); -/*! \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); +/// Disables the use of SPM until the next reset. +void SP_LockSPM(); -#endif /* SP_DRIVER_H */ +/// Waits for the SPM to finish and clears the command register. +void SP_WaitForSPM(); diff --git a/avr/src/xboot/uart.c b/avr/src/xboot/uart.c deleted file mode 100644 index c4cf091..0000000 --- a/avr/src/xboot/uart.c +++ /dev/null @@ -1,72 +0,0 @@ -/************************************************************************/ -/* XBoot Extensible AVR Bootloader */ -/* */ -/* UART Module */ -/* */ -/* uart.c */ -/* */ -/* Alex Forencich */ -/* */ -/* Copyright (c) 2010 Alex Forencich */ -/* */ -/* Permission is hereby granted, free of charge, to any person */ -/* obtaining a copy of this software and associated documentation */ -/* files(the "Software"), to deal in the Software without restriction, */ -/* including without limitation the rights to use, copy, modify, merge, */ -/* publish, distribute, sublicense, and/or sell copies of the Software, */ -/* and to permit persons to whom the Software is furnished to do so, */ -/* subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ -/* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS */ -/* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN */ -/* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN */ -/* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ -/* SOFTWARE. */ -/* */ -/************************************************************************/ - -#include "uart.h" -#include "xboot.h" - - -bool uart_has_char() {return UART_DEVICE.STATUS & USART_RXCIF_bm;} -uint8_t uart_recv_char() {return UART_DEVICE.DATA;} - - -void uart_send_char_blocking(uint8_t c) { - UART_DEVICE.DATA = c; - while (!(UART_DEVICE.STATUS & USART_TXCIF_bm)) continue; - UART_DEVICE.STATUS |= USART_TXCIF_bm; -} - - -void uart_init() { - UART_PORT.DIRSET = 1 << UART_TX_PIN; - UART_DEVICE.BAUDCTRLA = UART_BSEL_VALUE & USART_BSEL_gm; - UART_DEVICE.BAUDCTRLB = - ((UART_BSCALE_VALUE << USART_BSCALE_gp) & USART_BSCALE_gm) | - ((UART_BSEL_VALUE >> 8) & ~USART_BSCALE_gm); - -#if UART_CLK2X - UART_DEVICE.CTRLB = USART_RXEN_bm | USART_CLK2X_bm | USART_TXEN_bm; -#else - UART_DEVICE.CTRLB = USART_RXEN_bm | USART_TXEN_bm; -#endif // UART_CLK2X - - PORTC.OUTCLR = 1 << 4; // CTS Lo (enable) - PORTC.DIRSET = 1 << 4; // CTS Output -} - - -void uart_deinit() { - UART_DEVICE.CTRLB = 0; - UART_DEVICE.BAUDCTRLA = 0; - UART_DEVICE.BAUDCTRLB = 0; - UART_PORT.DIRCLR = 1 << UART_TX_PIN; -} diff --git a/avr/src/xboot/uart.h b/avr/src/xboot/uart.h deleted file mode 100644 index 0392f7e..0000000 --- a/avr/src/xboot/uart.h +++ /dev/null @@ -1,43 +0,0 @@ -/************************************************************************/ -/* XBoot Extensible AVR Bootloader */ -/* */ -/* UART Module */ -/* */ -/* uart.h */ -/* */ -/* Alex Forencich */ -/* */ -/* Copyright (c) 2010 Alex Forencich */ -/* */ -/* Permission is hereby granted, free of charge, to any person */ -/* obtaining a copy of this software and associated documentation */ -/* files(the "Software"), to deal in the Software without restriction, */ -/* including without limitation the rights to use, copy, modify, merge, */ -/* publish, distribute, sublicense, and/or sell copies of the Software, */ -/* and to permit persons to whom the Software is furnished to do so, */ -/* subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ -/* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS */ -/* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN */ -/* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN */ -/* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ -/* SOFTWARE. */ -/* */ -/************************************************************************/ - -#pragma once - -#include -#include - -bool uart_has_char(); -uint8_t uart_recv_char(); -void uart_send_char_blocking(uint8_t c); -void uart_init(void); -void uart_deinit(void); diff --git a/avr/src/xboot/watchdog.c b/avr/src/xboot/watchdog.c deleted file mode 100644 index a7e1064..0000000 --- a/avr/src/xboot/watchdog.c +++ /dev/null @@ -1,51 +0,0 @@ -/************************************************************************/ -/* XBoot Extensible AVR Bootloader */ -/* */ -/* Watchdog Module */ -/* */ -/* watchdog.c */ -/* */ -/* Alex Forencich */ -/* */ -/* Copyright (c) 2010 Alex Forencich */ -/* */ -/* Permission is hereby granted, free of charge, to any person */ -/* obtaining a copy of this software and associated documentation */ -/* files(the "Software"), to deal in the Software without restriction, */ -/* including without limitation the rights to use, copy, modify, merge, */ -/* publish, distribute, sublicense, and/or sell copies of the Software, */ -/* and to permit persons to whom the Software is furnished to do so, */ -/* subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ -/* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS */ -/* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN */ -/* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN */ -/* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ -/* SOFTWARE. */ -/* */ -/************************************************************************/ - -#include "watchdog.h" - - -void WDT_EnableAndSetTimeout() { - uint8_t temp = WDT_ENABLE_bm | WDT_CEN_bm | WATCHDOG_TIMEOUT; - CCP = CCP_IOREG_gc; - WDT.CTRL = temp; - - // Wait for WD to synchronize with new settings. - while (WDT_IsSyncBusy()) continue; -} - - -void WDT_Disable() { - uint8_t temp = (WDT.CTRL & ~WDT_ENABLE_bm) | WDT_CEN_bm; - CCP = CCP_IOREG_gc; - WDT.CTRL = temp; -} diff --git a/avr/src/xboot/watchdog.h b/avr/src/xboot/watchdog.h deleted file mode 100644 index f9fcc74..0000000 --- a/avr/src/xboot/watchdog.h +++ /dev/null @@ -1,42 +0,0 @@ -/************************************************************************/ -/* XBoot Extensible AVR Bootloader */ -/* */ -/* Watchdog Module */ -/* */ -/* watchdog.c */ -/* */ -/* Alex Forencich */ -/* */ -/* Copyright (c) 2010 Alex Forencich */ -/* */ -/* Permission is hereby granted, free of charge, to any person */ -/* obtaining a copy of this software and associated documentation */ -/* files(the "Software"), to deal in the Software without restriction, */ -/* including without limitation the rights to use, copy, modify, merge, */ -/* publish, distribute, sublicense, and/or sell copies of the Software, */ -/* and to permit persons to whom the Software is furnished to do so, */ -/* subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ -/* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS */ -/* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN */ -/* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN */ -/* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ -/* SOFTWARE. */ -/* */ -/************************************************************************/ - -#pragma once - -#include "xboot.h" - -#define WDT_IsSyncBusy() (WDT.STATUS & WDT_SYNCBUSY_bm) -#define WDT_Reset() asm("wdr") - -void WDT_EnableAndSetTimeout(); -void WDT_Disable(); diff --git a/avr/src/xboot/xboot.c b/avr/src/xboot/xboot.c index 7fd5ac0..03bbc32 100644 --- a/avr/src/xboot/xboot.c +++ b/avr/src/xboot/xboot.c @@ -1,102 +1,246 @@ -/************************************************************************/ -/* XBoot Extensible AVR Bootloader */ -/* */ -/* xboot.c */ -/* */ -/* Alex Forencich */ -/* */ -/* Copyright (c) 2010 Alex Forencich */ -/* */ -/* Permission is hereby granted, free of charge, to any person */ -/* obtaining a copy of this software and associated documentation */ -/* files(the "Software"), to deal in the Software without restriction, */ -/* including without limitation the rights to use, copy, modify, merge, */ -/* publish, distribute, sublicense, and/or sell copies of the Software, */ -/* and to permit persons to whom the Software is furnished to do so, */ -/* subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ -/* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS */ -/* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN */ -/* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN */ -/* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ -/* SOFTWARE. */ -/* */ -/************************************************************************/ +/******************************************************************************\ + + This file is part of the Buildbotics firmware. + + Copyright (c) 2015 - 2016 Buildbotics LLC + Copyright (c) 2010 Alex Forencich + All rights reserved. + + This file ("the software") is free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License, + version 2 as published by the Free Software Foundation. You should + have received a copy of the GNU General Public License, version 2 + along with the software. If not, see . + + The software is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the software. If not, see + . + + For information regarding this software email: + "Joseph Coffland" + +\******************************************************************************/ #include "xboot.h" +#include "sp_driver.h" #include +#include + +#include +#include #include uint8_t buffer[SPM_PAGESIZE]; +uint16_t block_crc = 0; + + +void clock_init() { + // External 16Mhz Xtal w/ 2x PLL = 32 Mhz + // 12-16 MHz crystal; 0.4-16 MHz XTAL w/ 16K CLK startup + OSC.XOSCCTRL = OSC_FRQRANGE_12TO16_gc | OSC_XOSCSEL_XTAL_16KCLK_gc; + OSC.CTRL = OSC_XOSCEN_bm; // enable external crystal oscillator + while (!(OSC.STATUS & OSC_XOSCRDY_bm)); // wait for oscillator ready + OSC.PLLCTRL = OSC_PLLSRC_XOSC_gc | 2; // PLL source, 2x (32 MHz sys clock) + OSC.CTRL = OSC_PLLEN_bm | OSC_XOSCEN_bm; // Enable PLL & External Oscillator + while (!(OSC.STATUS & OSC_PLLRDY_bm)); // wait for PLL ready -void NVM_Wait() { - while (NVM_STATUS & NVM_NVMBUSY_bp) - // reset watchdog while waiting for erase completion - WDT_Reset(); + CCP = CCP_IOREG_gc; + CLK.CTRL = CLK_SCLKSEL_PLL_gc; // switch to PLL clock + OSC.CTRL &= ~OSC_RC2MEN_bm; // disable internal 2 MHz clock } -int main() { - // Initialization section - // Entry point and communication methods are initialized here - // -------------------------------------------------- -#ifdef USE_32MHZ_RC -#if (F_CPU != 32000000L) -#error F_CPU must match oscillator setting! -#endif // F_CPU - OSC.CTRL |= OSC_RC32MEN_bm; // turn on 32 MHz oscillator - while (!(OSC.STATUS & OSC_RC32MRDY_bm)) continue; // wait for it to start +bool uart_has_char() {return UART_DEVICE.STATUS & USART_RXCIF_bm;} +uint8_t uart_recv_char() {return UART_DEVICE.DATA;} + + +void uart_send_char_blocking(uint8_t c) { + UART_DEVICE.DATA = c; + while (!(UART_DEVICE.STATUS & USART_TXCIF_bm)) continue; + UART_DEVICE.STATUS |= USART_TXCIF_bm; +} + + +void uart_init() { + UART_PORT.DIRSET = 1 << UART_TX_PIN; + UART_DEVICE.BAUDCTRLA = UART_BSEL_VALUE & USART_BSEL_gm; + UART_DEVICE.BAUDCTRLB = + ((UART_BSCALE_VALUE << USART_BSCALE_gp) & USART_BSCALE_gm) | + ((UART_BSEL_VALUE >> 8) & ~USART_BSCALE_gm); + UART_DEVICE.CTRLB = USART_RXEN_bm | USART_TXEN_bm; + + PORTC.OUTCLR = 1 << 4; // CTS Lo (enable) + PORTC.DIRSET = 1 << 4; // CTS Output +} + + +void uart_deinit() { + UART_DEVICE.CTRLB = 0; + UART_DEVICE.BAUDCTRLA = 0; + UART_DEVICE.BAUDCTRLB = 0; + UART_PORT.DIRCLR = 1 << UART_TX_PIN; +} + + +void watchdog_init() { + uint8_t temp = WDT_ENABLE_bm | WDT_CEN_bm | WDT_PER_1KCLK_gc; CCP = CCP_IOREG_gc; - CLK.CTRL = CLK_SCLKSEL_RC32M_gc; -#ifdef USE_DFLL - OSC.CTRL |= OSC_RC32KEN_bm; - while(!(OSC.STATUS & OSC_RC32KRDY_bm)); - DFLLRC32M.CTRL = DFLL_ENABLE_bm; -#endif // USE_DFLL -#else // USE_32MHZ_RC -#if (F_CPU != 2000000L) -#error F_CPU must match oscillator setting! -#endif // F_CPU -#ifdef USE_DFLL - OSC.CTRL |= OSC_RC32KEN_bm; - while(!(OSC.STATUS & OSC_RC32KRDY_bm)); - DFLLRC2M.CTRL = DFLL_ENABLE_bm; -#endif // USE_DFLL -#endif // USE_32MHZ_RC - - // Initialize UART - uart_init(); + WDT.CTRL = temp; + while (WDT.STATUS & WDT_SYNCBUSY_bm) continue; +} - // End initialization section - uint32_t address = 0; - uint16_t i = 0; +void watchdog_reset() {asm("wdr");} + + +void watchdog_disable() { + uint8_t temp = (WDT.CTRL & ~WDT_ENABLE_bm) | WDT_CEN_bm; + CCP = CCP_IOREG_gc; + WDT.CTRL = temp; +} + + +void nvm_wait() {while (NVM_STATUS & NVM_NVMBUSY_bp) watchdog_reset();} + + +void nvm_exec() { + void *z = (void *)&NVM_CTRLA; + + __asm__ volatile + ("out %[ccp], %[ioreg]\n" + "st z, %[cmdex]" :: + [ccp] "I" (_SFR_IO_ADDR(CCP)), + [ioreg] "d" (CCP_IOREG_gc), + [cmdex] "r" (NVM_CMDEX_bm), + [z] "z" (z)); +} + +uint8_t get_char() { + while (!uart_has_char()) continue; + return uart_recv_char(); +} + + +void send_char(uint8_t c) {uart_send_char_blocking(c);} + + +uint16_t get_word() { + uint8_t hi = get_char(); + uint8_t lo = get_char(); + return ((uint16_t)hi << 8) | lo; +} + + +uint8_t BlockLoad(unsigned size, uint8_t mem, uint32_t *address) { + watchdog_reset(); + + // fill up buffer + block_crc = 0xffff; + for (int i = 0; i < SPM_PAGESIZE; i++) + if (i < size) { + buffer[i] = get_char(); + block_crc = _crc16_update(block_crc, buffer[i]); + + } else buffer[i] = 0xff; + + switch (mem) { + case MEM_EEPROM: + eeprom_write_block(buffer, (uint8_t *)(uint16_t)*address, size); + *address += size; + break; + + case MEM_FLASH: + // NOTE: Flash programming, address is given in words. + SP_LoadFlashPage(buffer); + SP_EraseWriteApplicationPage(*address << 1); + *address += size >> 1; + nvm_wait(); + break; + + case MEM_USERSIG: + SP_LoadFlashPage(buffer); + SP_EraseUserSignatureRow(); + nvm_wait(); + SP_WriteUserSignatureRow(); + nvm_wait(); + break; + + default: return REPLY_ERROR; + } + + return REPLY_ACK; +} + + + +void BlockRead(unsigned size, uint8_t mem, uint32_t *address) { + switch (mem) { + case MEM_EEPROM: + eeprom_read_block(buffer, (uint8_t *)(uint16_t)*address, size); + *address += size; + + // send bytes + for (int i = 0; i < size; i++) + send_char(buffer[i]); + break; + + case MEM_FLASH: case MEM_USERSIG: case MEM_PRODSIG: { + *address <<= 1; // Convert address to bytes temporarily + + do { + switch (mem) { + case MEM_FLASH: send_char(SP_ReadByte(*address)); break; + case MEM_USERSIG: send_char(SP_ReadUserSignatureByte(*address)); break; + case MEM_PRODSIG: send_char(SP_ReadCalibrationByte(*address)); break; + } + + nvm_wait(); + + (*address)++; // Select next word in memory. + size--; // Subtract two bytes from number of bytes to read + } while (size); // Repeat until all block has been read + + *address >>= 1; // Convert address back to Flash words again. + break; + } + + default: break; + } +} + + +int main() { + // Init + clock_init(); + uart_init(); + watchdog_init(); + + // Check for trigger bool in_bootloader = false; - uint16_t j = ENTER_WAIT; + uint16_t j = INITIAL_WAIT; while (!in_bootloader && 0 < j--) { - // Check for trigger if (uart_has_char()) in_bootloader = uart_recv_char() == CMD_SYNC; - + watchdog_reset(); _delay_ms(1); } - WDT_EnableAndSetTimeout(); - // Main bootloader + uint32_t address = 0; + uint16_t i = 0; + while (in_bootloader) { uint8_t val = get_char(); - WDT_Reset(); + watchdog_reset(); // Main bootloader parser switch (val) { @@ -107,20 +251,23 @@ int main() { send_char(REPLY_ACK); break; - case CMD_SET_EXT_ADDRESS: - address = ((uint32_t)get_char() << 16) | get_word(); + case CMD_SET_EXT_ADDRESS: { + uint8_t hi = get_char(); + address = ((uint32_t)hi << 16) | get_word(); send_char(REPLY_ACK); break; + } case CMD_CHIP_ERASE: // Erase the application section SP_EraseApplicationSection(); // Wait for completion - NVM_Wait(); + nvm_wait(); // Erase EEPROM - EEPROM_erase_all(); + NVM.CMD = NVM_CMD_ERASE_EEPROM_gc; + nvm_exec(); send_char(REPLY_ACK); break; @@ -128,8 +275,8 @@ int main() { case CMD_CHECK_BLOCK_SUPPORT: send_char(REPLY_YES); // Send block size (page size) - send_char((SPM_PAGESIZE >> 8) & 0xFF); - send_char(SPM_PAGESIZE & 0xFF); + send_char(SPM_PAGESIZE >> 8); + send_char((uint8_t)SPM_PAGESIZE); break; case CMD_BLOCK_LOAD: @@ -145,7 +292,7 @@ int main() { break; case CMD_READ_BYTE: { - unsigned w = SP_ReadWord((address << 1)); + unsigned w = SP_ReadWord(address << 1); send_char(w >> 8); send_char(w); @@ -161,7 +308,7 @@ int main() { case CMD_WRITE_HIGH_BYTE: i |= (get_char() << 8); // get high byte; combine - SP_LoadFlashWord((address << 1), i); + SP_LoadFlashWord(address << 1, i); address++; send_char(REPLY_ACK); break; @@ -177,13 +324,13 @@ int main() { break; case CMD_WRITE_EEPROM_BYTE: - EEPROM_write_byte(address, get_char()); + eeprom_write_byte((uint8_t *)(uint16_t)address, get_char()); address++; send_char(REPLY_ACK); break; case CMD_READ_EEPROM_BYTE: - send_char(EEPROM_read_byte(address)); + send_char(eeprom_read_byte((uint8_t *)(uint16_t)address)); address++; break; @@ -213,18 +360,18 @@ int main() { break; case CMD_PROGRAM_ID: - send_char('X'); - send_char('B'); - send_char('o'); - send_char('o'); + send_char('b'); + send_char('b'); + send_char('c'); send_char('t'); - send_char('+'); - send_char('+'); + send_char('r'); + send_char('l'); + send_char(' '); break; case CMD_VERSION: - send_char('0' + XBOOT_VERSION_MAJOR); - send_char('0' + XBOOT_VERSION_MINOR); + send_char('0'); + send_char('1'); break; case CMD_READ_SIGNATURE: @@ -233,32 +380,10 @@ int main() { send_char(SIGNATURE_0); break; - case CMD_CRC: { - uint32_t start = 0; - uint32_t length = 0; - uint16_t crc; - - val = get_char(); - - switch (val) { - case SECTION_FLASH: length = PROGMEM_SIZE; break; - case SECTION_APPLICATION: length = APP_SECTION_SIZE; break; - case SECTION_BOOT: - start = BOOT_SECTION_START; - length = BOOT_SECTION_SIZE; - break; - - default: - send_char(REPLY_ERROR); - continue; - } - - crc = crc16_block(start, length); - - send_char((crc >> 8) & 0xff); - send_char(crc & 0xff); + case CMD_BLOCK_CRC: + send_char(block_crc >> 8); + send_char((uint8_t)block_crc); break; - } case CMD_SYNC: break; // ESC (0x1b) to sync @@ -268,134 +393,16 @@ int main() { } // Wait for any lingering SPM instructions to finish - NVM_Wait(); + nvm_wait(); } - // Bootloader exit - // Code here runs after the bootloader has exited, - // but before the application code has started - - // Shut down UART + // Deinit uart_deinit(); + watchdog_disable(); - WDT_Disable(); + // Disable further self programming until next reset + SP_LockSPM(); - // Jump into main code + // Jump to application code asm("jmp 0"); } - - -uint8_t get_char() { - while (!uart_has_char()) continue; - return uart_recv_char(); -} - - -void send_char(uint8_t c) {uart_send_char_blocking(c);} -uint16_t get_word() {return (get_char() << 8) | get_char();} - - -uint8_t BlockLoad(unsigned size, uint8_t mem, uint32_t *address) { - WDT_Reset(); - - // fill up buffer - for (int i = 0; i < SPM_PAGESIZE; i++) { - char c = 0xff; - if (i < size) c = get_char(); - buffer[i] = c; - } - - switch (mem) { - case MEM_EEPROM: - EEPROM_write_block(*address, buffer, size); - *address += size; - break; - - case MEM_FLASH: - // NOTE: Flash programming, address is given in words. - SP_LoadFlashPage(buffer); - SP_EraseWriteApplicationPage(*address << 1); - *address += size >> 1; - NVM_Wait(); - break; - - case MEM_USERSIG: - SP_LoadFlashPage(buffer); - SP_EraseUserSignatureRow(); - NVM_Wait(); - SP_WriteUserSignatureRow(); - NVM_Wait(); - break; - - default: return REPLY_ERROR; - } - - return REPLY_ACK; -} - - - -void BlockRead(unsigned size, uint8_t mem, uint32_t *address) { - int offset = 0; - int size2 = size; - - switch (mem) { - case MEM_EEPROM: - EEPROM_read_block(*address, buffer, size); - (*address) += size; - break; - - case MEM_FLASH: case MEM_USERSIG: case MEM_PRODSIG: { - *address <<= 1; // Convert address to bytes temporarily - - do { - switch (mem) { - case MEM_FLASH: buffer[offset++] = SP_ReadByte(*address); break; - - case MEM_USERSIG: - buffer[offset++] = SP_ReadUserSignatureByte(*address); - break; - - case MEM_PRODSIG: - buffer[offset++] = SP_ReadCalibrationByte(*address); - break; - } - - NVM_Wait(); - - (*address)++; // Select next word in memory. - size--; // Subtract two bytes from number of bytes to read - } while (size); // Repeat until all block has been read - - *address >>= 1; // Convert address back to Flash words again. - break; - } - - default: send_char(REPLY_ERROR); break; - } - - // send bytes - for (int i = 0; i < size2; i++) - send_char(buffer[i]); -} - - -uint16_t crc16_block(uint32_t start, uint32_t length) { - uint16_t crc = 0; - - int bc = SPM_PAGESIZE; - - for (; length > 0; length--) { - if (bc == SPM_PAGESIZE) { - SP_ReadFlashPage(buffer, start); - start += SPM_PAGESIZE; - bc = 0; - } - - crc = _crc16_update(crc, buffer[bc]); - - bc++; - } - - return crc; -} diff --git a/avr/src/xboot/xboot.h b/avr/src/xboot/xboot.h index 7b327d7..9b68142 100644 --- a/avr/src/xboot/xboot.h +++ b/avr/src/xboot/xboot.h @@ -1,168 +1,108 @@ -/************************************************************************/ -/* XBoot Extensible AVR Bootloader */ -/* */ -/* xboot.h */ -/* */ -/* Alex Forencich */ -/* */ -/* Copyright (c) 2010 Alex Forencich */ -/* */ -/* Permission is hereby granted, free of charge, to any person */ -/* obtaining a copy of this software and associated documentation */ -/* files(the "Software"), to deal in the Software without restriction, */ -/* including without limitation the rights to use, copy, modify, merge, */ -/* publish, distribute, sublicense, and/or sell copies of the Software, */ -/* and to permit persons to whom the Software is furnished to do so, */ -/* subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ -/* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS */ -/* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN */ -/* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN */ -/* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ -/* SOFTWARE. */ -/* */ -/************************************************************************/ +/******************************************************************************\ + + This file is part of the Buildbotics firmware. + + Copyright (c) 2015 - 2016 Buildbotics LLC + Copyright (c) 2010 Alex Forencich + All rights reserved. + + This file ("the software") is free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License, + version 2 as published by the Free Software Foundation. You should + have received a copy of the GNU General Public License, version 2 + along with the software. If not, see . + + The software is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the software. If not, see + . + + For information regarding this software email: + "Joseph Coffland" + +\******************************************************************************/ #pragma once -#include -#include -#include - -// token pasting -#define CAT2_int(x, y) x ## y -#define CAT2(x, y) CAT2_int(x, y) -#define CAT3_int(x, y, z) x ## y ## z -#define CAT3(x, y, z) CAT3_int(x, y, z) - -// Version -#define XBOOT_VERSION_MAJOR 1 -#define XBOOT_VERSION_MINOR 7 - -// Configuration -#define ENTER_WAIT 1000 // In ms -#define UART_BAUD_RATE 115200 -#define UART_NUMBER 0 -#define UART_PORT_NAME C -#define USE_AVR1008_EEPROM -#define USE_DFLL -#define WATCHDOG_TIMEOUT WDT_PER_1KCLK_gc - -// clock config -// use 32MHz osc if makefile calls for it -#if (F_CPU == 32000000L) -// defaults to 2MHz RC oscillator -// define USE_32MHZ_RC to override -#define USE_32MHZ_RC -#endif // F_CPU - -// UART RS485 Enable Output -#define UART_EN_PORT CAT2(PORT, UART_EN_PORT_NAME) - -#if (UART_NUMBER == 0) +#define INITIAL_WAIT 1000 // In ms + #define UART_RX_PIN 2 #define UART_TX_PIN 3 -#else -#define UART_RX_PIN 6 -#define UART_TX_PIN 7 -#endif -#define UART_PORT CAT2(PORT, UART_PORT_NAME) -#define UART_DEVICE_PORT CAT2(UART_PORT_NAME, UART_NUMBER) -#define UART_DEVICE CAT2(USART, UART_DEVICE_PORT) -#define UART_DEVICE_RXC_ISR CAT3(USART, UART_DEVICE_PORT, _RXC_vect) -#define UART_DEVICE_DRE_ISR CAT3(USART, UART_DEVICE_PORT, _DRE_vect) -#define UART_DEVICE_TXC_ISR CAT3(USART, UART_DEVICE_PORT, _TXC_vect) -#define UART_RX_PIN_CTRL CAT3(UART_PORT.PIN, UART_RX_PIN, CTRL) -#define UART_TX_PIN_CTRL CAT3(UART_PORT.PIN, UART_TX_PIN, CTRL) - -// BAUD Rate Values -// Known good at 2MHz -#if (F_CPU == 2000000L) && (UART_BAUD_RATE == 19200) -#define UART_BSEL_VALUE 12 -#define UART_BSCALE_VALUE 0 -#define UART_CLK2X 1 -#elif (F_CPU == 2000000L) && (UART_BAUD_RATE == 38400) -#define UART_BSEL_VALUE 22 -#define UART_BSCALE_VALUE -2 -#define UART_CLK2X 1 -#elif (F_CPU == 2000000L) && (UART_BAUD_RATE == 57600) -#define UART_BSEL_VALUE 26 -#define UART_BSCALE_VALUE -3 -#define UART_CLK2X 1 -#elif (F_CPU == 2000000L) && (UART_BAUD_RATE == 115200) -#define UART_BSEL_VALUE 19 -#define UART_BSCALE_VALUE -4 -#define UART_CLK2X 1 - -// Known good at 32MHz -#elif (F_CPU == 32000000L) && (UART_BAUD_RATE == 19200) -#define UART_BSEL_VALUE 103 -#define UART_BSCALE_VALUE 0 -#define UART_CLK2X 0 -#elif (F_CPU == 32000000L) && (UART_BAUD_RATE == 38400) -#define UART_BSEL_VALUE 51 -#define UART_BSCALE_VALUE 0 -#define UART_CLK2X 0 -#elif (F_CPU == 32000000L) && (UART_BAUD_RATE == 57600) -#define UART_BSEL_VALUE 34 -#define UART_BSCALE_VALUE 0 -#define UART_CLK2X 0 -#elif (F_CPU == 32000000L) && (UART_BAUD_RATE == 115200) +#define UART_PORT PORTC +#define UART_DEVICE USARTC0 + +// Baud rate 115200 @ 32Mhz #define UART_BSEL_VALUE 1047 #define UART_BSCALE_VALUE -6 -#define UART_CLK2X 0 - -#else // None of the above, so calculate something -#warning Not using predefined BAUD rate, possible BAUD rate error! -#if (F_CPU == 2000000L) -#define UART_BSEL_VALUE ((F_CPU) / ((uint32_t)UART_BAUD_RATE * 8) - 1) -#define UART_BSCALE_VALUE 0 -#define UART_CLK2X 1 - -#else -#define UART_BSEL_VALUE ((F_CPU) / ((uint32_t)UART_BAUD_RATE * 16) - 1) -#define UART_BSCALE_VALUE 0 -#define UART_CLK2X 0 -#endif -#endif - -#ifndef EEPROM_PAGE_SIZE -#define EEPROM_PAGE_SIZE E2PAGESIZE -#endif - -#ifndef EEPROM_BYTE_ADDRESS_MASK -#if EEPROM_PAGE_SIZE == 32 -#define EEPROM_BYTE_ADDRESS_MASK 0x1f -#elif EEPROM_PAGE_SIZE == 16 -#define EEPROM_BYTE_ADDRESS_MASK = 0x0f -#elif EEPROM_PAGE_SIZE == 8 -#define EEPROM_BYTE_ADDRESS_MASK = 0x07 -#elif EEPROM_PAGE_SIZE == 4 -#define EEPROM_BYTE_ADDRESS_MASK = 0x03 -#else -#error Unknown EEPROM page size! Please add new byte address value! -#endif -#endif - -// Includes -#include "protocol.h" -#include "sp_driver.h" -#include "eeprom_driver.h" -#include "uart.h" -#include "watchdog.h" - -// Functions -uint8_t get_char(void); -void send_char(uint8_t c); -uint16_t get_word(void); - -uint8_t BlockLoad(unsigned size, uint8_t mem, uint32_t *address); -void BlockRead(unsigned size, uint8_t mem, uint32_t *address); - -uint16_t crc16_block(uint32_t start, uint32_t length); + + +// Protocol +enum { + CMD_SYNC = '\x1b', + + // Informational + CMD_CHECK_AUTOINCREMENT = 'a', + CMD_CHECK_BLOCK_SUPPORT = 'b', + CMD_PROGRAMMER_TYPE = 'p', + CMD_DEVICE_CODE = 't', + CMD_PROGRAM_ID = 'S', + CMD_VERSION = 'V', + CMD_HW_VERSION = 'v', // Unsupported extension + CMD_READ_SIGNATURE = 's', + + // Addressing + CMD_SET_ADDRESS = 'A', + CMD_SET_EXT_ADDRESS = 'H', + + // Erase + CMD_CHIP_ERASE = 'e', + + // Block Access + CMD_BLOCK_LOAD = 'B', + CMD_BLOCK_READ = 'g', + CMD_BLOCK_CRC = 'i', + + // Byte Access + CMD_READ_BYTE = 'R', + CMD_WRITE_LOW_BYTE = 'c', + CMD_WRITE_HIGH_BYTE = 'C', + CMD_WRITE_PAGE = 'm', + CMD_WRITE_EEPROM_BYTE = 'D', + CMD_READ_EEPROM_BYTE = 'd', + + // Lock and Fuse Bits + CMD_WRITE_LOCK_BITS = 'l', + CMD_READ_LOCK_BITS = 'r', + CMD_READ_LOW_FUSE_BITS = 'F', + CMD_READ_HIGH_FUSE_BITS = 'N', + CMD_READ_EXT_FUSE_BITS = 'Q', + + // Control + CMD_ENTER_PROG_MODE = 'P', + CMD_LEAVE_PROG_MODE = 'L', + CMD_EXIT_BOOTLOADER = 'E', + CMD_SET_LED = 'x', + CMD_CLEAR_LED = 'y', + CMD_SET_TYPE = 'T', +}; + + +// Memory types for block access +enum { + MEM_EEPROM = 'E', + MEM_FLASH = 'F', + MEM_USERSIG = 'U', + MEM_PRODSIG = 'P', +}; + + +// Command Responses +enum { + REPLY_ACK = '\r', + REPLY_YES = 'Y', + REPLY_ERROR = '?', +}; -- 2.27.0