Merge commit '60b30c0363' as 'lib/lufa'

This commit is contained in:
Jack Humbert 2017-07-07 11:55:23 -04:00
commit 8655d4f494
1455 changed files with 394541 additions and 0 deletions

View file

@ -0,0 +1,274 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, 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 disclaims 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 TINY target's NVM module.
*/
#define INCLUDE_FROM_TINYNVM_C
#include "TINYNVM.h"
#if defined(ENABLE_XPROG_PROTOCOL) || defined(__DOXYGEN__)
/** Sends the given pointer address to the target's TPI pointer register */
static void TINYNVM_SendPointerAddress(const uint16_t AbsoluteAddress)
{
/* Send the given 16-bit address to the target, LSB first */
XPROGTarget_SendByte(TPI_CMD_SSTPR | 0);
XPROGTarget_SendByte(AbsoluteAddress & 0xFF);
XPROGTarget_SendByte(TPI_CMD_SSTPR | 1);
XPROGTarget_SendByte(AbsoluteAddress >> 8);
}
/** Sends a SIN command to the target with the specified I/O address, ready for the data byte to be written.
*
* \param[in] Address 6-bit I/O address to write to in the target's I/O memory space
*/
static void TINYNVM_SendReadNVMRegister(const uint8_t Address)
{
/* The TPI command for reading from the I/O space uses strange addressing, where the I/O address's upper
* two bits of the 6-bit address are shifted left once - use function to reduce code size */
XPROGTarget_SendByte(TPI_CMD_SIN(Address));
}
/** Sends a SOUT command to the target with the specified I/O address, ready for the data byte to be read.
*
* \param[in] Address 6-bit I/O address to read from in the target's I/O memory space
*/
static void TINYNVM_SendWriteNVMRegister(const uint8_t Address)
{
/* The TPI command for reading from the I/O space uses strange addressing, where the I/O address's upper
* two bits of the 6-bit address are shifted left once - use function to reduce code size */
XPROGTarget_SendByte(TPI_CMD_SOUT(Address));
}
/** Busy-waits while the NVM controller is busy performing a NVM operation, such as a FLASH page read.
*
* \return Boolean \c true if the NVM controller became ready within the timeout period, \c false otherwise
*/
bool TINYNVM_WaitWhileNVMBusBusy(void)
{
/* Poll the STATUS register to check to see if NVM access has been enabled */
for (;;)
{
/* Send the SLDCS command to read the TPI STATUS register to see the NVM bus is active */
XPROGTarget_SendByte(TPI_CMD_SLDCS(TPI_REG_STATUS));
uint8_t StatusRegister = XPROGTarget_ReceiveByte();
/* We might have timed out waiting for the status register read response, check here */
if (!(TimeoutTicksRemaining))
return false;
/* Check the status register read response to see if the NVM bus is enabled */
if (StatusRegister & TPI_STATUS_NVM)
return true;
}
}
/** Waits while the target's NVM controller is busy performing an operation, exiting if the
* timeout period expires.
*
* \return Boolean \c true if the NVM controller became ready within the timeout period, \c false otherwise
*/
bool TINYNVM_WaitWhileNVMControllerBusy(void)
{
/* Poll the STATUS register to check to see if NVM access has been enabled */
for (;;)
{
/* Send the SIN command to read the TPI STATUS register to see the NVM bus is busy */
TINYNVM_SendReadNVMRegister(XPROG_Param_NVMCSRRegAddr);
uint8_t StatusRegister = XPROGTarget_ReceiveByte();
/* We might have timed out waiting for the status register read response, check here */
if (!(TimeoutTicksRemaining))
return false;
/* Check to see if the BUSY flag is still set */
if (!(StatusRegister & (1 << 7)))
return true;
}
}
/** Enables the physical TPI interface on the target and enables access to the internal NVM controller.
*
* \return Boolean \c true if the TPI interface was enabled successfully, \c false otherwise
*/
bool TINYNVM_EnableTPI(void)
{
/* Enable TPI programming mode with the attached target */
XPROGTarget_EnableTargetTPI();
/* Lower direction change guard time to 32 USART bits */
XPROGTarget_SendByte(TPI_CMD_SSTCS(TPI_REG_CTRL));
XPROGTarget_SendByte(0x02);
/* Enable access to the XPROG NVM bus by sending the documented NVM access key to the device */
XPROGTarget_SendByte(TPI_CMD_SKEY);
for (uint8_t i = sizeof(TPI_NVMENABLE_KEY); i > 0; i--)
XPROGTarget_SendByte(TPI_NVMENABLE_KEY[i - 1]);
/* Wait until the NVM bus becomes active */
return TINYNVM_WaitWhileNVMBusBusy();
}
/** Removes access to the target's NVM controller and physically disables the target's physical TPI interface. */
void TINYNVM_DisableTPI(void)
{
TINYNVM_WaitWhileNVMBusBusy();
do
{
/* Clear the NVMEN bit in the TPI STATUS register to disable TPI mode */
XPROGTarget_SendByte(TPI_CMD_SSTCS(TPI_REG_STATUS));
XPROGTarget_SendByte(0x00);
/* Read back the STATUS register, check to see if it took effect */
XPROGTarget_SendByte(TPI_CMD_SLDCS(TPI_REG_STATUS));
} while (XPROGTarget_ReceiveByte() != 0x00);
XPROGTarget_DisableTargetTPI();
}
/** 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 Length of the data to read from the device
*
* \return Boolean \c true if the command sequence complete successfully
*/
bool TINYNVM_ReadMemory(const uint16_t ReadAddress,
uint8_t* ReadBuffer,
uint16_t ReadSize)
{
/* Wait until the NVM controller is no longer busy */
if (!(TINYNVM_WaitWhileNVMControllerBusy()))
return false;
/* Set the NVM control register to the NO OP command for memory reading */
TINYNVM_SendWriteNVMRegister(XPROG_Param_NVMCMDRegAddr);
XPROGTarget_SendByte(TINY_NVM_CMD_NOOP);
/* Send the address of the location to read from */
TINYNVM_SendPointerAddress(ReadAddress);
while (ReadSize-- && TimeoutTicksRemaining)
{
/* Read the byte of data from the target */
XPROGTarget_SendByte(TPI_CMD_SLD(TPI_POINTER_INDIRECT_PI));
*(ReadBuffer++) = XPROGTarget_ReceiveByte();
}
return (TimeoutTicksRemaining > 0);
}
/** Writes word addressed memory to the target's memory spaces.
*
* \param[in] WriteAddress Start address to write to within the target's address space
* \param[in] WriteBuffer Buffer to source data from
* \param[in] WriteLength Total number of bytes to write to the device (must be an integer multiple of 2)
*
* \return Boolean \c true if the command sequence complete successfully
*/
bool TINYNVM_WriteMemory(const uint16_t WriteAddress,
uint8_t* WriteBuffer,
uint16_t WriteLength)
{
/* Wait until the NVM controller is no longer busy */
if (!(TINYNVM_WaitWhileNVMControllerBusy()))
return false;
/* Must have an integer number of words to write - if extra byte, word-align via a dummy high byte */
if (WriteLength & 0x01)
WriteBuffer[WriteLength++] = 0xFF;
/* Set the NVM control register to the WORD WRITE command for memory writing */
TINYNVM_SendWriteNVMRegister(XPROG_Param_NVMCMDRegAddr);
XPROGTarget_SendByte(TINY_NVM_CMD_WORDWRITE);
/* Send the address of the location to write to */
TINYNVM_SendPointerAddress(WriteAddress);
while (WriteLength)
{
/* Wait until the NVM controller is no longer busy */
if (!(TINYNVM_WaitWhileNVMControllerBusy()))
return false;
/* Write the low byte of data to the target */
XPROGTarget_SendByte(TPI_CMD_SST(TPI_POINTER_INDIRECT_PI));
XPROGTarget_SendByte(*(WriteBuffer++));
/* Write the high byte of data to the target */
XPROGTarget_SendByte(TPI_CMD_SST(TPI_POINTER_INDIRECT_PI));
XPROGTarget_SendByte(*(WriteBuffer++));
/* Need to decrement the write length twice, since we wrote a whole two-byte word */
WriteLength -= 2;
}
return true;
}
/** Erases the target's memory space.
*
* \param[in] EraseCommand NVM erase command to send to the device
* \param[in] Address Address inside the memory space to erase
*
* \return Boolean \c true if the command sequence complete successfully
*/
bool TINYNVM_EraseMemory(const uint8_t EraseCommand,
const uint16_t Address)
{
/* Wait until the NVM controller is no longer busy */
if (!(TINYNVM_WaitWhileNVMControllerBusy()))
return false;
/* Set the NVM control register to the target memory erase command */
TINYNVM_SendWriteNVMRegister(XPROG_Param_NVMCMDRegAddr);
XPROGTarget_SendByte(EraseCommand);
/* Write to a high byte location within the target address space to start the erase process */
TINYNVM_SendPointerAddress(Address | 0x0001);
XPROGTarget_SendByte(TPI_CMD_SST(TPI_POINTER_INDIRECT));
XPROGTarget_SendByte(0x00);
/* Wait until the NVM controller is no longer busy */
if (!(TINYNVM_WaitWhileNVMControllerBusy()))
return false;
return true;
}
#endif

