From cda88cf97c63c26229578e17184bedcdc0cabc77 Mon Sep 17 00:00:00 2001 From: Dean Camera Date: Wed, 23 Dec 2009 12:54:15 +0000 Subject: Start of implementation of the low level TPI programming protocol in the AVRISP project. --- Projects/AVRISP/AVRISP.txt | 61 ++++++- Projects/AVRISP/Lib/ISPProtocol.h | 1 + Projects/AVRISP/Lib/ISPTarget.h | 1 + Projects/AVRISP/Lib/NVMTarget.c | 332 -------------------------------------- Projects/AVRISP/Lib/NVMTarget.h | 120 -------------- Projects/AVRISP/Lib/PDIProtocol.h | 3 +- Projects/AVRISP/Lib/PDITarget.c | 15 +- Projects/AVRISP/Lib/PDITarget.h | 3 +- Projects/AVRISP/Lib/TPITarget.c | 320 ++++++++++++++++++++++++++++++++++++ Projects/AVRISP/Lib/TPITarget.h | 81 ++++++++++ Projects/AVRISP/Lib/V2Protocol.h | 1 + Projects/AVRISP/Lib/XMEGANVM.c | 332 ++++++++++++++++++++++++++++++++++++++ Projects/AVRISP/Lib/XMEGANVM.h | 121 ++++++++++++++ Projects/AVRISP/makefile | 4 +- 14 files changed, 930 insertions(+), 465 deletions(-) delete mode 100644 Projects/AVRISP/Lib/NVMTarget.c delete mode 100644 Projects/AVRISP/Lib/NVMTarget.h create mode 100644 Projects/AVRISP/Lib/TPITarget.c create mode 100644 Projects/AVRISP/Lib/TPITarget.h create mode 100644 Projects/AVRISP/Lib/XMEGANVM.c create mode 100644 Projects/AVRISP/Lib/XMEGANVM.h (limited to 'Projects/AVRISP') diff --git a/Projects/AVRISP/AVRISP.txt b/Projects/AVRISP/AVRISP.txt index 35cf93770..20e0cce0e 100644 --- a/Projects/AVRISP/AVRISP.txt +++ b/Projects/AVRISP/AVRISP.txt @@ -62,10 +62,10 @@ * without an ADC converter, VTARGET will report at a fixed 5V level. * * When compiled for the XPLAIN board target, this will automatically configure itself for the correct connections to the - * XPLAIN's XMEGA AVR, and will enable PDI only programming support (since ISP mode is not needed). + * XPLAIN's XMEGA AVR, and will enable PDI only programming support (since ISP and TPI modes are not needed). * * While this application can be compiled for USB AVRs with as little as 8KB of FLASH, for full functionality 16KB or more - * of FLASH is required. On 8KB devices, either ISP or PDI programming support can be disabled to reduce program size. + * of FLASH is required. On 8KB devices, ISP, PDI or TPI programming support can be disabled to reduce program size. * * \section Sec_ISP ISP Connections * Connections to the device for SPI programming (when enabled): @@ -155,6 +155,50 @@ * 1 When PDI_VIA_HARDWARE_USART is set, the AVR's Tx and Rx become the DATA line when connected together * via a pair of 300 ohm resistors, and the AVR's XCK pin becomes CLOCK. * + * \section Sec_TPI TPI Connections + * Connections to the device for TPI programming1 (when enabled): + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Programmer Pin:Target Device Pin:PDI 6 Pin Layout:
MISODATA1
ADCx 1VTARGET2
SCLKCLOCK3
N/AN/A4
PORTx.y 2/RESET5
GNDGND6
+ * + * 1 When TPI_VIA_HARDWARE_USART is set, the AVR's Tx and Rx become the DATA line when connected together + * via a pair of 300 ohm resistors, and the AVR's XCK pin becomes CLOCK. + * * \section SSec_Options Project Options * * The following defines can be found in this project, which can control the project behaviour when defined, or changed in value. @@ -204,6 +248,11 @@ * Define to enable XMEGA PDI programming protocol support. Ignored when compiled for the XPLAIN board. * * + * ENABLE_TPI_PROTOCOL + * Makefile CDEFS + * Define to enable 6-PIN ATTINY TPI programming protocol support. Ignored when compiled for the XPLAIN board. + * + * * PDI_VIA_HARDWARE_USART * Makefile CDEFS * Define to force the PDI protocol (when enabled) to use the much faster hardware USART instead of bit-banging to @@ -211,5 +260,13 @@ * seperate ISP and PDI programming headers) but increases programming speed dramatically. * Ignored when compiled for the XPLAIN board. * + * + * TPI_VIA_HARDWARE_USART + * Makefile CDEFS + * Define to force the TPI protocol (when enabled) to use the much faster hardware USART instead of bit-banging to + * match the official AVRISP pinout. This breaks pinout compatibility with the official AVRISP MKII (and requires + * seperate ISP and TPI programming headers) but increases programming speed dramatically. + * Ignored when compiled for the XPLAIN board. + * * */ diff --git a/Projects/AVRISP/Lib/ISPProtocol.h b/Projects/AVRISP/Lib/ISPProtocol.h index 305e68cbc..4bbffbbd1 100644 --- a/Projects/AVRISP/Lib/ISPProtocol.h +++ b/Projects/AVRISP/Lib/ISPProtocol.h @@ -44,6 +44,7 @@ /* Preprocessor Checks: */ #if ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1)) #undef ENABLE_ISP_PROTOCOL + #undef ENABLE_TPI_PROTOCOL #if !defined(ENABLE_PDI_PROTOCOL) #define ENABLE_PDI_PROTOCOL diff --git a/Projects/AVRISP/Lib/ISPTarget.h b/Projects/AVRISP/Lib/ISPTarget.h index 445f3f305..2af4541a9 100644 --- a/Projects/AVRISP/Lib/ISPTarget.h +++ b/Projects/AVRISP/Lib/ISPTarget.h @@ -50,6 +50,7 @@ /* Preprocessor Checks: */ #if ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1)) #undef ENABLE_ISP_PROTOCOL + #undef ENABLE_TPI_PROTOCOL #if !defined(ENABLE_PDI_PROTOCOL) #define ENABLE_PDI_PROTOCOL diff --git a/Projects/AVRISP/Lib/NVMTarget.c b/Projects/AVRISP/Lib/NVMTarget.c deleted file mode 100644 index adf213bb4..000000000 --- a/Projects/AVRISP/Lib/NVMTarget.c +++ /dev/null @@ -1,332 +0,0 @@ -/* - LUFA Library - Copyright (C) Dean Camera, 2009. - - dean [at] fourwalledcubicle [dot] com - www.fourwalledcubicle.com -*/ - -/* - Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) - - Permission to use, copy, modify, and distribute this software - and its documentation for any purpose and without fee is hereby - granted, provided that the above copyright notice appear in all - copies and that both that the copyright notice and this - permission notice and warranty disclaimer appear in supporting - documentation, and that the name of the author not be used in - advertising or publicity pertaining to distribution of the - software without specific, written prior permission. - - The author disclaim all warranties with regard to this - software, including all implied warranties of merchantability - and fitness. In no event shall the author be liable for any - special, indirect or consequential damages or any damages - whatsoever resulting from loss of use, data or profits, whether - in an action of contract, negligence or other tortious action, - arising out of or in connection with the use or performance of - this software. -*/ - -/** \file - * - * Target-related functions for the target's NVM module. - */ - -#define INCLUDE_FROM_NVMTARGET_C -#include "NVMTarget.h" - -#if defined(ENABLE_PDI_PROTOCOL) || defined(__DOXYGEN__) - -/** Sends the given NVM register address to the target. - * - * \param[in] Register NVM register whose absolute address is to be sent - */ -void NVMTarget_SendNVMRegAddress(const uint8_t Register) -{ - /* Determine the absolute register address from the NVM base memory address and the NVM register address */ - uint32_t Address = XPROG_Param_NVMBase | Register; - - /* Send the calculated 32-bit address to the target, LSB first */ - NVMTarget_SendAddress(Address); -} - -/** Sends the given 32-bit absolute address to the target. - * - * \param[in] AbsoluteAddress Absolute address to send to the target - */ -void NVMTarget_SendAddress(const uint32_t AbsoluteAddress) -{ - /* Send the given 32-bit address to the target, LSB first */ - PDITarget_SendByte(AbsoluteAddress & 0xFF); - PDITarget_SendByte(AbsoluteAddress >> 8); - PDITarget_SendByte(AbsoluteAddress >> 16); - PDITarget_SendByte(AbsoluteAddress >> 24); -} - -/** Waits while the target's NVM controller is busy performing an operation, exiting if the - * timeout period expires. - * - * \return Boolean true if the NVM controller became ready within the timeout period, false otherwise - */ -bool NVMTarget_WaitWhileNVMControllerBusy(void) -{ - TCNT0 = 0; - TIFR0 = (1 << OCF1A); - - uint8_t TimeoutMS = PDI_NVM_TIMEOUT_MS; - - /* Poll the NVM STATUS register while the NVM controller is busy */ - while (TimeoutMS) - { - /* Send a LDS command to read the NVM STATUS register to check the BUSY flag */ - PDITarget_SendByte(PDI_CMD_LDS | (PDI_DATSIZE_4BYTES << 2)); - NVMTarget_SendNVMRegAddress(NVM_REG_STATUS); - - /* Check to see if the BUSY flag is still set */ - if (!(PDITarget_ReceiveByte() & (1 << 7))) - return true; - - if (TIFR0 & (1 << OCF1A)) - { - TIFR0 = (1 << OCF1A); - TimeoutMS--; - } - } - - return false; -} - -/** Retrieves the CRC value of the given memory space. - * - * \param[in] CRCCommand NVM CRC command to issue to the target - * \param[out] CRCDest CRC Destination when read from the target - * - * \return Boolean true if the command sequence complete successfully - */ -bool NVMTarget_GetMemoryCRC(const uint8_t CRCCommand, uint32_t* const CRCDest) -{ - /* Wait until the NVM controller is no longer busy */ - if (!(NVMTarget_WaitWhileNVMControllerBusy())) - return false; - - /* Set the NVM command to the correct CRC read command */ - PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2)); - NVMTarget_SendNVMRegAddress(NVM_REG_CMD); - PDITarget_SendByte(CRCCommand); - - /* Set CMDEX bit in NVM CTRLA register to start the CRC generation */ - PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2)); - NVMTarget_SendNVMRegAddress(NVM_REG_CTRLA); - PDITarget_SendByte(1 << 0); - - /* Wait until the NVM bus is ready again */ - if (!(PDITarget_WaitWhileNVMBusBusy())) - return false; - - /* Wait until the NVM controller is no longer busy */ - if (!(NVMTarget_WaitWhileNVMControllerBusy())) - return false; - - *CRCDest = 0; - - /* Read the first generated CRC byte value */ - PDITarget_SendByte(PDI_CMD_LDS | (PDI_DATSIZE_4BYTES << 2)); - NVMTarget_SendNVMRegAddress(NVM_REG_DAT0); - *CRCDest = PDITarget_ReceiveByte(); - - /* Read the second generated CRC byte value */ - PDITarget_SendByte(PDI_CMD_LDS | (PDI_DATSIZE_4BYTES << 2)); - NVMTarget_SendNVMRegAddress(NVM_REG_DAT1); - *CRCDest |= ((uint16_t)PDITarget_ReceiveByte() << 8); - - /* Read the third generated CRC byte value */ - PDITarget_SendByte(PDI_CMD_LDS | (PDI_DATSIZE_4BYTES << 2)); - NVMTarget_SendNVMRegAddress(NVM_REG_DAT2); - *CRCDest |= ((uint32_t)PDITarget_ReceiveByte() << 16); - - return true; -} - -/** Reads memory from the target's memory spaces. - * - * \param[in] ReadAddress Start address to read from within the target's address space - * \param[out] ReadBuffer Buffer to store read data into - * \param[in] ReadSize Number of bytes to read - * - * \return Boolean true if the command sequence complete successfully - */ -bool NVMTarget_ReadMemory(const uint32_t ReadAddress, uint8_t* ReadBuffer, const uint16_t ReadSize) -{ - /* Wait until the NVM controller is no longer busy */ - if (!(NVMTarget_WaitWhileNVMControllerBusy())) - return false; - - /* Send the READNVM command to the NVM controller for reading of an arbitrary location */ - PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2)); - NVMTarget_SendNVMRegAddress(NVM_REG_CMD); - PDITarget_SendByte(NVM_CMD_READNVM); - - /* Load the PDI pointer register with the start address we want to read from */ - PDITarget_SendByte(PDI_CMD_ST | (PDI_POINTER_DIRECT << 2) | PDI_DATSIZE_4BYTES); - NVMTarget_SendAddress(ReadAddress); - - /* Send the REPEAT command with the specified number of bytes to read */ - PDITarget_SendByte(PDI_CMD_REPEAT | PDI_DATSIZE_1BYTE); - PDITarget_SendByte(ReadSize - 1); - - /* Send a LD command with indirect access and postincrement to read out the bytes */ - PDITarget_SendByte(PDI_CMD_LD | (PDI_POINTER_INDIRECT_PI << 2) | PDI_DATSIZE_1BYTE); - for (uint16_t i = 0; i < ReadSize; i++) - *(ReadBuffer++) = PDITarget_ReceiveByte(); - - return true; -} - -/** Writes byte addressed memory to the target's memory spaces. - * - * \param[in] WriteCommand Command to send to the device to write each memory byte - * \param[in] WriteAddress Start address to write to within the target's address space - * \param[in] WriteBuffer Buffer to source data from - * - * \return Boolean true if the command sequence complete successfully - */ -bool NVMTarget_WriteByteMemory(const uint8_t WriteCommand, const uint32_t WriteAddress, const uint8_t* WriteBuffer) -{ - /* Wait until the NVM controller is no longer busy */ - if (!(NVMTarget_WaitWhileNVMControllerBusy())) - return false; - - /* Send the memory write command to the target */ - PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2)); - NVMTarget_SendNVMRegAddress(NVM_REG_CMD); - PDITarget_SendByte(WriteCommand); - - /* Send new memory byte to the memory to the target */ - PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2)); - NVMTarget_SendAddress(WriteAddress); - PDITarget_SendByte(*(WriteBuffer++)); - - return true; -} - -/** Writes page addressed memory to the target's memory spaces. - * - * \param[in] WriteBuffCommand Command to send to the device to write a byte to the memory page buffer - * \param[in] EraseBuffCommand Command to send to the device to erase the memory page buffer - * \param[in] WritePageCommand Command to send to the device to write the page buffer to the destination memory - * \param[in] PageMode Bitfield indicating what operations need to be executed on the specified page - * \param[in] WriteAddress Start address to write the page data to within the target's address space - * \param[in] WriteBuffer Buffer to source data from - * \param[in] WriteSize Number of bytes to write - * - * \return Boolean true if the command sequence complete successfully - */ -bool NVMTarget_WritePageMemory(const uint8_t WriteBuffCommand, const uint8_t EraseBuffCommand, - const uint8_t WritePageCommand, const uint8_t PageMode, const uint32_t WriteAddress, - const uint8_t* WriteBuffer, const uint16_t WriteSize) -{ - if (PageMode & XPRG_PAGEMODE_ERASE) - { - /* Wait until the NVM controller is no longer busy */ - if (!(NVMTarget_WaitWhileNVMControllerBusy())) - return false; - - /* Send the memory buffer erase command to the target */ - PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2)); - NVMTarget_SendNVMRegAddress(NVM_REG_CMD); - PDITarget_SendByte(EraseBuffCommand); - - /* Set CMDEX bit in NVM CTRLA register to start the buffer erase */ - PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2)); - NVMTarget_SendNVMRegAddress(NVM_REG_CTRLA); - PDITarget_SendByte(1 << 0); - } - - if (WriteSize) - { - /* Wait until the NVM controller is no longer busy */ - if (!(NVMTarget_WaitWhileNVMControllerBusy())) - return false; - - /* Send the memory buffer write command to the target */ - PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2)); - NVMTarget_SendNVMRegAddress(NVM_REG_CMD); - PDITarget_SendByte(WriteBuffCommand); - - /* Load the PDI pointer register with the start address we want to write to */ - PDITarget_SendByte(PDI_CMD_ST | (PDI_POINTER_DIRECT << 2) | PDI_DATSIZE_4BYTES); - NVMTarget_SendAddress(WriteAddress); - - /* Send the REPEAT command with the specified number of bytes to write */ - PDITarget_SendByte(PDI_CMD_REPEAT | PDI_DATSIZE_1BYTE); - PDITarget_SendByte(WriteSize - 1); - - /* Send a ST command with indirect access and postincrement to write the bytes */ - PDITarget_SendByte(PDI_CMD_ST | (PDI_POINTER_INDIRECT_PI << 2) | PDI_DATSIZE_1BYTE); - for (uint16_t i = 0; i < WriteSize; i++) - PDITarget_SendByte(*(WriteBuffer++)); - } - - if (PageMode & XPRG_PAGEMODE_WRITE) - { - /* Wait until the NVM controller is no longer busy */ - if (!(NVMTarget_WaitWhileNVMControllerBusy())) - return false; - - /* Send the memory write command to the target */ - PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2)); - NVMTarget_SendNVMRegAddress(NVM_REG_CMD); - PDITarget_SendByte(WritePageCommand); - - /* Send the address of the first page location to write the memory page */ - PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2)); - NVMTarget_SendAddress(WriteAddress); - PDITarget_SendByte(0x00); - } - - return true; -} - -/** Erases a specific memory space of the target. - * - * \param[in] EraseCommand NVM erase command to send to the device - * \param[in] Address Address inside the memory space to erase - * - * \return Boolean true if the command sequence complete successfully - */ -bool NVMTarget_EraseMemory(const uint8_t EraseCommand, const uint32_t Address) -{ - /* Wait until the NVM controller is no longer busy */ - if (!(NVMTarget_WaitWhileNVMControllerBusy())) - return false; - - /* Send the memory erase command to the target */ - PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2)); - NVMTarget_SendNVMRegAddress(NVM_REG_CMD); - PDITarget_SendByte(EraseCommand); - - /* Chip erase is handled separately, since it's procedure is different to other erase types */ - if (EraseCommand == NVM_CMD_CHIPERASE) - { - /* Set CMDEX bit in NVM CTRLA register to start the chip erase */ - PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2)); - NVMTarget_SendNVMRegAddress(NVM_REG_CTRLA); - PDITarget_SendByte(1 << 0); - } - else - { - /* Other erase modes just need us to address a byte within the target memory space */ - PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2)); - NVMTarget_SendAddress(Address); - PDITarget_SendByte(0x00); - } - - /* Wait until the NVM bus is ready again */ - if (!(PDITarget_WaitWhileNVMBusBusy())) - return false; - - return true; -} - -#endif diff --git a/Projects/AVRISP/Lib/NVMTarget.h b/Projects/AVRISP/Lib/NVMTarget.h deleted file mode 100644 index 24319331d..000000000 --- a/Projects/AVRISP/Lib/NVMTarget.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - LUFA Library - Copyright (C) Dean Camera, 2009. - - dean [at] fourwalledcubicle [dot] com - www.fourwalledcubicle.com -*/ - -/* - Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) - - Permission to use, copy, modify, and distribute this software - and its documentation for any purpose and without fee is hereby - granted, provided that the above copyright notice appear in all - copies and that both that the copyright notice and this - permission notice and warranty disclaimer appear in supporting - documentation, and that the name of the author not be used in - advertising or publicity pertaining to distribution of the - software without specific, written prior permission. - - The author disclaim all warranties with regard to this - software, including all implied warranties of merchantability - and fitness. In no event shall the author be liable for any - special, indirect or consequential damages or any damages - whatsoever resulting from loss of use, data or profits, whether - in an action of contract, negligence or other tortious action, - arising out of or in connection with the use or performance of - this software. -*/ - -/** \file - * - * Header file for NVMTarget.c. - */ - -#ifndef _NVM_TARGET_ -#define _NVM_TARGET_ - - /* Includes: */ - #include - #include - #include - - #include - - #include "PDIProtocol.h" - #include "PDITarget.h" - - /* Preprocessor Checks: */ - #if ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1)) - #undef ENABLE_ISP_PROTOCOL - - #if !defined(ENABLE_PDI_PROTOCOL) - #define ENABLE_PDI_PROTOCOL - #endif - #endif - - /* Defines: */ - #define NVM_BUSY_TIMEOUT_MS 200 - - #define NVM_REG_ADDR0 0x00 - #define NVM_REG_ADDR1 0x01 - #define NVM_REG_ADDR2 0x02 - #define NVM_REG_DAT0 0x04 - #define NVM_REG_DAT1 0x05 - #define NVM_REG_DAT2 0x06 - #define NVM_REG_CMD 0x0A - #define NVM_REG_CTRLA 0x0B - #define NVM_REG_CTRLB 0x0C - #define NVM_REG_INTCTRL 0x0D - #define NVM_REG_STATUS 0x0F - #define NVM_REG_LOCKBITS 0x10 - - #define NVM_CMD_NOOP 0x00 - #define NVM_CMD_CHIPERASE 0x40 - #define NVM_CMD_READNVM 0x43 - #define NVM_CMD_LOADFLASHPAGEBUFF 0x23 - #define NVM_CMD_ERASEFLASHPAGEBUFF 0x26 - #define NVM_CMD_ERASEFLASHPAGE 0x2B - #define NVM_CMD_WRITEFLASHPAGE 0x2E - #define NVM_CMD_ERASEWRITEFLASH 0x2F - #define NVM_CMD_FLASHCRC 0x78 - #define NVM_CMD_ERASEAPPSEC 0x20 - #define NVM_CMD_ERASEAPPSECPAGE 0x22 - #define NVM_CMD_WRITEAPPSECPAGE 0x24 - #define NVM_CMD_ERASEWRITEAPPSECPAGE 0x25 - #define NVM_CMD_APPCRC 0x38 - #define NVM_CMD_ERASEBOOTSEC 0x68 - #define NVM_CMD_ERASEBOOTSECPAGE 0x2A - #define NVM_CMD_WRITEBOOTSECPAGE 0x2C - #define NVM_CMD_ERASEWRITEBOOTSECPAGE 0x2D - #define NVM_CMD_BOOTCRC 0x39 - #define NVM_CMD_READUSERSIG 0x03 - #define NVM_CMD_ERASEUSERSIG 0x18 - #define NVM_CMD_WRITEUSERSIG 0x1A - #define NVM_CMD_READCALIBRATION 0x02 - #define NVM_CMD_READFUSE 0x07 - #define NVM_CMD_WRITEFUSE 0x4C - #define NVM_CMD_WRITELOCK 0x08 - #define NVM_CMD_LOADEEPROMPAGEBUFF 0x33 - #define NVM_CMD_ERASEEEPROMPAGEBUFF 0x36 - #define NVM_CMD_ERASEEEPROM 0x30 - #define NVM_CMD_ERASEEEPROMPAGE 0x32 - #define NVM_CMD_WRITEEEPROMPAGE 0x34 - #define NVM_CMD_ERASEWRITEEEPROMPAGE 0x35 - #define NVM_CMD_READEEPROM 0x06 - - /* Function Prototypes: */ - void NVMTarget_SendNVMRegAddress(const uint8_t Register); - void NVMTarget_SendAddress(const uint32_t AbsoluteAddress); - bool NVMTarget_WaitWhileNVMControllerBusy(void); - bool NVMTarget_GetMemoryCRC(const uint8_t CRCCommand, uint32_t* const CRCDest); - bool NVMTarget_ReadMemory(const uint32_t ReadAddress, uint8_t* ReadBuffer, const uint16_t ReadSize); - bool NVMTarget_WriteByteMemory(const uint8_t WriteCommand, const uint32_t WriteAddress, const uint8_t* WriteBuffer); - bool NVMTarget_WritePageMemory(const uint8_t WriteBuffCommand, const uint8_t EraseBuffCommand, - const uint8_t WritePageCommand, const uint8_t PageMode, const uint32_t WriteAddress, - const uint8_t* WriteBuffer, const uint16_t WriteSize); - bool NVMTarget_EraseMemory(const uint8_t EraseCommand, const uint32_t Address); - -#endif diff --git a/Projects/AVRISP/Lib/PDIProtocol.h b/Projects/AVRISP/Lib/PDIProtocol.h index 137bcc2cf..f2c38d596 100644 --- a/Projects/AVRISP/Lib/PDIProtocol.h +++ b/Projects/AVRISP/Lib/PDIProtocol.h @@ -43,11 +43,12 @@ #include "V2Protocol.h" #include "PDITarget.h" - #include "NVMTarget.h" + #include "XMEGANVM.h" /* Preprocessor Checks: */ #if ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1)) #undef ENABLE_ISP_PROTOCOL + #undef ENABLE_TPI_PROTOCOL #if !defined(ENABLE_PDI_PROTOCOL) #define ENABLE_PDI_PROTOCOL diff --git a/Projects/AVRISP/Lib/PDITarget.c b/Projects/AVRISP/Lib/PDITarget.c index 29bb33985..2c6ffd9a6 100644 --- a/Projects/AVRISP/Lib/PDITarget.c +++ b/Projects/AVRISP/Lib/PDITarget.c @@ -67,13 +67,13 @@ ISR(TIMER1_COMPA_vect, ISR_BLOCK) return; /* Wait for the start bit when receiving */ - if ((SoftUSART_BitCount == BITS_IN_FRAME) && (BITBANG_PDIDATA_PIN & BITBANG_PDIDATA_MASK)) + if ((SoftUSART_BitCount == BITS_IN_PDI_FRAME) && (BITBANG_PDIDATA_PIN & BITBANG_PDIDATA_MASK)) return; /* Shift in the bit one less than the frame size in position, so that the start bit will eventually * be discarded leaving the data to be byte-aligned for quick access */ if (BITBANG_PDIDATA_PIN & BITBANG_PDIDATA_MASK) - SoftUSART_Data |= (1 << (BITS_IN_FRAME - 1)); + SoftUSART_Data |= (1 << (BITS_IN_PDI_FRAME - 1)); SoftUSART_Data >>= 1; SoftUSART_BitCount--; @@ -133,6 +133,7 @@ void PDITarget_EnableTargetPDI(void) TCCR1B = (1 << WGM12) | (1 << CS10); TIMSK1 = (1 << OCIE1A); + /* Send two BREAKs of 12 bits each to enable TPI interface (need at least 16 idle bits) */ PDITarget_SendBreak(); PDITarget_SendBreak(); #endif @@ -158,8 +159,6 @@ void PDITarget_DisableTargetPDI(void) /* Tristate DATA and CLOCK lines */ BITBANG_PDIDATA_PORT &= ~BITBANG_PDIDATA_MASK; BITBANG_PDICLOCK_PORT &= ~BITBANG_PDICLOCK_MASK; - - TCCR0B = 0; #endif } @@ -212,7 +211,7 @@ void PDITarget_SendByte(const uint8_t Byte) /* Data shifted out LSB first, START DATA PARITY STOP STOP */ SoftUSART_Data = NewUSARTData; - SoftUSART_BitCount = BITS_IN_FRAME; + SoftUSART_BitCount = BITS_IN_PDI_FRAME; #endif } @@ -254,7 +253,7 @@ uint8_t PDITarget_ReceiveByte(void) } /* Wait until a byte has been received before reading */ - SoftUSART_BitCount = BITS_IN_FRAME; + SoftUSART_BitCount = BITS_IN_PDI_FRAME; while (SoftUSART_BitCount); /* Throw away the parity and stop bits to leave only the data (start bit is already discarded) */ @@ -279,7 +278,7 @@ void PDITarget_SendBreak(void) } /* Need to do nothing for a full frame to send a BREAK */ - for (uint8_t i = 0; i < BITS_IN_FRAME; i++) + for (uint8_t i = 0; i < BITS_IN_PDI_FRAME; i++) { /* Wait for a full cycle of the clock */ while (PIND & (1 << 5)); @@ -299,7 +298,7 @@ void PDITarget_SendBreak(void) /* Need to do nothing for a full frame to send a BREAK */ SoftUSART_Data = 0x0FFF; - SoftUSART_BitCount = BITS_IN_FRAME; + SoftUSART_BitCount = BITS_IN_PDI_FRAME; #endif } diff --git a/Projects/AVRISP/Lib/PDITarget.h b/Projects/AVRISP/Lib/PDITarget.h index 3758489a7..da89d55f1 100644 --- a/Projects/AVRISP/Lib/PDITarget.h +++ b/Projects/AVRISP/Lib/PDITarget.h @@ -46,6 +46,7 @@ /* Preprocessor Checks: */ #if ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1)) #undef ENABLE_ISP_PROTOCOL + #undef ENABLE_TPI_PROTOCOL #if !defined(ENABLE_PDI_PROTOCOL) #define ENABLE_PDI_PROTOCOL @@ -67,7 +68,7 @@ #define BITBANG_PDICLOCK_MASK RESET_LINE_MASK #endif - #define BITS_IN_FRAME 12 + #define BITS_IN_PDI_FRAME 12 #define PDI_NVM_TIMEOUT_MS 200 diff --git a/Projects/AVRISP/Lib/TPITarget.c b/Projects/AVRISP/Lib/TPITarget.c new file mode 100644 index 000000000..8b47006c9 --- /dev/null +++ b/Projects/AVRISP/Lib/TPITarget.c @@ -0,0 +1,320 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * Target-related functions for the TPI Protocol decoder. + */ + +#define INCLUDE_FROM_TPITARGET_C +#include "TPITarget.h" + +#if defined(ENABLE_TPI_PROTOCOL) || defined(__DOXYGEN__) + +/** Flag to indicate if the USART is currently in Tx or Rx mode. */ +volatile bool IsSending; + +#if !defined(TPI_VIA_HARDWARE_USART) +/** Software USART raw frame bits for transmission/reception. */ +volatile uint16_t SoftUSART_Data; + +/** Bits remaining to be sent or received via the software USART - set as a GPIOR for speed. */ +#define SoftUSART_BitCount GPIOR2 + + +/** ISR to manage the software USART when bit-banged USART mode is selected. */ +ISR(TIMER1_CAPT_vect, ISR_BLOCK) +{ + /* Toggle CLOCK pin in a single cycle (see AVR datasheet) */ + BITBANG_TPICLOCK_PIN |= BITBANG_TPICLOCK_MASK; + + /* If not sending or receiving, just exit */ + if (!(SoftUSART_BitCount)) + return; + + /* Check to see if we are at a rising or falling edge of the clock */ + if (BITBANG_TPICLOCK_PORT & BITBANG_TPICLOCK_MASK) + { + /* If at rising clock edge and we are in send mode, abort */ + if (IsSending) + return; + + /* Wait for the start bit when receiving */ + if ((SoftUSART_BitCount == BITS_IN_TPI_FRAME) && (BITBANG_TPIDATA_PIN & BITBANG_TPIDATA_MASK)) + return; + + /* Shift in the bit one less than the frame size in position, so that the start bit will eventually + * be discarded leaving the data to be byte-aligned for quick access */ + if (BITBANG_TPIDATA_PIN & BITBANG_TPIDATA_MASK) + SoftUSART_Data |= (1 << (BITS_IN_TPI_FRAME - 1)); + + SoftUSART_Data >>= 1; + SoftUSART_BitCount--; + } + else + { + /* If at falling clock edge and we are in receive mode, abort */ + if (!IsSending) + return; + + /* Set the data line to the next bit value */ + if (SoftUSART_Data & 0x01) + BITBANG_TPIDATA_PORT |= BITBANG_TPIDATA_MASK; + else + BITBANG_TPIDATA_PORT &= ~BITBANG_TPIDATA_MASK; + + SoftUSART_Data >>= 1; + SoftUSART_BitCount--; + } +} +#endif + +/** Enables the target's TPI interface, holding the target in reset until TPI mode is exited. */ +void TPITarget_EnableTargetTPI(void) +{ + /* Set /RESET line low for at least 90ns to enable TPI functionality */ + RESET_LINE_DDR |= RESET_LINE_MASK; + RESET_LINE_PORT &= ~RESET_LINE_MASK; + asm volatile ("NOP"::); + asm volatile ("NOP"::); + +#if defined(TPI_VIA_HARDWARE_USART) + /* Set Tx and XCK as outputs, Rx as input */ + DDRD |= (1 << 5) | (1 << 3); + DDRD &= ~(1 << 2); + + /* Set up the synchronous USART for XMEGA communications - + 8 data bits, even parity, 2 stop bits */ + UBRR1 = (F_CPU / 1000000UL); + UCSR1B = (1 << TXEN1); + UCSR1C = (1 << UMSEL10) | (1 << UPM11) | (1 << USBS1) | (1 << UCSZ11) | (1 << UCSZ10) | (1 << UCPOL1); + + /* Send two BREAKs of 12 bits each to enable TPI interface (need at least 16 idle bits) */ + TPITarget_SendBreak(); + TPITarget_SendBreak(); +#else + /* Set DATA and CLOCK lines to outputs */ + BITBANG_TPIDATA_DDR |= BITBANG_TPIDATA_MASK; + BITBANG_TPICLOCK_DDR |= BITBANG_TPICLOCK_MASK; + + /* Set DATA line high for idle state */ + BITBANG_TPIDATA_PORT |= BITBANG_TPIDATA_MASK; + + /* Fire timer capture ISR every 100 cycles to manage the software USART */ + OCR1A = 80; + TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS10); + TIMSK1 = (1 << ICIE1); + + /* Send two BREAKs of 12 bits each to enable TPI interface (need at least 16 idle bits) */ + TPITarget_SendBreak(); + TPITarget_SendBreak(); +#endif +} + +/** Disables the target's TPI interface, exits programming mode and starts the target's application. */ +void TPITarget_DisableTargetTPI(void) +{ +#if defined(TPI_VIA_HARDWARE_USART) + /* Turn off receiver and transmitter of the USART, clear settings */ + UCSR1A |= (1 << TXC1) | (1 << RXC1); + UCSR1B = 0; + UCSR1C = 0; + + /* Set all USART lines as input, tristate */ + DDRD &= ~((1 << 5) | (1 << 3)); + PORTD &= ~((1 << 5) | (1 << 3) | (1 << 2)); +#else + /* Set DATA and CLOCK lines to inputs */ + BITBANG_TPIDATA_DDR &= ~BITBANG_TPIDATA_MASK; + BITBANG_TPICLOCK_DDR &= ~BITBANG_TPICLOCK_MASK; + + /* Tristate DATA and CLOCK lines */ + BITBANG_TPIDATA_PORT &= ~BITBANG_TPIDATA_MASK; + BITBANG_TPICLOCK_PORT &= ~BITBANG_TPICLOCK_MASK; +#endif + + /* Tristate target /RESET line */ + RESET_LINE_DDR &= ~RESET_LINE_MASK; + RESET_LINE_PORT &= ~RESET_LINE_MASK; +} + +/** Sends a byte via the USART. + * + * \param[in] Byte Byte to send through the USART + */ +void TPITarget_SendByte(const uint8_t Byte) +{ +#if defined(TPI_VIA_HARDWARE_USART) + /* Switch to Tx mode if currently in Rx mode */ + if (!(IsSending)) + { + PORTD |= (1 << 3); + DDRD |= (1 << 3); + + UCSR1B |= (1 << TXEN1); + UCSR1B &= ~(1 << RXEN1); + + IsSending = true; + } + + /* Wait until there is space in the hardware Tx buffer before writing */ + while (!(UCSR1A & (1 << UDRE1))); + UCSR1A |= (1 << TXC1); + UDR1 = Byte; +#else + /* Switch to Tx mode if currently in Rx mode */ + if (!(IsSending)) + { + BITBANG_TPIDATA_PORT |= BITBANG_TPIDATA_MASK; + BITBANG_TPIDATA_DDR |= BITBANG_TPIDATA_MASK; + + IsSending = true; + } + + /* Calculate the new USART frame data here while while we wait for a previous byte (if any) to finish sending */ + uint16_t NewUSARTData = ((1 << 11) | (1 << 10) | (0 << 9) | ((uint16_t)Byte << 1) | (0 << 0)); + + /* Compute Even parity - while a bit is still set, chop off lowest bit and toggle parity bit */ + uint8_t ParityData = Byte; + while (ParityData) + { + NewUSARTData ^= (1 << 9); + ParityData &= (ParityData - 1); + } + + /* Wait until transmitter is idle before writing new data */ + while (SoftUSART_BitCount); + + /* Data shifted out LSB first, START DATA PARITY STOP STOP */ + SoftUSART_Data = NewUSARTData; + SoftUSART_BitCount = BITS_IN_TPI_FRAME; +#endif +} + +/** Receives a byte via the software USART, blocking until data is received. + * + * \return Received byte from the USART + */ +uint8_t TPITarget_ReceiveByte(void) +{ +#if defined(TPI_VIA_HARDWARE_USART) + /* Switch to Rx mode if currently in Tx mode */ + if (IsSending) + { + while (!(UCSR1A & (1 << TXC1))); + UCSR1A |= (1 << TXC1); + + UCSR1B &= ~(1 << TXEN1); + UCSR1B |= (1 << RXEN1); + + DDRD &= ~(1 << 3); + PORTD &= ~(1 << 3); + + IsSending = false; + } + + /* Wait until a byte has been received before reading */ + while (!(UCSR1A & (1 << RXC1))); + return UDR1; +#else + /* Switch to Rx mode if currently in Tx mode */ + if (IsSending) + { + while (SoftUSART_BitCount); + + BITBANG_TPIDATA_DDR &= ~BITBANG_TPIDATA_MASK; + BITBANG_TPIDATA_PORT &= ~BITBANG_TPIDATA_MASK; + + IsSending = false; + } + + /* Wait until a byte has been received before reading */ + SoftUSART_BitCount = BITS_IN_TPI_FRAME; + while (SoftUSART_BitCount); + + /* Throw away the parity and stop bits to leave only the data (start bit is already discarded) */ + return (uint8_t)SoftUSART_Data; +#endif +} + +/** Sends a BREAK via the USART to the attached target, consisting of a full frame of idle bits. */ +void TPITarget_SendBreak(void) +{ +#if defined(TPI_VIA_HARDWARE_USART) + /* Switch to Tx mode if currently in Rx mode */ + if (!(IsSending)) + { + PORTD |= (1 << 3); + DDRD |= (1 << 3); + + UCSR1B &= ~(1 << RXEN1); + UCSR1B |= (1 << TXEN1); + + IsSending = true; + } + + /* Need to do nothing for a full frame to send a BREAK */ + for (uint8_t i = 0; i < BITS_IN_TPI_FRAME; i++) + { + /* Wait for a full cycle of the clock */ + while (PIND & (1 << 5)); + while (!(PIND & (1 << 5))); + } +#else + /* Switch to Tx mode if currently in Rx mode */ + if (!(IsSending)) + { + BITBANG_TPIDATA_PORT |= BITBANG_TPIDATA_MASK; + BITBANG_TPIDATA_DDR |= BITBANG_TPIDATA_MASK; + + IsSending = true; + } + + while (SoftUSART_BitCount); + + /* Need to do nothing for a full frame to send a BREAK */ + SoftUSART_Data = 0x0FFF; + SoftUSART_BitCount = BITS_IN_TPI_FRAME; +#endif +} + +/** Busy-waits while the NVM controller is busy performing a NVM operation, such as a FLASH page read or CRC + * calculation. + * + * \return Boolean true if the NVM controller became ready within the timeout period, false otherwise + */ +bool TPITarget_WaitWhileNVMBusBusy(void) +{ + // TODO + + return false; +} + +#endif diff --git a/Projects/AVRISP/Lib/TPITarget.h b/Projects/AVRISP/Lib/TPITarget.h new file mode 100644 index 000000000..715af16d1 --- /dev/null +++ b/Projects/AVRISP/Lib/TPITarget.h @@ -0,0 +1,81 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * Header file for TPITarget.c. + */ + +#ifndef _TPI_TARGET_ +#define _TPI_TARGET_ + + /* Includes: */ + #include + #include + #include + + #include + + /* Preprocessor Checks: */ + #if ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1)) + #undef ENABLE_ISP_PROTOCOL + #undef ENABLE_TPI_PROTOCOL + + #if !defined(ENABLE_PDI_PROTOCOL) + #define ENABLE_PDI_PROTOCOL + #endif + #endif + + /* Defines: */ + #define BITBANG_TPIDATA_PORT PORTB + #define BITBANG_TPIDATA_DDR DDRB + #define BITBANG_TPIDATA_PIN PINB + #define BITBANG_TPIDATA_MASK (1 << 3) + + #define BITBANG_TPICLOCK_PORT PORTB + #define BITBANG_TPICLOCK_DDR DDRB + #define BITBANG_TPICLOCK_PIN PINB + #define BITBANG_TPICLOCK_MASK (1 << 1) + + #define BITS_IN_TPI_FRAME 12 + + #define TPI_NVM_TIMEOUT_MS 200 + + #define TPI_NVMENABLE_KEY (uint8_t[]){0x12, 0x89, 0xAB, 0x45, 0xCD, 0xD8, 0x88, 0xFF} + + /* Function Prototypes: */ + void TPITarget_EnableTargetTPI(void); + void TPITarget_DisableTargetTPI(void); + void TPITarget_SendByte(const uint8_t Byte); + uint8_t TPITarget_ReceiveByte(void); + void TPITarget_SendBreak(void); + bool TPITarget_WaitWhileNVMBusBusy(void); + +#endif diff --git a/Projects/AVRISP/Lib/V2Protocol.h b/Projects/AVRISP/Lib/V2Protocol.h index 1777e0fe1..4ea1cba19 100644 --- a/Projects/AVRISP/Lib/V2Protocol.h +++ b/Projects/AVRISP/Lib/V2Protocol.h @@ -49,6 +49,7 @@ /* Preprocessor Checks: */ #if ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1)) #undef ENABLE_ISP_PROTOCOL + #undef ENABLE_TPI_PROTOCOL #if !defined(ENABLE_PDI_PROTOCOL) #define ENABLE_PDI_PROTOCOL diff --git a/Projects/AVRISP/Lib/XMEGANVM.c b/Projects/AVRISP/Lib/XMEGANVM.c new file mode 100644 index 000000000..adf213bb4 --- /dev/null +++ b/Projects/AVRISP/Lib/XMEGANVM.c @@ -0,0 +1,332 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * Target-related functions for the target's NVM module. + */ + +#define INCLUDE_FROM_NVMTARGET_C +#include "NVMTarget.h" + +#if defined(ENABLE_PDI_PROTOCOL) || defined(__DOXYGEN__) + +/** Sends the given NVM register address to the target. + * + * \param[in] Register NVM register whose absolute address is to be sent + */ +void NVMTarget_SendNVMRegAddress(const uint8_t Register) +{ + /* Determine the absolute register address from the NVM base memory address and the NVM register address */ + uint32_t Address = XPROG_Param_NVMBase | Register; + + /* Send the calculated 32-bit address to the target, LSB first */ + NVMTarget_SendAddress(Address); +} + +/** Sends the given 32-bit absolute address to the target. + * + * \param[in] AbsoluteAddress Absolute address to send to the target + */ +void NVMTarget_SendAddress(const uint32_t AbsoluteAddress) +{ + /* Send the given 32-bit address to the target, LSB first */ + PDITarget_SendByte(AbsoluteAddress & 0xFF); + PDITarget_SendByte(AbsoluteAddress >> 8); + PDITarget_SendByte(AbsoluteAddress >> 16); + PDITarget_SendByte(AbsoluteAddress >> 24); +} + +/** Waits while the target's NVM controller is busy performing an operation, exiting if the + * timeout period expires. + * + * \return Boolean true if the NVM controller became ready within the timeout period, false otherwise + */ +bool NVMTarget_WaitWhileNVMControllerBusy(void) +{ + TCNT0 = 0; + TIFR0 = (1 << OCF1A); + + uint8_t TimeoutMS = PDI_NVM_TIMEOUT_MS; + + /* Poll the NVM STATUS register while the NVM controller is busy */ + while (TimeoutMS) + { + /* Send a LDS command to read the NVM STATUS register to check the BUSY flag */ + PDITarget_SendByte(PDI_CMD_LDS | (PDI_DATSIZE_4BYTES << 2)); + NVMTarget_SendNVMRegAddress(NVM_REG_STATUS); + + /* Check to see if the BUSY flag is still set */ + if (!(PDITarget_ReceiveByte() & (1 << 7))) + return true; + + if (TIFR0 & (1 << OCF1A)) + { + TIFR0 = (1 << OCF1A); + TimeoutMS--; + } + } + + return false; +} + +/** Retrieves the CRC value of the given memory space. + * + * \param[in] CRCCommand NVM CRC command to issue to the target + * \param[out] CRCDest CRC Destination when read from the target + * + * \return Boolean true if the command sequence complete successfully + */ +bool NVMTarget_GetMemoryCRC(const uint8_t CRCCommand, uint32_t* const CRCDest) +{ + /* Wait until the NVM controller is no longer busy */ + if (!(NVMTarget_WaitWhileNVMControllerBusy())) + return false; + + /* Set the NVM command to the correct CRC read command */ + PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2)); + NVMTarget_SendNVMRegAddress(NVM_REG_CMD); + PDITarget_SendByte(CRCCommand); + + /* Set CMDEX bit in NVM CTRLA register to start the CRC generation */ + PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2)); + NVMTarget_SendNVMRegAddress(NVM_REG_CTRLA); + PDITarget_SendByte(1 << 0); + + /* Wait until the NVM bus is ready again */ + if (!(PDITarget_WaitWhileNVMBusBusy())) + return false; + + /* Wait until the NVM controller is no longer busy */ + if (!(NVMTarget_WaitWhileNVMControllerBusy())) + return false; + + *CRCDest = 0; + + /* Read the first generated CRC byte value */ + PDITarget_SendByte(PDI_CMD_LDS | (PDI_DATSIZE_4BYTES << 2)); + NVMTarget_SendNVMRegAddress(NVM_REG_DAT0); + *CRCDest = PDITarget_ReceiveByte(); + + /* Read the second generated CRC byte value */ + PDITarget_SendByte(PDI_CMD_LDS | (PDI_DATSIZE_4BYTES << 2)); + NVMTarget_SendNVMRegAddress(NVM_REG_DAT1); + *CRCDest |= ((uint16_t)PDITarget_ReceiveByte() << 8); + + /* Read the third generated CRC byte value */ + PDITarget_SendByte(PDI_CMD_LDS | (PDI_DATSIZE_4BYTES << 2)); + NVMTarget_SendNVMRegAddress(NVM_REG_DAT2); + *CRCDest |= ((uint32_t)PDITarget_ReceiveByte() << 16); + + return true; +} + +/** Reads memory from the target's memory spaces. + * + * \param[in] ReadAddress Start address to read from within the target's address space + * \param[out] ReadBuffer Buffer to store read data into + * \param[in] ReadSize Number of bytes to read + * + * \return Boolean true if the command sequence complete successfully + */ +bool NVMTarget_ReadMemory(const uint32_t ReadAddress, uint8_t* ReadBuffer, const uint16_t ReadSize) +{ + /* Wait until the NVM controller is no longer busy */ + if (!(NVMTarget_WaitWhileNVMControllerBusy())) + return false; + + /* Send the READNVM command to the NVM controller for reading of an arbitrary location */ + PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2)); + NVMTarget_SendNVMRegAddress(NVM_REG_CMD); + PDITarget_SendByte(NVM_CMD_READNVM); + + /* Load the PDI pointer register with the start address we want to read from */ + PDITarget_SendByte(PDI_CMD_ST | (PDI_POINTER_DIRECT << 2) | PDI_DATSIZE_4BYTES); + NVMTarget_SendAddress(ReadAddress); + + /* Send the REPEAT command with the specified number of bytes to read */ + PDITarget_SendByte(PDI_CMD_REPEAT | PDI_DATSIZE_1BYTE); + PDITarget_SendByte(ReadSize - 1); + + /* Send a LD command with indirect access and postincrement to read out the bytes */ + PDITarget_SendByte(PDI_CMD_LD | (PDI_POINTER_INDIRECT_PI << 2) | PDI_DATSIZE_1BYTE); + for (uint16_t i = 0; i < ReadSize; i++) + *(ReadBuffer++) = PDITarget_ReceiveByte(); + + return true; +} + +/** Writes byte addressed memory to the target's memory spaces. + * + * \param[in] WriteCommand Command to send to the device to write each memory byte + * \param[in] WriteAddress Start address to write to within the target's address space + * \param[in] WriteBuffer Buffer to source data from + * + * \return Boolean true if the command sequence complete successfully + */ +bool NVMTarget_WriteByteMemory(const uint8_t WriteCommand, const uint32_t WriteAddress, const uint8_t* WriteBuffer) +{ + /* Wait until the NVM controller is no longer busy */ + if (!(NVMTarget_WaitWhileNVMControllerBusy())) + return false; + + /* Send the memory write command to the target */ + PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2)); + NVMTarget_SendNVMRegAddress(NVM_REG_CMD); + PDITarget_SendByte(WriteCommand); + + /* Send new memory byte to the memory to the target */ + PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2)); + NVMTarget_SendAddress(WriteAddress); + PDITarget_SendByte(*(WriteBuffer++)); + + return true; +} + +/** Writes page addressed memory to the target's memory spaces. + * + * \param[in] WriteBuffCommand Command to send to the device to write a byte to the memory page buffer + * \param[in] EraseBuffCommand Command to send to the device to erase the memory page buffer + * \param[in] WritePageCommand Command to send to the device to write the page buffer to the destination memory + * \param[in] PageMode Bitfield indicating what operations need to be executed on the specified page + * \param[in] WriteAddress Start address to write the page data to within the target's address space + * \param[in] WriteBuffer Buffer to source data from + * \param[in] WriteSize Number of bytes to write + * + * \return Boolean true if the command sequence complete successfully + */ +bool NVMTarget_WritePageMemory(const uint8_t WriteBuffCommand, const uint8_t EraseBuffCommand, + const uint8_t WritePageCommand, const uint8_t PageMode, const uint32_t WriteAddress, + const uint8_t* WriteBuffer, const uint16_t WriteSize) +{ + if (PageMode & XPRG_PAGEMODE_ERASE) + { + /* Wait until the NVM controller is no longer busy */ + if (!(NVMTarget_WaitWhileNVMControllerBusy())) + return false; + + /* Send the memory buffer erase command to the target */ + PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2)); + NVMTarget_SendNVMRegAddress(NVM_REG_CMD); + PDITarget_SendByte(EraseBuffCommand); + + /* Set CMDEX bit in NVM CTRLA register to start the buffer erase */ + PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2)); + NVMTarget_SendNVMRegAddress(NVM_REG_CTRLA); + PDITarget_SendByte(1 << 0); + } + + if (WriteSize) + { + /* Wait until the NVM controller is no longer busy */ + if (!(NVMTarget_WaitWhileNVMControllerBusy())) + return false; + + /* Send the memory buffer write command to the target */ + PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2)); + NVMTarget_SendNVMRegAddress(NVM_REG_CMD); + PDITarget_SendByte(WriteBuffCommand); + + /* Load the PDI pointer register with the start address we want to write to */ + PDITarget_SendByte(PDI_CMD_ST | (PDI_POINTER_DIRECT << 2) | PDI_DATSIZE_4BYTES); + NVMTarget_SendAddress(WriteAddress); + + /* Send the REPEAT command with the specified number of bytes to write */ + PDITarget_SendByte(PDI_CMD_REPEAT | PDI_DATSIZE_1BYTE); + PDITarget_SendByte(WriteSize - 1); + + /* Send a ST command with indirect access and postincrement to write the bytes */ + PDITarget_SendByte(PDI_CMD_ST | (PDI_POINTER_INDIRECT_PI << 2) | PDI_DATSIZE_1BYTE); + for (uint16_t i = 0; i < WriteSize; i++) + PDITarget_SendByte(*(WriteBuffer++)); + } + + if (PageMode & XPRG_PAGEMODE_WRITE) + { + /* Wait until the NVM controller is no longer busy */ + if (!(NVMTarget_WaitWhileNVMControllerBusy())) + return false; + + /* Send the memory write command to the target */ + PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2)); + NVMTarget_SendNVMRegAddress(NVM_REG_CMD); + PDITarget_SendByte(WritePageCommand); + + /* Send the address of the first page location to write the memory page */ + PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2)); + NVMTarget_SendAddress(WriteAddress); + PDITarget_SendByte(0x00); + } + + return true; +} + +/** Erases a specific memory space of the target. + * + * \param[in] EraseCommand NVM erase command to send to the device + * \param[in] Address Address inside the memory space to erase + * + * \return Boolean true if the command sequence complete successfully + */ +bool NVMTarget_EraseMemory(const uint8_t EraseCommand, const uint32_t Address) +{ + /* Wait until the NVM controller is no longer busy */ + if (!(NVMTarget_WaitWhileNVMControllerBusy())) + return false; + + /* Send the memory erase command to the target */ + PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2)); + NVMTarget_SendNVMRegAddress(NVM_REG_CMD); + PDITarget_SendByte(EraseCommand); + + /* Chip erase is handled separately, since it's procedure is different to other erase types */ + if (EraseCommand == NVM_CMD_CHIPERASE) + { + /* Set CMDEX bit in NVM CTRLA register to start the chip erase */ + PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2)); + NVMTarget_SendNVMRegAddress(NVM_REG_CTRLA); + PDITarget_SendByte(1 << 0); + } + else + { + /* Other erase modes just need us to address a byte within the target memory space */ + PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2)); + NVMTarget_SendAddress(Address); + PDITarget_SendByte(0x00); + } + + /* Wait until the NVM bus is ready again */ + if (!(PDITarget_WaitWhileNVMBusBusy())) + return false; + + return true; +} + +#endif diff --git a/Projects/AVRISP/Lib/XMEGANVM.h b/Projects/AVRISP/Lib/XMEGANVM.h new file mode 100644 index 000000000..a8f3c493d --- /dev/null +++ b/Projects/AVRISP/Lib/XMEGANVM.h @@ -0,0 +1,121 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2009. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, and distribute this software + and its documentation for any purpose and without fee is hereby + granted, provided that the above copyright notice appear in all + copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * Header file for NVMTarget.c. + */ + +#ifndef _NVM_TARGET_ +#define _NVM_TARGET_ + + /* Includes: */ + #include + #include + #include + + #include + + #include "PDIProtocol.h" + #include "PDITarget.h" + + /* Preprocessor Checks: */ + #if ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1)) + #undef ENABLE_ISP_PROTOCOL + #undef ENABLE_TPI_PROTOCOL + + #if !defined(ENABLE_PDI_PROTOCOL) + #define ENABLE_PDI_PROTOCOL + #endif + #endif + + /* Defines: */ + #define NVM_BUSY_TIMEOUT_MS 200 + + #define NVM_REG_ADDR0 0x00 + #define NVM_REG_ADDR1 0x01 + #define NVM_REG_ADDR2 0x02 + #define NVM_REG_DAT0 0x04 + #define NVM_REG_DAT1 0x05 + #define NVM_REG_DAT2 0x06 + #define NVM_REG_CMD 0x0A + #define NVM_REG_CTRLA 0x0B + #define NVM_REG_CTRLB 0x0C + #define NVM_REG_INTCTRL 0x0D + #define NVM_REG_STATUS 0x0F + #define NVM_REG_LOCKBITS 0x10 + + #define NVM_CMD_NOOP 0x00 + #define NVM_CMD_CHIPERASE 0x40 + #define NVM_CMD_READNVM 0x43 + #define NVM_CMD_LOADFLASHPAGEBUFF 0x23 + #define NVM_CMD_ERASEFLASHPAGEBUFF 0x26 + #define NVM_CMD_ERASEFLASHPAGE 0x2B + #define NVM_CMD_WRITEFLASHPAGE 0x2E + #define NVM_CMD_ERASEWRITEFLASH 0x2F + #define NVM_CMD_FLASHCRC 0x78 + #define NVM_CMD_ERASEAPPSEC 0x20 + #define NVM_CMD_ERASEAPPSECPAGE 0x22 + #define NVM_CMD_WRITEAPPSECPAGE 0x24 + #define NVM_CMD_ERASEWRITEAPPSECPAGE 0x25 + #define NVM_CMD_APPCRC 0x38 + #define NVM_CMD_ERASEBOOTSEC 0x68 + #define NVM_CMD_ERASEBOOTSECPAGE 0x2A + #define NVM_CMD_WRITEBOOTSECPAGE 0x2C + #define NVM_CMD_ERASEWRITEBOOTSECPAGE 0x2D + #define NVM_CMD_BOOTCRC 0x39 + #define NVM_CMD_READUSERSIG 0x03 + #define NVM_CMD_ERASEUSERSIG 0x18 + #define NVM_CMD_WRITEUSERSIG 0x1A + #define NVM_CMD_READCALIBRATION 0x02 + #define NVM_CMD_READFUSE 0x07 + #define NVM_CMD_WRITEFUSE 0x4C + #define NVM_CMD_WRITELOCK 0x08 + #define NVM_CMD_LOADEEPROMPAGEBUFF 0x33 + #define NVM_CMD_ERASEEEPROMPAGEBUFF 0x36 + #define NVM_CMD_ERASEEEPROM 0x30 + #define NVM_CMD_ERASEEEPROMPAGE 0x32 + #define NVM_CMD_WRITEEEPROMPAGE 0x34 + #define NVM_CMD_ERASEWRITEEEPROMPAGE 0x35 + #define NVM_CMD_READEEPROM 0x06 + + /* Function Prototypes: */ + void NVMTarget_SendNVMRegAddress(const uint8_t Register); + void NVMTarget_SendAddress(const uint32_t AbsoluteAddress); + bool NVMTarget_WaitWhileNVMControllerBusy(void); + bool NVMTarget_GetMemoryCRC(const uint8_t CRCCommand, uint32_t* const CRCDest); + bool NVMTarget_ReadMemory(const uint32_t ReadAddress, uint8_t* ReadBuffer, const uint16_t ReadSize); + bool NVMTarget_WriteByteMemory(const uint8_t WriteCommand, const uint32_t WriteAddress, const uint8_t* WriteBuffer); + bool NVMTarget_WritePageMemory(const uint8_t WriteBuffCommand, const uint8_t EraseBuffCommand, + const uint8_t WritePageCommand, const uint8_t PageMode, const uint32_t WriteAddress, + const uint8_t* WriteBuffer, const uint16_t WriteSize); + bool NVMTarget_EraseMemory(const uint8_t EraseCommand, const uint32_t Address); + +#endif diff --git a/Projects/AVRISP/makefile b/Projects/AVRISP/makefile index 2b6a1e858..ce47b13a1 100644 --- a/Projects/AVRISP/makefile +++ b/Projects/AVRISP/makefile @@ -133,7 +133,8 @@ SRC = $(TARGET).c \ Lib/ISPTarget.c \ Lib/PDIProtocol.c \ Lib/PDITarget.c \ - Lib/NVMTarget.c \ + Lib/XMEGANVM.c \ + Lib/TPITarget.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c \ $(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c \ @@ -197,6 +198,7 @@ CDEFS += -DRESET_LINE_MASK="(1 << 4)" CDEFS += -DVTARGET_ADC_CHANNEL=2 CDEFS += -DENABLE_ISP_PROTOCOL CDEFS += -DENABLE_PDI_PROTOCOL +CDEFS += -DENABLE_TPI_PROTOCOL # Place -D or -U options here for ASM sources -- cgit v1.2.3