From: Joseph Coffland Date: Thu, 12 Jan 2017 00:14:26 +0000 (-0800) Subject: Added bootloader X-Git-Url: https://git.buildbotics.com/?a=commitdiff_plain;h=3cc8ea1e7131686e48e22d45d824cee9e47eb2ec;p=bbctrl-firmware Added bootloader --- diff --git a/Makefile b/Makefile index e03a917..9cfe043 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # Makefile for the project Bulidbotics firmware -PROJECT = buildbotics -MCU = atxmega192a3u -CLOCK = 32000000 +PROJECT = buildbotics +MCU = atxmega192a3u +CLOCK = 32000000 TARGET = $(PROJECT).elf @@ -14,13 +14,13 @@ COMMON = -mmcu=$(MCU) CFLAGS += $(COMMON) CFLAGS += -Wall -Werror # -Wno-error=unused-function CFLAGS += -Wno-error=strict-aliasing # for _invsqrt -CFLAGS += -gdwarf-2 -std=gnu99 -DF_CPU=$(CLOCK)UL -O3 -funroll-loops +CFLAGS += -std=gnu99 -DF_CPU=$(CLOCK)UL -O3 #-funroll-loops CFLAGS += -funsigned-bitfields -fpack-struct -fshort-enums -funsigned-char CFLAGS += -MD -MP -MT $@ -MF build/dep/$(@F).d CFLAGS += -Isrc # Linker flags -LDFLAGS += $(COMMON) -Wl,-u,vfprintf -lprintf_flt -lm -Wl,-Map=$(PROJECT).map +LDFLAGS += $(COMMON) -Wl,-u,vfprintf -lprintf_flt -lm LIBS += -lm # EEPROM flags @@ -29,14 +29,14 @@ EEFLAGS += --set-section-flags=.eeprom="alloc,load" EEFLAGS += --change-section-lma .eeprom=0 --no-change-warnings # Programming flags -#PROGRAMMER = avrispmkII -PROGRAMMER = jtag3pdi -PDEV = usb +PROGRAMMER = avrispmkII +#PROGRAMMER = jtag3pdi +PDEV = usb AVRDUDE_OPTS = -c $(PROGRAMMER) -p $(MCU) -P $(PDEV) FUSE0=0xff FUSE1=0x00 -FUSE2=0xfe +FUSE2=0xbe FUSE4=0xff FUSE5=0xeb @@ -45,27 +45,51 @@ SRC = $(wildcard src/*.c) SRC += $(wildcard src/plan/*.c) OBJ = $(patsubst src/%.c,build/%.o,$(SRC)) +# Boot SRC +BOOT_SRC = $(wildcard src/xboot/*.S) +BOOT_SRC += $(wildcard src/xboot/*.c) +BOOT_OBJ = $(patsubst src/%.c,build/%.o,$(BOOT_SRC)) +BOOT_OBJ := $(patsubst src/%.S,build/%.o,$(BOOT_OBJ)) + +BOOT_LDFLAGS = $(LDFLAGS) -Wl,--section-start=.text=0x030000 + # Build -all: $(TARGET) $(PROJECT).hex $(PROJECT).eep $(PROJECT).lss size +all: $(TARGET) $(PROJECT).hex $(PROJECT).eep $(PROJECT).lss xboot.hex \ + boot-size size # Compile build/%.o: src/%.c @mkdir -p $(shell dirname $@) $(CC) $(INCLUDES) $(CFLAGS) -c -o $@ $< +build/%.o: src/%.S + @mkdir -p $(shell dirname $@) + $(CC) $(INCLUDES) $(CFLAGS) -c -o $@ $< + # Link $(TARGET): $(OBJ) - $(CC) $(LDFLAGS) $(OBJ) $(LIBS) -o $(TARGET) + $(CC) $(LDFLAGS) $(OBJ) $(LIBS) -o $@ + +xboot.elf: $(BOOT_OBJ) + $(CC) $(BOOT_LDFLAGS) $(BOOT_OBJ) -o $@ -%.hex: $(TARGET) +%.hex: %.elf avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature $< $@ -%.eep: $(TARGET) +%.eep: %.elf avr-objcopy $(EEFLAGS) -O ihex $< $@ -%.lss: $(TARGET) +%.lss: %.elf avr-objdump -h -S $< > $@ +boot-size: xboot.elf + @echo '********************************************************************' + @avr-size -A --mcu=$(MCU) xboot.elf + @echo '********************************************************************' + @avr-size -B --mcu=$(MCU) xboot.elf + @echo '********************************************************************' + @avr-size -C --mcu=$(MCU) xboot.elf + size: $(TARGET) @echo '********************************************************************' @avr-size -A --mcu=$(MCU) $(TARGET) @@ -75,6 +99,11 @@ size: $(TARGET) @avr-size -C --mcu=$(MCU) $(TARGET) # Program +init: + $(MAKE) fuses + $(MAKE) program-boot + $(MAKE) program + reset: avrdude $(AVRDUDE_OPTS) @@ -87,6 +116,9 @@ program: $(PROJECT).hex verify: $(PROJECT).hex avrdude $(AVRDUDE_OPTS) -U flash:v:$(PROJECT).hex:i +program-boot: xboot.hex + avrdude $(AVRDUDE_OPTS) -U flash:w:xboot.hex:i + fuses: avrdude $(AVRDUDE_OPTS) -U fuse0:w:$(FUSE0):m -U fuse1:w:$(FUSE1):m \ -U fuse2:w:$(FUSE2):m -U fuse4:w:$(FUSE4):m -U fuse5:w:$(FUSE5):m @@ -110,7 +142,7 @@ tidy: clean: tidy rm -rf $(PROJECT).elf $(PROJECT).hex $(PROJECT).eep $(PROJECT).lss \ - $(PROJECT).map build + $(PROJECT).map build xboot.hex xboot.elf .PHONY: tidy clean size all reset erase program fuses read_fuses prodsig .PHONY: signature usersig diff --git a/src/xboot/eeprom_driver.c b/src/xboot/eeprom_driver.c new file mode 100644 index 0000000..38b6eea --- /dev/null +++ b/src/xboot/eeprom_driver.c @@ -0,0 +1,58 @@ +/************************************************************************/ +/* 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/src/xboot/eeprom_driver.h b/src/xboot/eeprom_driver.h new file mode 100644 index 0000000..c139a43 --- /dev/null +++ b/src/xboot/eeprom_driver.h @@ -0,0 +1,56 @@ +/************************************************************************/ +/* 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/src/xboot/protocol.h b/src/xboot/protocol.h new file mode 100644 index 0000000..4336094 --- /dev/null +++ b/src/xboot/protocol.h @@ -0,0 +1,102 @@ +/************************************************************************/ +/* 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/src/xboot/sp_driver.S b/src/xboot/sp_driver.S new file mode 100644 index 0000000..e6fff99 --- /dev/null +++ b/src/xboot/sp_driver.S @@ -0,0 +1,794 @@ +;****************************************************************************** +;* +;* 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/src/xboot/sp_driver.h b/src/xboot/sp_driver.h new file mode 100644 index 0000000..0bcbce9 --- /dev/null +++ b/src/xboot/sp_driver.h @@ -0,0 +1,298 @@ +/* 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 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); + +/*! \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 */ diff --git a/src/xboot/uart.c b/src/xboot/uart.c new file mode 100644 index 0000000..c4cf091 --- /dev/null +++ b/src/xboot/uart.c @@ -0,0 +1,72 @@ +/************************************************************************/ +/* 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/src/xboot/uart.h b/src/xboot/uart.h new file mode 100644 index 0000000..0392f7e --- /dev/null +++ b/src/xboot/uart.h @@ -0,0 +1,43 @@ +/************************************************************************/ +/* 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/src/xboot/watchdog.c b/src/xboot/watchdog.c new file mode 100644 index 0000000..a7e1064 --- /dev/null +++ b/src/xboot/watchdog.c @@ -0,0 +1,51 @@ +/************************************************************************/ +/* 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/src/xboot/watchdog.h b/src/xboot/watchdog.h new file mode 100644 index 0000000..f9fcc74 --- /dev/null +++ b/src/xboot/watchdog.h @@ -0,0 +1,42 @@ +/************************************************************************/ +/* 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/src/xboot/xboot.c b/src/xboot/xboot.c new file mode 100644 index 0000000..7fd5ac0 --- /dev/null +++ b/src/xboot/xboot.c @@ -0,0 +1,401 @@ +/************************************************************************/ +/* 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. */ +/* */ +/************************************************************************/ + +#include "xboot.h" + +#include + +#include + + +uint8_t buffer[SPM_PAGESIZE]; + + +void NVM_Wait() { + while (NVM_STATUS & NVM_NVMBUSY_bp) + // reset watchdog while waiting for erase completion + WDT_Reset(); +} + + +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 + 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(); + + // End initialization section + + uint32_t address = 0; + uint16_t i = 0; + + bool in_bootloader = false; + uint16_t j = ENTER_WAIT; + while (!in_bootloader && 0 < j--) { + // Check for trigger + if (uart_has_char()) in_bootloader = uart_recv_char() == CMD_SYNC; + + _delay_ms(1); + } + + WDT_EnableAndSetTimeout(); + + // Main bootloader + while (in_bootloader) { + uint8_t val = get_char(); + WDT_Reset(); + + // Main bootloader parser + switch (val) { + case CMD_CHECK_AUTOINCREMENT: send_char(REPLY_YES); break; + + case CMD_SET_ADDRESS: + address = get_word(); + send_char(REPLY_ACK); + break; + + case CMD_SET_EXT_ADDRESS: + address = ((uint32_t)get_char() << 16) | get_word(); + send_char(REPLY_ACK); + break; + + case CMD_CHIP_ERASE: + // Erase the application section + SP_EraseApplicationSection(); + + // Wait for completion + NVM_Wait(); + + // Erase EEPROM + EEPROM_erase_all(); + + send_char(REPLY_ACK); + break; + + 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); + break; + + case CMD_BLOCK_LOAD: + i = get_word(); // Block size + val = get_char(); // Memory type + send_char(BlockLoad(i, val, &address)); // Load it + break; + + case CMD_BLOCK_READ: + i = get_word(); // Block size + val = get_char(); // Memory type + BlockRead(i, val, &address); // Read it + break; + + case CMD_READ_BYTE: { + unsigned w = SP_ReadWord((address << 1)); + + send_char(w >> 8); + send_char(w); + + address++; + break; + } + + case CMD_WRITE_LOW_BYTE: + i = get_char(); // get low byte + send_char(REPLY_ACK); + break; + + case CMD_WRITE_HIGH_BYTE: + i |= (get_char() << 8); // get high byte; combine + SP_LoadFlashWord((address << 1), i); + address++; + send_char(REPLY_ACK); + break; + + case CMD_WRITE_PAGE: + if (address >= (APP_SECTION_SIZE >> 1)) + send_char(REPLY_ERROR); // don't allow bootloader overwrite + + else { + SP_WriteApplicationPage(address << 1); + send_char(REPLY_ACK); + } + break; + + case CMD_WRITE_EEPROM_BYTE: + EEPROM_write_byte(address, get_char()); + address++; + send_char(REPLY_ACK); + break; + + case CMD_READ_EEPROM_BYTE: + send_char(EEPROM_read_byte(address)); + address++; + break; + + case CMD_READ_LOW_FUSE_BITS: send_char(SP_ReadFuseByte(0)); break; + case CMD_READ_HIGH_FUSE_BITS: send_char(SP_ReadFuseByte(1)); break; + case CMD_READ_EXT_FUSE_BITS: send_char(SP_ReadFuseByte(2)); break; + + case CMD_ENTER_PROG_MODE: case CMD_LEAVE_PROG_MODE: + send_char(REPLY_ACK); + break; + + case CMD_EXIT_BOOTLOADER: + in_bootloader = false; + send_char(REPLY_ACK); + break; + + case CMD_PROGRAMMER_TYPE: send_char('S'); break; // serial + + case CMD_DEVICE_CODE: + send_char(123); // send only this device + send_char(0); // terminator + break; + + case CMD_SET_LED: case CMD_CLEAR_LED: case CMD_SET_TYPE: + get_char(); // discard parameter + send_char(REPLY_ACK); + break; + + case CMD_PROGRAM_ID: + send_char('X'); + send_char('B'); + send_char('o'); + send_char('o'); + send_char('t'); + send_char('+'); + send_char('+'); + break; + + case CMD_VERSION: + send_char('0' + XBOOT_VERSION_MAJOR); + send_char('0' + XBOOT_VERSION_MINOR); + break; + + case CMD_READ_SIGNATURE: + send_char(SIGNATURE_2); + send_char(SIGNATURE_1); + 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); + break; + } + + case CMD_SYNC: break; // ESC (0x1b) to sync + + default: // otherwise, error + send_char(REPLY_ERROR); + break; + } + + // Wait for any lingering SPM instructions to finish + NVM_Wait(); + } + + // Bootloader exit + // Code here runs after the bootloader has exited, + // but before the application code has started + + // Shut down UART + uart_deinit(); + + WDT_Disable(); + + // Jump into main 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/src/xboot/xboot.h b/src/xboot/xboot.h new file mode 100644 index 0000000..7b327d7 --- /dev/null +++ b/src/xboot/xboot.h @@ -0,0 +1,168 @@ +/************************************************************************/ +/* 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. */ +/* */ +/************************************************************************/ + +#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 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_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);