View file

@ -0,0 +1,86 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, 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 disclaims 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 TINYNVM.c.
*/
#ifndef _TINY_NVM_
#define _TINY_NVM_
/* Includes: */
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdbool.h>
#include <LUFA/Common/Common.h>
#include "XPROGProtocol.h"
#include "XPROGTarget.h"
#include "Config/AppConfig.h"
/* Preprocessor Checks: */
#if ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1))
#undef ENABLE_ISP_PROTOCOL
#if !defined(ENABLE_XPROG_PROTOCOL)
#define ENABLE_XPROG_PROTOCOL
#endif
#endif
/* Defines: */
#define TINY_NVM_CMD_NOOP 0x00
#define TINY_NVM_CMD_CHIPERASE 0x10
#define TINY_NVM_CMD_SECTIONERASE 0x14
#define TINY_NVM_CMD_WORDWRITE 0x1D
/* Function Prototypes: */
bool TINYNVM_WaitWhileNVMBusBusy(void);
bool TINYNVM_WaitWhileNVMControllerBusy(void);
bool TINYNVM_EnableTPI(void);
void TINYNVM_DisableTPI(void);
bool TINYNVM_ReadMemory(const uint16_t ReadAddress,
uint8_t* ReadBuffer,
uint16_t ReadLength);
bool TINYNVM_WriteMemory(const uint16_t WriteAddress,
uint8_t* WriteBuffer,
uint16_t WriteLength);
bool TINYNVM_EraseMemory(const uint8_t EraseCommand,
const uint16_t Address);
#if (defined(INCLUDE_FROM_TINYNVM_C) && defined(ENABLE_XPROG_PROTOCOL))
static void TINYNVM_SendReadNVMRegister(const uint8_t Address);
static void TINYNVM_SendWriteNVMRegister(const uint8_t Address);
static void TINYNVM_SendPointerAddress(const uint16_t AbsoluteAddress);
#endif
#endif

View file

@ -0,0 +1,468 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, 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 disclaims 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 XMEGA target's NVM module.
*/
#define INCLUDE_FROM_XMEGA_NVM_C
#include "XMEGANVM.h"
#if defined(ENABLE_XPROG_PROTOCOL) || defined(__DOXYGEN__)
/** Sends the given 32-bit absolute address to the target.
*
* \param[in] AbsoluteAddress Absolute address to send to the target
*/
static void XMEGANVM_SendAddress(const uint32_t AbsoluteAddress)
{
/* Send the given 32-bit address to the target, LSB first */
XPROGTarget_SendByte(AbsoluteAddress & 0xFF);
XPROGTarget_SendByte(AbsoluteAddress >> 8);
XPROGTarget_SendByte(AbsoluteAddress >> 16);
XPROGTarget_SendByte(AbsoluteAddress >> 24);
}
/** Sends the given NVM register address to the target.
*
* \param[in] Register NVM register whose absolute address is to be sent
*/
static void XMEGANVM_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 */
XMEGANVM_SendAddress(Address);
}
/** Busy-waits while the NVM controller is busy performing a NVM operation, such as a FLASH page read or CRC
* calculation.
*
* \return Boolean \c true if the NVM controller became ready within the timeout period, \c false otherwise
*/
bool XMEGANVM_WaitWhileNVMBusBusy(void)
{
/* Poll the STATUS register to check to see if NVM access has been enabled */
for (;;)
{
/* Send the LDCS command to read the PDI STATUS register to see the NVM bus is active */
XPROGTarget_SendByte(PDI_CMD_LDCS(PDI_REG_STATUS));
uint8_t StatusRegister = XPROGTarget_ReceiveByte();
/* We might have timed out waiting for the status register read response, check here */
if (!(TimeoutTicksRemaining))
return false;
/* Check the status register read response to see if the NVM bus is enabled */
if (StatusRegister & PDI_STATUS_NVM)
return true;
}
}
/** Waits while the target's NVM controller is busy performing an operation, exiting if the
* timeout period expires.
*
* \return Boolean \c true if the NVM controller became ready within the timeout period, \c false otherwise
*/
bool XMEGANVM_WaitWhileNVMControllerBusy(void)
{
/* Preload the pointer register with the NVM STATUS register address to check the BUSY flag */
XPROGTarget_SendByte(PDI_CMD_ST(PDI_POINTER_DIRECT, PDI_DATASIZE_4BYTES));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_STATUS);
/* Poll the NVM STATUS register while the NVM controller is busy */
for (;;)
{
/* Fetch the current status value via the pointer register (without auto-increment afterwards) */
XPROGTarget_SendByte(PDI_CMD_LD(PDI_POINTER_INDIRECT, PDI_DATASIZE_1BYTE));
uint8_t StatusRegister = XPROGTarget_ReceiveByte();
/* We might have timed out waiting for the status register read response, check here */
if (!(TimeoutTicksRemaining))
return false;
/* Check to see if the BUSY flag is still set */
if (!(StatusRegister & (1 << 7)))
return true;
}
}
/** Enables the physical PDI interface on the target and enables access to the internal NVM controller.
*
* \return Boolean \c true if the PDI interface was enabled successfully, \c false otherwise
*/
bool XMEGANVM_EnablePDI(void)
{
/* Enable PDI programming mode with the attached target */
XPROGTarget_EnableTargetPDI();
/* Store the RESET key into the RESET PDI register to keep the XMEGA in reset */
XPROGTarget_SendByte(PDI_CMD_STCS(PDI_REG_RESET));
XPROGTarget_SendByte(PDI_RESET_KEY);
/* Lower direction change guard time to 32 USART bits */
XPROGTarget_SendByte(PDI_CMD_STCS(PDI_REG_CTRL));
XPROGTarget_SendByte(0x02);
/* Enable access to the XPROG NVM bus by sending the documented NVM access key to the device */
XPROGTarget_SendByte(PDI_CMD_KEY);
for (uint8_t i = sizeof(PDI_NVMENABLE_KEY); i > 0; i--)
XPROGTarget_SendByte(PDI_NVMENABLE_KEY[i - 1]);
/* Wait until the NVM bus becomes active */
return XMEGANVM_WaitWhileNVMBusBusy();
}
/** Removes access to the target's NVM controller and physically disables the target's physical PDI interface. */
void XMEGANVM_DisablePDI(void)
{
XMEGANVM_WaitWhileNVMBusBusy();
/* Clear the RESET key in the RESET PDI register to allow the XMEGA to run - must perform this until the
* change takes effect, as in some cases it takes multiple writes (silicon bug?).
*/
do
{
/* Clear reset register */
XPROGTarget_SendByte(PDI_CMD_STCS(PDI_REG_RESET));
XPROGTarget_SendByte(0x00);
/* Read back the reset register, check to see if it took effect */
XPROGTarget_SendByte(PDI_CMD_LDCS(PDI_REG_RESET));
} while (XPROGTarget_ReceiveByte() != 0x00);
XPROGTarget_DisableTargetPDI();
}
/** 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 \c true if the command sequence complete successfully
*/
bool XMEGANVM_GetMemoryCRC(const uint8_t CRCCommand,
uint32_t* const CRCDest)
{
*CRCDest = 0;
/* Wait until the NVM controller is no longer busy */
if (!(XMEGANVM_WaitWhileNVMControllerBusy()))
return false;
/* Set the NVM command to the correct CRC read command */
XPROGTarget_SendByte(PDI_CMD_STS(PDI_DATASIZE_4BYTES, PDI_DATASIZE_1BYTE));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CMD);
XPROGTarget_SendByte(CRCCommand);
/* Set CMDEX bit in NVM CTRLA register to start the CRC generation */
XPROGTarget_SendByte(PDI_CMD_STS(PDI_DATASIZE_4BYTES, PDI_DATASIZE_1BYTE));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CTRLA);
XPROGTarget_SendByte(XMEGA_NVM_BIT_CTRLA_CMDEX);
/* Wait until the NVM bus is ready again */
if (!(XMEGANVM_WaitWhileNVMBusBusy()))
return false;
/* Wait until the NVM controller is no longer busy */
if (!(XMEGANVM_WaitWhileNVMControllerBusy()))
return false;
/* Load the PDI pointer register with the DAT0 register start address */
XPROGTarget_SendByte(PDI_CMD_ST(PDI_POINTER_DIRECT, PDI_DATASIZE_4BYTES));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_DAT0);
/* Send the REPEAT command to grab the CRC bytes */
XPROGTarget_SendByte(PDI_CMD_REPEAT(PDI_DATASIZE_1BYTE));
XPROGTarget_SendByte(XMEGA_CRC_LENGTH_BYTES - 1);
/* Read in the CRC bytes from the target */
XPROGTarget_SendByte(PDI_CMD_LD(PDI_POINTER_INDIRECT_PI, PDI_DATASIZE_1BYTE));
for (uint8_t i = 0; i < XMEGA_CRC_LENGTH_BYTES; i++)
((uint8_t*)CRCDest)[i] = XPROGTarget_ReceiveByte();
return (TimeoutTicksRemaining > 0);
}
/** 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 \c true if the command sequence complete successfully
*/
bool XMEGANVM_ReadMemory(const uint32_t ReadAddress,
uint8_t* ReadBuffer,
uint16_t ReadSize)
{
/* Wait until the NVM controller is no longer busy */
if (!(XMEGANVM_WaitWhileNVMControllerBusy()))
return false;
/* Send the READNVM command to the NVM controller for reading of an arbitrary location */
XPROGTarget_SendByte(PDI_CMD_STS(PDI_DATASIZE_4BYTES, PDI_DATASIZE_1BYTE));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CMD);
XPROGTarget_SendByte(XMEGA_NVM_CMD_READNVM);
if (ReadSize > 1)
{
/* Load the PDI pointer register with the start address we want to read from */
XPROGTarget_SendByte(PDI_CMD_ST(PDI_POINTER_DIRECT, PDI_DATASIZE_4BYTES));
XMEGANVM_SendAddress(ReadAddress);
/* Send the REPEAT command with the specified number of bytes to read */
XPROGTarget_SendByte(PDI_CMD_REPEAT(PDI_DATASIZE_1BYTE));
XPROGTarget_SendByte(ReadSize - 1);
/* Send a LD command with indirect access and post-increment to read out the bytes */
XPROGTarget_SendByte(PDI_CMD_LD(PDI_POINTER_INDIRECT_PI, PDI_DATASIZE_1BYTE));
while (ReadSize-- && TimeoutTicksRemaining)
*(ReadBuffer++) = XPROGTarget_ReceiveByte();
}
else
{
/* Send a LDS command with the read address to read out the requested byte */
XPROGTarget_SendByte(PDI_CMD_LDS(PDI_DATASIZE_4BYTES, PDI_DATASIZE_1BYTE));
XMEGANVM_SendAddress(ReadAddress);
*(ReadBuffer++) = XPROGTarget_ReceiveByte();
}
return (TimeoutTicksRemaining > 0);
}
/** 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 Address to write to within the target's address space
* \param[in] Byte Byte to write to the target
*
* \return Boolean \c true if the command sequence complete successfully
*/
bool XMEGANVM_WriteByteMemory(const uint8_t WriteCommand,
const uint32_t WriteAddress,
const uint8_t Byte)
{
/* Wait until the NVM controller is no longer busy */
if (!(XMEGANVM_WaitWhileNVMControllerBusy()))
return false;
/* Send the memory write command to the target */
XPROGTarget_SendByte(PDI_CMD_STS(PDI_DATASIZE_4BYTES, PDI_DATASIZE_1BYTE));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CMD);
XPROGTarget_SendByte(WriteCommand);
/* Send new memory byte to the memory of the target */
XPROGTarget_SendByte(PDI_CMD_STS(PDI_DATASIZE_4BYTES, PDI_DATASIZE_1BYTE));
XMEGANVM_SendAddress(WriteAddress);
XPROGTarget_SendByte(Byte);
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 \c true if the command sequence complete successfully
*/
bool XMEGANVM_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,
uint16_t WriteSize)
{
if (PageMode & XPROG_PAGEMODE_ERASE)
{
/* Wait until the NVM controller is no longer busy */
if (!(XMEGANVM_WaitWhileNVMControllerBusy()))
return false;
/* Send the memory buffer erase command to the target */
XPROGTarget_SendByte(PDI_CMD_STS(PDI_DATASIZE_4BYTES, PDI_DATASIZE_1BYTE));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CMD);
XPROGTarget_SendByte(EraseBuffCommand);
/* Set CMDEX bit in NVM CTRLA register to start the buffer erase */
XPROGTarget_SendByte(PDI_CMD_STS(PDI_DATASIZE_4BYTES, PDI_DATASIZE_1BYTE));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CTRLA);
XPROGTarget_SendByte(XMEGA_NVM_BIT_CTRLA_CMDEX);
}
if (WriteSize)
{
/* Wait until the NVM controller is no longer busy */
if (!(XMEGANVM_WaitWhileNVMControllerBusy()))
return false;
/* Send the memory buffer write command to the target */
XPROGTarget_SendByte(PDI_CMD_STS(PDI_DATASIZE_4BYTES, PDI_DATASIZE_1BYTE));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CMD);
XPROGTarget_SendByte(WriteBuffCommand);
/* Load the PDI pointer register with the start address we want to write to */
XPROGTarget_SendByte(PDI_CMD_ST(PDI_POINTER_DIRECT, PDI_DATASIZE_4BYTES));
XMEGANVM_SendAddress(WriteAddress);
/* Send the REPEAT command with the specified number of bytes to write */
XPROGTarget_SendByte(PDI_CMD_REPEAT(PDI_DATASIZE_1BYTE));
XPROGTarget_SendByte(WriteSize - 1);
/* Send a ST command with indirect access and post-increment to write the bytes */
XPROGTarget_SendByte(PDI_CMD_ST(PDI_POINTER_INDIRECT_PI, PDI_DATASIZE_1BYTE));
while (WriteSize--)
XPROGTarget_SendByte(*(WriteBuffer++));
}
if (PageMode & XPROG_PAGEMODE_WRITE)
{
/* Wait until the NVM controller is no longer busy */
if (!(XMEGANVM_WaitWhileNVMControllerBusy()))
return false;
/* Send the memory write command to the target */
XPROGTarget_SendByte(PDI_CMD_STS(PDI_DATASIZE_4BYTES, PDI_DATASIZE_1BYTE));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CMD);
XPROGTarget_SendByte(WritePageCommand);
/* Send the address of the first page location to write the memory page */
XPROGTarget_SendByte(PDI_CMD_STS(PDI_DATASIZE_4BYTES, PDI_DATASIZE_1BYTE));
XMEGANVM_SendAddress(WriteAddress);
XPROGTarget_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 \c true if the command sequence complete successfully
*/
bool XMEGANVM_EraseMemory(const uint8_t EraseCommand,
const uint32_t Address)
{
/* Wait until the NVM controller is no longer busy */
if (!(XMEGANVM_WaitWhileNVMControllerBusy()))
return false;
/* EEPROM and Chip erasures are triggered differently to FLASH section erasures */
if (EraseCommand == XMEGA_NVM_CMD_CHIPERASE)
{
/* Send the memory erase command to the target */
XPROGTarget_SendByte(PDI_CMD_STS(PDI_DATASIZE_4BYTES, PDI_DATASIZE_1BYTE));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CMD);
XPROGTarget_SendByte(EraseCommand);
/* Set CMDEX bit in NVM CTRLA register to start the erase sequence */
XPROGTarget_SendByte(PDI_CMD_STS(PDI_DATASIZE_4BYTES, PDI_DATASIZE_1BYTE));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CTRLA);
XPROGTarget_SendByte(XMEGA_NVM_BIT_CTRLA_CMDEX);
}
else if (EraseCommand == XMEGA_NVM_CMD_ERASEEEPROM)
{
/* Send the EEPROM page buffer erase command to the target */
XPROGTarget_SendByte(PDI_CMD_STS(PDI_DATASIZE_4BYTES, PDI_DATASIZE_1BYTE));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CMD);
XPROGTarget_SendByte(XMEGA_NVM_CMD_ERASEEEPROMPAGEBUFF);
/* Set CMDEX bit in NVM CTRLA register to start the buffer erase */
XPROGTarget_SendByte(PDI_CMD_STS(PDI_DATASIZE_4BYTES, PDI_DATASIZE_1BYTE));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CTRLA);
XPROGTarget_SendByte(XMEGA_NVM_BIT_CTRLA_CMDEX);
/* Wait until the NVM controller is no longer busy */
if (!(XMEGANVM_WaitWhileNVMControllerBusy()))
return false;
/* Send the EEPROM memory buffer write command to the target */
XPROGTarget_SendByte(PDI_CMD_STS(PDI_DATASIZE_4BYTES, PDI_DATASIZE_1BYTE));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CMD);
XPROGTarget_SendByte(XMEGA_NVM_CMD_LOADEEPROMPAGEBUFF);
/* Load the PDI pointer register with the EEPROM page start address */
XPROGTarget_SendByte(PDI_CMD_ST(PDI_POINTER_DIRECT, PDI_DATASIZE_4BYTES));
XMEGANVM_SendAddress(Address);
/* Send the REPEAT command with the specified number of bytes to write */
XPROGTarget_SendByte(PDI_CMD_REPEAT(PDI_DATASIZE_1BYTE));
XPROGTarget_SendByte(XPROG_Param_EEPageSize - 1);
/* Send a ST command with indirect access and post-increment to tag each byte in the EEPROM page buffer */
XPROGTarget_SendByte(PDI_CMD_ST(PDI_POINTER_INDIRECT_PI, PDI_DATASIZE_1BYTE));
for (uint8_t PageByte = 0; PageByte < XPROG_Param_EEPageSize; PageByte++)
XPROGTarget_SendByte(0x00);
/* Send the memory erase command to the target */
XPROGTarget_SendByte(PDI_CMD_STS(PDI_DATASIZE_4BYTES, PDI_DATASIZE_1BYTE));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CMD);
XPROGTarget_SendByte(EraseCommand);
/* Set CMDEX bit in NVM CTRLA register to start the EEPROM erase sequence */
XPROGTarget_SendByte(PDI_CMD_STS(PDI_DATASIZE_4BYTES, PDI_DATASIZE_1BYTE));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CTRLA);
XPROGTarget_SendByte(XMEGA_NVM_BIT_CTRLA_CMDEX);
}
else
{
/* Send the memory erase command to the target */
XPROGTarget_SendByte(PDI_CMD_STS(PDI_DATASIZE_4BYTES, PDI_DATASIZE_1BYTE));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CMD);
XPROGTarget_SendByte(EraseCommand);
/* Other erase modes just need us to address a byte within the target memory space */
XPROGTarget_SendByte(PDI_CMD_STS(PDI_DATASIZE_4BYTES, PDI_DATASIZE_1BYTE));
XMEGANVM_SendAddress(Address);
XPROGTarget_SendByte(0x00);
}
/* Wait until the NVM bus is ready again */
if (!(XMEGANVM_WaitWhileNVMBusBusy()))
return false;
return true;
}
#endif

View file

@ -0,0 +1,140 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, 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 disclaims 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 XMEGANVM.c.
*/
#ifndef _XMEGA_NVM_
#define _XMEGA_NVM_
/* Includes: */
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdbool.h>
#include <LUFA/Common/Common.h>
#include "XPROGProtocol.h"
#include "XPROGTarget.h"
#include "Config/AppConfig.h"
/* Preprocessor Checks: */
#if ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1))
#undef ENABLE_ISP_PROTOCOL
#if !defined(ENABLE_XPROG_PROTOCOL)
#define ENABLE_XPROG_PROTOCOL
#endif
#endif
/* Defines: */
#define XMEGA_CRC_LENGTH_BYTES 3
#define XMEGA_NVM_REG_ADDR0 0x00
#define XMEGA_NVM_REG_ADDR1 0x01
#define XMEGA_NVM_REG_ADDR2 0x02
#define XMEGA_NVM_REG_DAT0 0x04
#define XMEGA_NVM_REG_DAT1 0x05
#define XMEGA_NVM_REG_DAT2 0x06
#define XMEGA_NVM_REG_CMD 0x0A
#define XMEGA_NVM_REG_CTRLA 0x0B
#define XMEGA_NVM_REG_CTRLB 0x0C
#define XMEGA_NVM_REG_INTCTRL 0x0D
#define XMEGA_NVM_REG_STATUS 0x0F
#define XMEGA_NVM_REG_LOCKBITS 0x10
#define XMEGA_NVM_BIT_CTRLA_CMDEX (1 << 0)
#define XMEGA_NVM_CMD_NOOP 0x00
#define XMEGA_NVM_CMD_CHIPERASE 0x40
#define XMEGA_NVM_CMD_READNVM 0x43
#define XMEGA_NVM_CMD_LOADFLASHPAGEBUFF 0x23
#define XMEGA_NVM_CMD_ERASEFLASHPAGEBUFF 0x26
#define XMEGA_NVM_CMD_ERASEFLASHPAGE 0x2B
#define XMEGA_NVM_CMD_WRITEFLASHPAGE 0x2E
#define XMEGA_NVM_CMD_ERASEWRITEFLASH 0x2F
#define XMEGA_NVM_CMD_FLASHCRC 0x78
#define XMEGA_NVM_CMD_ERASEAPPSEC 0x20
#define XMEGA_NVM_CMD_ERASEAPPSECPAGE 0x22
#define XMEGA_NVM_CMD_WRITEAPPSECPAGE 0x24
#define XMEGA_NVM_CMD_ERASEWRITEAPPSECPAGE 0x25
#define XMEGA_NVM_CMD_APPCRC 0x38
#define XMEGA_NVM_CMD_ERASEBOOTSEC 0x68
#define XMEGA_NVM_CMD_ERASEBOOTSECPAGE 0x2A
#define XMEGA_NVM_CMD_WRITEBOOTSECPAGE 0x2C
#define XMEGA_NVM_CMD_ERASEWRITEBOOTSECPAGE 0x2D
#define XMEGA_NVM_CMD_BOOTCRC 0x39
#define XMEGA_NVM_CMD_READUSERSIG 0x03
#define XMEGA_NVM_CMD_ERASEUSERSIG 0x18
#define XMEGA_NVM_CMD_WRITEUSERSIG 0x1A
#define XMEGA_NVM_CMD_READCALIBRATION 0x02
#define XMEGA_NVM_CMD_READFUSE 0x07
#define XMEGA_NVM_CMD_WRITEFUSE 0x4C
#define XMEGA_NVM_CMD_WRITELOCK 0x08
#define XMEGA_NVM_CMD_LOADEEPROMPAGEBUFF 0x33
#define XMEGA_NVM_CMD_ERASEEEPROMPAGEBUFF 0x36
#define XMEGA_NVM_CMD_ERASEEEPROM 0x30
#define XMEGA_NVM_CMD_ERASEEEPROMPAGE 0x32
#define XMEGA_NVM_CMD_WRITEEEPROMPAGE 0x34
#define XMEGA_NVM_CMD_ERASEWRITEEEPROMPAGE 0x35
#define XMEGA_NVM_CMD_READEEPROM 0x06
/* Function Prototypes: */
bool XMEGANVM_WaitWhileNVMBusBusy(void);
bool XMEGANVM_WaitWhileNVMControllerBusy(void);
bool XMEGANVM_EnablePDI(void);
void XMEGANVM_DisablePDI(void);
bool XMEGANVM_GetMemoryCRC(const uint8_t CRCCommand,
uint32_t* const CRCDest);
bool XMEGANVM_ReadMemory(const uint32_t ReadAddress,
uint8_t* ReadBuffer,
uint16_t ReadSize);
bool XMEGANVM_WriteByteMemory(const uint8_t WriteCommand,
const uint32_t WriteAddress,
const uint8_t Byte);
bool XMEGANVM_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,
uint16_t WriteSize);
bool XMEGANVM_EraseMemory(const uint8_t EraseCommand,
const uint32_t Address);
#if defined(INCLUDE_FROM_XMEGANVM_C)
static void XMEGANVM_SendNVMRegAddress(const uint8_t Register);
static void XMEGANVM_SendAddress(const uint32_t AbsoluteAddress);
#endif
#endif

View file

@ -0,0 +1,480 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, 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 disclaims 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
*
* XPROG Protocol handler, to process V2 Protocol wrapped XPROG commands used in Atmel programmer devices.
*/
#define INCLUDE_FROM_XPROGPROTOCOL_C
#include "XPROGProtocol.h"
#if defined(ENABLE_XPROG_PROTOCOL) || defined(__DOXYGEN__)
/** Base absolute address for the target's NVM controller for PDI programming */
uint32_t XPROG_Param_NVMBase = 0x010001C0;
/** Size in bytes of the target's EEPROM page */
uint16_t XPROG_Param_EEPageSize = 32;
/** Address of the TPI device's NVMCMD register for TPI programming */
uint8_t XPROG_Param_NVMCMDRegAddr = 0x33;
/** Address of the TPI device's NVMCSR register for TPI programming */
uint8_t XPROG_Param_NVMCSRRegAddr = 0x32;
/** Currently selected XPROG programming protocol */
uint8_t XPROG_SelectedProtocol = XPROG_PROTOCOL_PDI;
/** Handler for the CMD_XPROG_SETMODE command, which sets the programmer-to-target protocol used for PDI/TPI
* programming.
*/
void XPROGProtocol_SetMode(void)
{
struct
{
uint8_t Protocol;
} SetMode_XPROG_Params;
Endpoint_Read_Stream_LE(&SetMode_XPROG_Params, sizeof(SetMode_XPROG_Params), NULL);
Endpoint_ClearOUT();
Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPADDR);
Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
XPROG_SelectedProtocol = SetMode_XPROG_Params.Protocol;
Endpoint_Write_8(CMD_XPROG_SETMODE);
Endpoint_Write_8((SetMode_XPROG_Params.Protocol != XPROG_PROTOCOL_JTAG) ? STATUS_CMD_OK : STATUS_CMD_FAILED);
Endpoint_ClearIN();
}
/** Handler for the CMD_XPROG command, which wraps up XPROG commands in a V2 wrapper which need to be
* removed and processed so that the underlying XPROG command can be handled.
*/
void XPROGProtocol_Command(void)
{
uint8_t XPROGCommand = Endpoint_Read_8();
switch (XPROGCommand)
{
case XPROG_CMD_ENTER_PROGMODE:
XPROGProtocol_EnterXPROGMode();
break;
case XPROG_CMD_LEAVE_PROGMODE:
XPROGProtocol_LeaveXPROGMode();
break;
case XPROG_CMD_ERASE:
XPROGProtocol_Erase();
break;
case XPROG_CMD_WRITE_MEM:
XPROGProtocol_WriteMemory();
break;
case XPROG_CMD_READ_MEM:
XPROGProtocol_ReadMemory();
break;
case XPROG_CMD_CRC:
XPROGProtocol_ReadCRC();
break;
case XPROG_CMD_SET_PARAM:
XPROGProtocol_SetParam();
break;
}
}
/** Handler for the XPROG ENTER_PROGMODE command to establish a connection with the attached device. */
static void XPROGProtocol_EnterXPROGMode(void)
{
Endpoint_ClearOUT();
Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPADDR);
Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
bool NVMBusEnabled = false;
if (XPROG_SelectedProtocol == XPROG_PROTOCOL_PDI)
NVMBusEnabled = XMEGANVM_EnablePDI();
else if (XPROG_SelectedProtocol == XPROG_PROTOCOL_TPI)
NVMBusEnabled = TINYNVM_EnableTPI();
Endpoint_Write_8(CMD_XPROG);
Endpoint_Write_8(XPROG_CMD_ENTER_PROGMODE);
Endpoint_Write_8(NVMBusEnabled ? XPROG_ERR_OK : XPROG_ERR_FAILED);
Endpoint_ClearIN();
}
/** Handler for the XPROG LEAVE_PROGMODE command to terminate the PDI programming connection with
* the attached device.
*/
static void XPROGProtocol_LeaveXPROGMode(void)
{
Endpoint_ClearOUT();
Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPADDR);
Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
if (XPROG_SelectedProtocol == XPROG_PROTOCOL_PDI)
XMEGANVM_DisablePDI();
else
TINYNVM_DisableTPI();
#if defined(XCK_RESCUE_CLOCK_ENABLE) && defined(ENABLE_ISP_PROTOCOL)
/* If the XCK rescue clock option is enabled, we need to restart it once the
* XPROG mode has been exited, since the XPROG protocol stops it after use. */
ISPTarget_ConfigureRescueClock();
#endif
Endpoint_Write_8(CMD_XPROG);
Endpoint_Write_8(XPROG_CMD_LEAVE_PROGMODE);
Endpoint_Write_8(XPROG_ERR_OK);
Endpoint_ClearIN();
}
/** Handler for the XPRG ERASE command to erase a specific memory address space in the attached device. */
static void XPROGProtocol_Erase(void)
{
uint8_t ReturnStatus = XPROG_ERR_OK;
struct
{
uint8_t MemoryType;
uint32_t Address;
} Erase_XPROG_Params;
Endpoint_Read_Stream_LE(&Erase_XPROG_Params, sizeof(Erase_XPROG_Params), NULL);
Erase_XPROG_Params.Address = SwapEndian_32(Erase_XPROG_Params.Address);
Endpoint_ClearOUT();
Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPADDR);
Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
uint8_t EraseCommand;
if (XPROG_SelectedProtocol == XPROG_PROTOCOL_PDI)
{
/* Determine which NVM command to send to the device depending on the memory to erase */
switch (Erase_XPROG_Params.MemoryType)
{
case XPROG_ERASE_CHIP:
EraseCommand = XMEGA_NVM_CMD_CHIPERASE;
break;
case XPROG_ERASE_APP:
EraseCommand = XMEGA_NVM_CMD_ERASEAPPSEC;
break;
case XPROG_ERASE_BOOT:
EraseCommand = XMEGA_NVM_CMD_ERASEBOOTSEC;
break;
case XPROG_ERASE_EEPROM:
EraseCommand = XMEGA_NVM_CMD_ERASEEEPROM;
break;
case XPROG_ERASE_APP_PAGE:
EraseCommand = XMEGA_NVM_CMD_ERASEAPPSECPAGE;
break;
case XPROG_ERASE_BOOT_PAGE:
EraseCommand = XMEGA_NVM_CMD_ERASEBOOTSECPAGE;
break;
case XPROG_ERASE_EEPROM_PAGE:
EraseCommand = XMEGA_NVM_CMD_ERASEEEPROMPAGE;
break;
case XPROG_ERASE_USERSIG:
EraseCommand = XMEGA_NVM_CMD_ERASEUSERSIG;
break;
default:
EraseCommand = XMEGA_NVM_CMD_NOOP;
break;
}
/* Erase the target memory, indicate timeout if occurred */
if (!(XMEGANVM_EraseMemory(EraseCommand, Erase_XPROG_Params.Address)))
ReturnStatus = XPROG_ERR_TIMEOUT;
}
else
{
if (Erase_XPROG_Params.MemoryType == XPROG_ERASE_CHIP)
EraseCommand = TINY_NVM_CMD_CHIPERASE;
else
EraseCommand = TINY_NVM_CMD_SECTIONERASE;
/* Erase the target memory, indicate timeout if occurred */
if (!(TINYNVM_EraseMemory(EraseCommand, Erase_XPROG_Params.Address)))
ReturnStatus = XPROG_ERR_TIMEOUT;
}
Endpoint_Write_8(CMD_XPROG);
Endpoint_Write_8(XPROG_CMD_ERASE);
Endpoint_Write_8(ReturnStatus);
Endpoint_ClearIN();
}
/** Handler for the XPROG WRITE_MEMORY command to write to a specific memory space within the attached device. */
static void XPROGProtocol_WriteMemory(void)
{
uint8_t ReturnStatus = XPROG_ERR_OK;
struct
{
uint8_t MemoryType;
uint8_t PageMode;
uint32_t Address;
uint16_t Length;
uint8_t ProgData[256];
} WriteMemory_XPROG_Params;
Endpoint_Read_Stream_LE(&WriteMemory_XPROG_Params, (sizeof(WriteMemory_XPROG_Params) -
sizeof(WriteMemory_XPROG_Params).ProgData), NULL);
WriteMemory_XPROG_Params.Address = SwapEndian_32(WriteMemory_XPROG_Params.Address);
WriteMemory_XPROG_Params.Length = SwapEndian_16(WriteMemory_XPROG_Params.Length);
Endpoint_Read_Stream_LE(&WriteMemory_XPROG_Params.ProgData, WriteMemory_XPROG_Params.Length, NULL);
// The driver will terminate transfers that are a round multiple of the endpoint bank in size with a ZLP, need
// to catch this and discard it before continuing on with packet processing to prevent communication issues
if (((sizeof(uint8_t) + sizeof(WriteMemory_XPROG_Params) - sizeof(WriteMemory_XPROG_Params.ProgData)) +
WriteMemory_XPROG_Params.Length) % AVRISP_DATA_EPSIZE == 0)
{
Endpoint_ClearOUT();
Endpoint_WaitUntilReady();
}
Endpoint_ClearOUT();
Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPADDR);
Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
if (XPROG_SelectedProtocol == XPROG_PROTOCOL_PDI)
{
/* Assume FLASH page programming by default, as it is the common case */
uint8_t WriteCommand = XMEGA_NVM_CMD_WRITEFLASHPAGE;
uint8_t WriteBuffCommand = XMEGA_NVM_CMD_LOADFLASHPAGEBUFF;
uint8_t EraseBuffCommand = XMEGA_NVM_CMD_ERASEFLASHPAGEBUFF;
bool PagedMemory = true;
switch (WriteMemory_XPROG_Params.MemoryType)
{
case XPROG_MEM_TYPE_APPL:
WriteCommand = XMEGA_NVM_CMD_WRITEAPPSECPAGE;
break;
case XPROG_MEM_TYPE_BOOT:
WriteCommand = XMEGA_NVM_CMD_WRITEBOOTSECPAGE;
break;
case XPROG_MEM_TYPE_EEPROM:
WriteCommand = XMEGA_NVM_CMD_ERASEWRITEEEPROMPAGE;
WriteBuffCommand = XMEGA_NVM_CMD_LOADEEPROMPAGEBUFF;
EraseBuffCommand = XMEGA_NVM_CMD_ERASEEEPROMPAGEBUFF;
break;
case XPROG_MEM_TYPE_USERSIG:
WriteCommand = XMEGA_NVM_CMD_WRITEUSERSIG;
break;
case XPROG_MEM_TYPE_FUSE:
WriteCommand = XMEGA_NVM_CMD_WRITEFUSE;
PagedMemory = false;
break;
case XPROG_MEM_TYPE_LOCKBITS:
WriteCommand = XMEGA_NVM_CMD_WRITELOCK;
PagedMemory = false;
break;
}
/* Send the appropriate memory write commands to the device, indicate timeout if occurred */
if ((PagedMemory && !(XMEGANVM_WritePageMemory(WriteBuffCommand, EraseBuffCommand, WriteCommand,
WriteMemory_XPROG_Params.PageMode, WriteMemory_XPROG_Params.Address,
WriteMemory_XPROG_Params.ProgData, WriteMemory_XPROG_Params.Length))) ||
(!PagedMemory && !(XMEGANVM_WriteByteMemory(WriteCommand, WriteMemory_XPROG_Params.Address,
WriteMemory_XPROG_Params.ProgData[0]))))
{
ReturnStatus = XPROG_ERR_TIMEOUT;
}
}
else
{
/* Send write command to the TPI device, indicate timeout if occurred */
if (!(TINYNVM_WriteMemory(WriteMemory_XPROG_Params.Address, WriteMemory_XPROG_Params.ProgData,
WriteMemory_XPROG_Params.Length)))
{
ReturnStatus = XPROG_ERR_TIMEOUT;
}
}
Endpoint_Write_8(CMD_XPROG);
Endpoint_Write_8(XPROG_CMD_WRITE_MEM);
Endpoint_Write_8(ReturnStatus);
Endpoint_ClearIN();
}
/** Handler for the XPROG READ_MEMORY command to read data from a specific address space within the
* attached device.
*/
static void XPROGProtocol_ReadMemory(void)
{
uint8_t ReturnStatus = XPROG_ERR_OK;
struct
{
uint8_t MemoryType;
uint32_t Address;
uint16_t Length;
} ReadMemory_XPROG_Params;
Endpoint_Read_Stream_LE(&ReadMemory_XPROG_Params, sizeof(ReadMemory_XPROG_Params), NULL);
ReadMemory_XPROG_Params.Address = SwapEndian_32(ReadMemory_XPROG_Params.Address);
ReadMemory_XPROG_Params.Length = SwapEndian_16(ReadMemory_XPROG_Params.Length);
Endpoint_ClearOUT();
Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPADDR);
Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
uint8_t ReadBuffer[256];
if (XPROG_SelectedProtocol == XPROG_PROTOCOL_PDI)
{
/* Read the PDI target's memory, indicate timeout if occurred */
if (!(XMEGANVM_ReadMemory(ReadMemory_XPROG_Params.Address, ReadBuffer, ReadMemory_XPROG_Params.Length)))
ReturnStatus = XPROG_ERR_TIMEOUT;
}
else
{
/* Read the TPI target's memory, indicate timeout if occurred */
if (!(TINYNVM_ReadMemory(ReadMemory_XPROG_Params.Address, ReadBuffer, ReadMemory_XPROG_Params.Length)))
ReturnStatus = XPROG_ERR_TIMEOUT;
}
Endpoint_Write_8(CMD_XPROG);
Endpoint_Write_8(XPROG_CMD_READ_MEM);
Endpoint_Write_8(ReturnStatus);
if (ReturnStatus == XPROG_ERR_OK)
Endpoint_Write_Stream_LE(ReadBuffer, ReadMemory_XPROG_Params.Length, NULL);
Endpoint_ClearIN();
}
/** Handler for the XPROG CRC command to read a specific memory space's CRC value for comparison between the
* attached device's memory and a data set on the host.
*/
static void XPROGProtocol_ReadCRC(void)
{
uint8_t ReturnStatus = XPROG_ERR_OK;
struct
{
uint8_t CRCType;
} ReadCRC_XPROG_Params;
Endpoint_Read_Stream_LE(&ReadCRC_XPROG_Params, sizeof(ReadCRC_XPROG_Params), NULL);
Endpoint_ClearOUT();
Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPADDR);
Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
uint32_t MemoryCRC;
if (XPROG_SelectedProtocol == XPROG_PROTOCOL_PDI)
{
uint8_t CRCCommand;
/* Determine which NVM command to send to the device depending on the memory to CRC */
switch (ReadCRC_XPROG_Params.CRCType)
{
case XPROG_CRC_APP:
CRCCommand = XMEGA_NVM_CMD_APPCRC;
break;
case XPROG_CRC_BOOT:
CRCCommand = XMEGA_NVM_CMD_BOOTCRC;
break;
default:
CRCCommand = XMEGA_NVM_CMD_FLASHCRC;
break;
}
/* Perform and retrieve the memory CRC, indicate timeout if occurred */
if (!(XMEGANVM_GetMemoryCRC(CRCCommand, &MemoryCRC)))
ReturnStatus = XPROG_ERR_TIMEOUT;
}
else
{
/* TPI does not support memory CRC */
ReturnStatus = XPROG_ERR_FAILED;
}
Endpoint_Write_8(CMD_XPROG);
Endpoint_Write_8(XPROG_CMD_CRC);
Endpoint_Write_8(ReturnStatus);
if (ReturnStatus == XPROG_ERR_OK)
{
Endpoint_Write_8(MemoryCRC >> 16);
Endpoint_Write_16_LE(MemoryCRC & 0xFFFF);
}
Endpoint_ClearIN();
}
/** Handler for the XPROG SET_PARAM command to set a XPROG parameter for use when communicating with the
* attached device.
*/
static void XPROGProtocol_SetParam(void)
{
uint8_t ReturnStatus = XPROG_ERR_OK;
uint8_t XPROGParam = Endpoint_Read_8();
/* Determine which parameter is being set, store the new parameter value */
switch (XPROGParam)
{
case XPROG_PARAM_NVMBASE:
XPROG_Param_NVMBase = Endpoint_Read_32_BE();
break;
case XPROG_PARAM_EEPPAGESIZE:
XPROG_Param_EEPageSize = Endpoint_Read_16_BE();
break;
case XPROG_PARAM_NVMCMD_REG:
XPROG_Param_NVMCMDRegAddr = Endpoint_Read_8();
break;
case XPROG_PARAM_NVMCSR_REG:
XPROG_Param_NVMCSRRegAddr = Endpoint_Read_8();
break;
case XPROG_PARAM_UNKNOWN_1:
/* TODO: Undocumented parameter added in AVRStudio 5.1, purpose unknown. Must ACK and discard or
the communication with AVRStudio 5.1 will fail.
*/
Endpoint_Discard_16();
break;
default:
ReturnStatus = XPROG_ERR_FAILED;
break;
}
Endpoint_ClearOUT();
Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPADDR);
Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
Endpoint_Write_8(CMD_XPROG);
Endpoint_Write_8(XPROG_CMD_SET_PARAM);
Endpoint_Write_8(ReturnStatus);
Endpoint_ClearIN();
}
#endif

View file

@ -0,0 +1,136 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, 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 disclaims 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 XPROGProtocol.c.
*/
#ifndef _XPROG_PROTOCOL_
#define _XPROG_PROTOCOL_
/* Includes: */
#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#include <LUFA/Drivers/USB/USB.h>
#include "../V2Protocol.h"
#include "XMEGANVM.h"
#include "TINYNVM.h"
#include "Config/AppConfig.h"
/* Preprocessor Checks: */
#if ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1))
/* On the XPLAIN board, we only need PDI programming
for the ATXMEGA128A1 - disable ISP to prevent hardware
damage and force-enable XPROG.
*/
#undef ENABLE_ISP_PROTOCOL
#if !defined(ENABLE_XPROG_PROTOCOL)
#define ENABLE_XPROG_PROTOCOL
#endif
#endif
/* Macros: */
#define XPROG_CMD_ENTER_PROGMODE 0x01
#define XPROG_CMD_LEAVE_PROGMODE 0x02
#define XPROG_CMD_ERASE 0x03
#define XPROG_CMD_WRITE_MEM 0x04
#define XPROG_CMD_READ_MEM 0x05
#define XPROG_CMD_CRC 0x06
#define XPROG_CMD_SET_PARAM 0x07
#define XPROG_MEM_TYPE_APPL 1
#define XPROG_MEM_TYPE_BOOT 2
#define XPROG_MEM_TYPE_EEPROM 3
#define XPROG_MEM_TYPE_FUSE 4
#define XPROG_MEM_TYPE_LOCKBITS 5
#define XPROG_MEM_TYPE_USERSIG 6
#define XPROG_MEM_TYPE_FACTORY_CALIBRATION 7
#define XPROG_ERASE_CHIP 1
#define XPROG_ERASE_APP 2
#define XPROG_ERASE_BOOT 3
#define XPROG_ERASE_EEPROM 4
#define XPROG_ERASE_APP_PAGE 5
#define XPROG_ERASE_BOOT_PAGE 6
#define XPROG_ERASE_EEPROM_PAGE 7
#define XPROG_ERASE_USERSIG 8
#define XPROG_MEM_WRITE_ERASE 0
#define XPROG_MEM_WRITE_WRITE 1
#define XPROG_CRC_APP 1
#define XPROG_CRC_BOOT 2
#define XPROG_CRC_FLASH 3
#define XPROG_ERR_OK 0
#define XPROG_ERR_FAILED 1
#define XPROG_ERR_COLLISION 2
#define XPROG_ERR_TIMEOUT 3
#define XPROG_PARAM_NVMBASE 0x01
#define XPROG_PARAM_EEPPAGESIZE 0x02
#define XPROG_PARAM_NVMCMD_REG 0x03
#define XPROG_PARAM_NVMCSR_REG 0x04
#define XPROG_PARAM_UNKNOWN_1 0x05
#define XPROG_PROTOCOL_PDI 0x00
#define XPROG_PROTOCOL_JTAG 0x01
#define XPROG_PROTOCOL_TPI 0x02
#define XPROG_PAGEMODE_WRITE (1 << 1)
#define XPROG_PAGEMODE_ERASE (1 << 0)
/* External Variables: */
extern uint32_t XPROG_Param_NVMBase;
extern uint16_t XPROG_Param_EEPageSize;
extern uint8_t XPROG_Param_NVMCSRRegAddr;
extern uint8_t XPROG_Param_NVMCMDRegAddr;
/* Function Prototypes: */
void XPROGProtocol_SetMode(void);
void XPROGProtocol_Command(void);
#if (defined(INCLUDE_FROM_XPROGPROTOCOL_C) && defined(ENABLE_XPROG_PROTOCOL))
static void XPROGProtocol_EnterXPROGMode(void);
static void XPROGProtocol_LeaveXPROGMode(void);
static void XPROGProtocol_SetParam(void);
static void XPROGProtocol_Erase(void);
static void XPROGProtocol_WriteMemory(void);
static void XPROGProtocol_ReadMemory(void);
static void XPROGProtocol_ReadCRC(void);
#endif
#endif

View file

@ -0,0 +1,209 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, 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 disclaims 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 PDI Protocol decoder.
*/
#define INCLUDE_FROM_XPROGTARGET_C
#include "XPROGTarget.h"
#if defined(ENABLE_XPROG_PROTOCOL) || defined(__DOXYGEN__)
/** Flag to indicate if the USART is currently in Tx or Rx mode. */
bool IsSending;
/** Enables the target's PDI interface, holding the target in reset until PDI mode is exited. */
void XPROGTarget_EnableTargetPDI(void)
{
IsSending = false;
/* Set Tx and XCK as outputs, Rx as input */
DDRD |= (1 << 5) | (1 << 3);
DDRD &= ~(1 << 2);
/* Set DATA line high for at least 90ns to disable /RESET functionality */
PORTD |= (1 << 3);
_delay_us(100);
/* Set up the synchronous USART for XMEGA communications - 8 data bits, even parity, 2 stop bits */
UBRR1 = ((F_CPU / 2 / XPROG_HARDWARE_SPEED) - 1);
UCSR1B = (1 << TXEN1);
UCSR1C = (1 << UMSEL10) | (1 << UPM11) | (1 << USBS1) | (1 << UCSZ11) | (1 << UCSZ10) | (1 << UCPOL1);
/* Send two IDLEs of 12 bits each to enable PDI interface (need at least 16 idle bits) */
XPROGTarget_SendIdle();
XPROGTarget_SendIdle();
}
/** Enables the target's TPI interface, holding the target in reset until TPI mode is exited. */
void XPROGTarget_EnableTargetTPI(void)
{
IsSending = false;
/* Set /RESET line low for at least 400ns to enable TPI functionality */
AUX_LINE_DDR |= AUX_LINE_MASK;
AUX_LINE_PORT &= ~AUX_LINE_MASK;
_delay_us(100);
/* Set Tx and XCK as outputs, Rx as input */
DDRD |= (1 << 5) | (1 << 3);
DDRD &= ~(1 << 2);
/* Set up the synchronous USART for TPI communications - 8 data bits, even parity, 2 stop bits */
UBRR1 = ((F_CPU / 2 / XPROG_HARDWARE_SPEED) - 1);
UCSR1B = (1 << TXEN1);
UCSR1C = (1 << UMSEL10) | (1 << UPM11) | (1 << USBS1) | (1 << UCSZ11) | (1 << UCSZ10) | (1 << UCPOL1);
/* Send two IDLEs of 12 bits each to enable TPI interface (need at least 16 idle bits) */
XPROGTarget_SendIdle();
XPROGTarget_SendIdle();
}
/** Disables the target's PDI interface, exits programming mode and starts the target's application. */
void XPROGTarget_DisableTargetPDI(void)
{
/* Switch to Rx mode to ensure that all pending transmissions are complete */
if (IsSending)
XPROGTarget_SetRxMode();
/* Turn off receiver and transmitter of the USART, clear settings */
UCSR1A = ((1 << TXC1) | (1 << RXC1));
UCSR1B = 0;
UCSR1C = 0;
/* Tristate all pins */
DDRD &= ~((1 << 5) | (1 << 3));
PORTD &= ~((1 << 5) | (1 << 3) | (1 << 2));
}
/** Disables the target's TPI interface, exits programming mode and starts the target's application. */
void XPROGTarget_DisableTargetTPI(void)
{
/* Switch to Rx mode to ensure that all pending transmissions are complete */
if (IsSending)
XPROGTarget_SetRxMode();
/* Turn off receiver and transmitter of the USART, clear settings */
UCSR1A |= (1 << TXC1) | (1 << RXC1);
UCSR1B = 0;
UCSR1C = 0;
/* Set all USART lines as inputs, tristate */
DDRD &= ~((1 << 5) | (1 << 3));
PORTD &= ~((1 << 5) | (1 << 3) | (1 << 2));
/* Tristate target /RESET line */
AUX_LINE_DDR &= ~AUX_LINE_MASK;
AUX_LINE_PORT &= ~AUX_LINE_MASK;
}
/** Sends a byte via the USART.
*
* \param[in] Byte Byte to send through the USART
*/
void XPROGTarget_SendByte(const uint8_t Byte)
{
/* Switch to Tx mode if currently in Rx mode */
if (!(IsSending))
XPROGTarget_SetTxMode();
/* Wait until there is space in the hardware Tx buffer before writing */
while (!(UCSR1A & (1 << UDRE1)));
UCSR1A |= (1 << TXC1);
UDR1 = Byte;
}
/** Receives a byte via the hardware USART, blocking until data is received or timeout expired.
*
* \return Received byte from the USART
*/
uint8_t XPROGTarget_ReceiveByte(void)
{
/* Switch to Rx mode if currently in Tx mode */
if (IsSending)
XPROGTarget_SetRxMode();
/* Wait until a byte has been received before reading */
while (!(UCSR1A & (1 << RXC1)) && TimeoutTicksRemaining);
return UDR1;
}
/** Sends an IDLE via the USART to the attached target, consisting of a full frame of idle bits. */
void XPROGTarget_SendIdle(void)
{
/* Switch to Tx mode if currently in Rx mode */
if (!(IsSending))
XPROGTarget_SetTxMode();
/* Need to do nothing for a full frame to send an IDLE */
for (uint8_t i = 0; i < BITS_IN_USART_FRAME; i++)
{
/* Wait for a full cycle of the clock */
while (PIND & (1 << 5));
while (!(PIND & (1 << 5)));
while (PIND & (1 << 5));
}
}
static void XPROGTarget_SetTxMode(void)
{
/* Wait for a full cycle of the clock */
while (PIND & (1 << 5));
while (!(PIND & (1 << 5)));
while (PIND & (1 << 5));
PORTD |= (1 << 3);
DDRD |= (1 << 3);
UCSR1B &= ~(1 << RXEN1);
UCSR1B |= (1 << TXEN1);
IsSending = true;
}
static void XPROGTarget_SetRxMode(void)
{
while (!(UCSR1A & (1 << TXC1)));
UCSR1A |= (1 << TXC1);
UCSR1B &= ~(1 << TXEN1);
UCSR1B |= (1 << RXEN1);
DDRD &= ~(1 << 3);
PORTD &= ~(1 << 3);
IsSending = false;
}
#endif

View file

@ -0,0 +1,136 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2017.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, 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 disclaims 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 XPROGTarget.c.
*/
#ifndef _XPROG_TARGET_
#define _XPROG_TARGET_
/* Includes: */
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdbool.h>
#include <LUFA/Common/Common.h>
#include "../V2Protocol.h"
#include "XPROGProtocol.h"
#include "Config/AppConfig.h"
/* Preprocessor Checks: */
#if ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1))
#undef ENABLE_ISP_PROTOCOL
#if !defined(ENABLE_XPROG_PROTOCOL)
#define ENABLE_XPROG_PROTOCOL
#endif
#endif
/** Serial carrier TPI/PDI speed in Hz, when hardware TPI/PDI mode is used. */
#define XPROG_HARDWARE_SPEED 2000000
/** Total number of bits in a single USART frame. */
#define BITS_IN_USART_FRAME 12
/** \name PDI Related Constants
* @{
*/
#define PDI_CMD_LDS(AddressSize, DataSize) (0x00 | ( AddressSize << 2) | DataSize)
#define PDI_CMD_LD(PointerAccess, DataSize) (0x20 | (PointerAccess << 2) | DataSize)
#define PDI_CMD_STS(AddressSize, DataSize) (0x40 | ( AddressSize << 2) | DataSize)
#define PDI_CMD_ST(PointerAccess, DataSize) (0x60 | (PointerAccess << 2) | DataSize)
#define PDI_CMD_LDCS(PDIReg) (0x80 | PDIReg)
#define PDI_CMD_REPEAT(DataSize) (0xA0 | DataSize)
#define PDI_CMD_STCS(PDIReg) (0xC0 | PDIReg)
#define PDI_CMD_KEY 0xE0
#define PDI_REG_STATUS 0
#define PDI_REG_RESET 1
#define PDI_REG_CTRL 2
#define PDI_STATUS_NVM (1 << 1)
#define PDI_RESET_KEY 0x59
#define PDI_NVMENABLE_KEY (uint8_t[]){0x12, 0x89, 0xAB, 0x45, 0xCD, 0xD8, 0x88, 0xFF}
#define PDI_DATASIZE_1BYTE 0
#define PDI_DATASIZE_2BYTES 1
#define PDI_DATASIZE_3BYTES 2
#define PDI_DATASIZE_4BYTES 3
#define PDI_POINTER_INDIRECT 0
#define PDI_POINTER_INDIRECT_PI 1
#define PDI_POINTER_DIRECT 2
/** @} */
/** \name TPI Related Constants
* @{
*/
#define TPI_CMD_SLD(PointerAccess) (0x20 | PointerAccess)
#define TPI_CMD_SST(PointerAccess) (0x60 | PointerAccess)
#define TPI_CMD_SSTPR 0x68
#define TPI_CMD_SIN(Address) (0x10 | ((Address & 0x30) << 1) | (Address & 0x0F))
#define TPI_CMD_SOUT(Address) (0x90 | ((Address & 0x30) << 1) | (Address & 0x0F))
#define TPI_CMD_SLDCS(TPIReg) (0x80 | TPIReg)
#define TPI_CMD_SSTCS(TPIReg) (0xC0 | TPIReg)
#define TPI_CMD_SKEY 0xE0
#define TPI_REG_STATUS 0x00
#define TPI_REG_CTRL 0x02
#define TPI_REG_ID 0x0F
#define TPI_STATUS_NVM (1 << 1)
#define TPI_NVMENABLE_KEY (uint8_t[]){0x12, 0x89, 0xAB, 0x45, 0xCD, 0xD8, 0x88, 0xFF}
#define TPI_POINTER_INDIRECT 0
#define TPI_POINTER_INDIRECT_PI 4
/** @} */
/* Function Prototypes: */
void XPROGTarget_EnableTargetPDI(void);
void XPROGTarget_EnableTargetTPI(void);
void XPROGTarget_DisableTargetPDI(void);
void XPROGTarget_DisableTargetTPI(void);
void XPROGTarget_SendByte(const uint8_t Byte);
uint8_t XPROGTarget_ReceiveByte(void);
void XPROGTarget_SendIdle(void);
bool XPROGTarget_WaitWhileNVMBusBusy(void);
#if (defined(INCLUDE_FROM_XPROGTARGET_C) && defined(ENABLE_XPROG_PROTOCOL))
static void XPROGTarget_SetTxMode(void);
static void XPROGTarget_SetRxMode(void);
#endif
#endif