Complete combining of PDI and TPI target communication code files, stub out TINY NVM controller functions.

Dean Camera 16 years ago
parent cfdab42dcf
commit 65fcebf478

File diff suppressed because one or more lines are too long

@ -38,6 +38,86 @@
#if defined(ENABLE_XPROG_PROTOCOL) || defined(__DOXYGEN__)
// TODO
/** 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 XMEGANVM_WaitWhileNVMBusBusy(void)
{
// TODO
return false;
}
/** 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 XMEGANVM_WaitWhileNVMControllerBusy(void)
{
// TODO
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 XMEGANVM_GetMemoryCRC(const uint8_t CRCCommand, uint32_t* const CRCDest)
{
// TODO
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 XMEGANVM_ReadMemory(const uint32_t ReadAddress, uint8_t* ReadBuffer, const uint16_t ReadSize)
{
// TODO
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 XMEGANVM_WriteMemory(const uint8_t WriteCommand, const uint32_t WriteAddress, const uint8_t* WriteBuffer)
{
// TODO
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 XMEGANVM_EraseMemory(const uint8_t EraseCommand, const uint32_t Address)
{
// TODO
return true;
}
#endif

@ -44,7 +44,7 @@
#include <LUFA/Common/Common.h>
#include "XPROGProtocol.h"
#include "TPITarget.h"
#include "XPROGTarget.h"
/* Preprocessor Checks: */
#if ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1))
@ -58,4 +58,11 @@
/* Defines: */
#define TINY_NVM_BUSY_TIMEOUT_MS 100
/* Function Prototypes: */
bool TINYNVM_WaitWhileNVMControllerBusy(void);
bool TINYNVM_ReadMemory(const uint32_t ReadAddress, uint8_t* ReadBuffer, const uint16_t ReadSize);
bool TINYNVM_WriteMemory(const uint8_t WriteCommand, const uint32_t WriteAddress, const uint8_t* WriteBuffer);
bool TINYNVM_EraseMemory(const uint8_t EraseCommand, const uint32_t Address);
bool TINYNVM_WaitWhileNVMBusBusy(void);
#endif

@ -58,10 +58,40 @@ void XMEGANVM_SendNVMRegAddress(const uint8_t Register)
void XMEGANVM_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);
XPROGTarget_SendByte(AbsoluteAddress & 0xFF);
XPROGTarget_SendByte(AbsoluteAddress >> 8);
XPROGTarget_SendByte(AbsoluteAddress >> 16);
XPROGTarget_SendByte(AbsoluteAddress >> 24);
}
/** 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 XMEGANVM_WaitWhileNVMBusBusy(void)
{
TCNT0 = 0;
TIFR0 = (1 << OCF1A);
uint8_t TimeoutMS = XMEGA_NVM_BUSY_TIMEOUT_MS;
/* Poll the STATUS register to check to see if NVM access has been enabled */
while (TimeoutMS)
{
/* Send the LDCS command to read the PDI STATUS register to see the NVM bus is active */
XPROGTarget_SendByte(PDI_CMD_LDCS | PDI_STATUS_REG);
if (XPROGTarget_ReceiveByte() & PDI_STATUS_NVM)
return true;
if (TIFR0 & (1 << OCF1A))
{
TIFR0 = (1 << OCF1A);
TimeoutMS--;
}
}
return false;
}
/** Waits while the target's NVM controller is busy performing an operation, exiting if the
@ -80,11 +110,11 @@ bool XMEGANVM_WaitWhileNVMControllerBusy(void)
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));
XPROGTarget_SendByte(PDI_CMD_LDS | (PDI_DATSIZE_4BYTES << 2));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_STATUS);
/* Check to see if the BUSY flag is still set */
if (!(PDITarget_ReceiveByte() & (1 << 7)))
if (!(XPROGTarget_ReceiveByte() & (1 << 7)))
return true;
if (TIFR0 & (1 << OCF1A))
@ -111,17 +141,17 @@ bool XMEGANVM_GetMemoryCRC(const uint8_t CRCCommand, uint32_t* const CRCDest)
return false;
/* Set the NVM command to the correct CRC read command */
PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CMD);
PDITarget_SendByte(CRCCommand);
XPROGTarget_SendByte(CRCCommand);
/* Set CMDEX bit in NVM CTRLA register to start the CRC generation */
PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CTRLA);
PDITarget_SendByte(1 << 0);
XPROGTarget_SendByte(1 << 0);
/* Wait until the NVM bus is ready again */
if (!(PDITarget_WaitWhileNVMBusBusy()))
if (!(XMEGANVM_WaitWhileNVMBusBusy()))
return false;
/* Wait until the NVM controller is no longer busy */
@ -131,19 +161,19 @@ bool XMEGANVM_GetMemoryCRC(const uint8_t CRCCommand, uint32_t* const CRCDest)
*CRCDest = 0;
/* Read the first generated CRC byte value */
PDITarget_SendByte(PDI_CMD_LDS | (PDI_DATSIZE_4BYTES << 2));
XPROGTarget_SendByte(PDI_CMD_LDS | (PDI_DATSIZE_4BYTES << 2));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_DAT0);
*CRCDest = PDITarget_ReceiveByte();
*CRCDest = XPROGTarget_ReceiveByte();
/* Read the second generated CRC byte value */
PDITarget_SendByte(PDI_CMD_LDS | (PDI_DATSIZE_4BYTES << 2));
XPROGTarget_SendByte(PDI_CMD_LDS | (PDI_DATSIZE_4BYTES << 2));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_DAT1);
*CRCDest |= ((uint16_t)PDITarget_ReceiveByte() << 8);
*CRCDest |= ((uint16_t)XPROGTarget_ReceiveByte() << 8);
/* Read the third generated CRC byte value */
PDITarget_SendByte(PDI_CMD_LDS | (PDI_DATSIZE_4BYTES << 2));
XPROGTarget_SendByte(PDI_CMD_LDS | (PDI_DATSIZE_4BYTES << 2));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_DAT2);
*CRCDest |= ((uint32_t)PDITarget_ReceiveByte() << 16);
*CRCDest |= ((uint32_t)XPROGTarget_ReceiveByte() << 16);
return true;
}
@ -163,22 +193,22 @@ bool XMEGANVM_ReadMemory(const uint32_t ReadAddress, uint8_t* ReadBuffer, const
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));
XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CMD);
PDITarget_SendByte(XMEGA_NVM_CMD_READNVM);
XPROGTarget_SendByte(XMEGA_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);
XPROGTarget_SendByte(PDI_CMD_ST | (PDI_POINTER_DIRECT << 2) | PDI_DATSIZE_4BYTES);
XMEGANVM_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);
XPROGTarget_SendByte(PDI_CMD_REPEAT | PDI_DATSIZE_1BYTE);
XPROGTarget_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);
XPROGTarget_SendByte(PDI_CMD_LD | (PDI_POINTER_INDIRECT_PI << 2) | PDI_DATSIZE_1BYTE);
for (uint16_t i = 0; i < ReadSize; i++)
*(ReadBuffer++) = PDITarget_ReceiveByte();
*(ReadBuffer++) = XPROGTarget_ReceiveByte();
return true;
}
@ -198,14 +228,14 @@ bool XMEGANVM_WriteByteMemory(const uint8_t WriteCommand, const uint32_t WriteAd
return false;
/* Send the memory write command to the target */
PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CMD);
PDITarget_SendByte(WriteCommand);
XPROGTarget_SendByte(WriteCommand);
/* Send new memory byte to the memory to the target */
PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
XMEGANVM_SendAddress(WriteAddress);
PDITarget_SendByte(*(WriteBuffer++));
XPROGTarget_SendByte(*(WriteBuffer++));
return true;
}
@ -233,14 +263,14 @@ bool XMEGANVM_WritePageMemory(const uint8_t WriteBuffCommand, const uint8_t Eras
return false;
/* Send the memory buffer erase command to the target */
PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CMD);
PDITarget_SendByte(EraseBuffCommand);
XPROGTarget_SendByte(EraseBuffCommand);
/* Set CMDEX bit in NVM CTRLA register to start the buffer erase */
PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CTRLA);
PDITarget_SendByte(1 << 0);
XPROGTarget_SendByte(1 << 0);
}
if (WriteSize)
@ -250,22 +280,22 @@ bool XMEGANVM_WritePageMemory(const uint8_t WriteBuffCommand, const uint8_t Eras
return false;
/* Send the memory buffer write command to the target */
PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CMD);
PDITarget_SendByte(WriteBuffCommand);
XPROGTarget_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);
XPROGTarget_SendByte(PDI_CMD_ST | (PDI_POINTER_DIRECT << 2) | PDI_DATSIZE_4BYTES);
XMEGANVM_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);
XPROGTarget_SendByte(PDI_CMD_REPEAT | PDI_DATSIZE_1BYTE);
XPROGTarget_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);
XPROGTarget_SendByte(PDI_CMD_ST | (PDI_POINTER_INDIRECT_PI << 2) | PDI_DATSIZE_1BYTE);
for (uint16_t i = 0; i < WriteSize; i++)
PDITarget_SendByte(*(WriteBuffer++));
XPROGTarget_SendByte(*(WriteBuffer++));
}
if (PageMode & XPRG_PAGEMODE_WRITE)
@ -275,14 +305,14 @@ bool XMEGANVM_WritePageMemory(const uint8_t WriteBuffCommand, const uint8_t Eras
return false;
/* Send the memory write command to the target */
PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CMD);
PDITarget_SendByte(WritePageCommand);
XPROGTarget_SendByte(WritePageCommand);
/* Send the address of the first page location to write the memory page */
PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
XMEGANVM_SendAddress(WriteAddress);
PDITarget_SendByte(0x00);
XPROGTarget_SendByte(0x00);
}
return true;
@ -302,28 +332,28 @@ bool XMEGANVM_EraseMemory(const uint8_t EraseCommand, const uint32_t Address)
return false;
/* Send the memory erase command to the target */
PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CMD);
PDITarget_SendByte(EraseCommand);
XPROGTarget_SendByte(EraseCommand);
/* Chip erase is handled separately, since it's procedure is different to other erase types */
if (EraseCommand == XMEGA_NVM_CMD_CHIPERASE)
{
/* Set CMDEX bit in NVM CTRLA register to start the chip erase */
PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_CTRLA);
PDITarget_SendByte(1 << 0);
XPROGTarget_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));
XPROGTarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
XMEGANVM_SendAddress(Address);
PDITarget_SendByte(0x00);
XPROGTarget_SendByte(0x00);
}
/* Wait until the NVM bus is ready again */
if (!(PDITarget_WaitWhileNVMBusBusy()))
if (!(XMEGANVM_WaitWhileNVMBusBusy()))
return false;
return true;

@ -44,7 +44,7 @@
#include <LUFA/Common/Common.h>
#include "XPROGProtocol.h"
#include "PDITarget.h"
#include "XPROGTarget.h"
/* Preprocessor Checks: */
#if ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1))
@ -56,7 +56,7 @@
#endif
/* Defines: */
#define XMEGA_NVM_BUSY_TIMEOUT_MS 200
#define XMEGA_NVM_BUSY_TIMEOUT_MS 100
#define XMEGA_NVM_REG_ADDR0 0x00
#define XMEGA_NVM_REG_ADDR1 0x01
@ -116,5 +116,6 @@
const uint8_t WritePageCommand, const uint8_t PageMode, const uint32_t WriteAddress,
const uint8_t* WriteBuffer, const uint16_t WriteSize);
bool XMEGANVM_EraseMemory(const uint8_t EraseCommand, const uint32_t Address);
bool XMEGANVM_WaitWhileNVMBusBusy(void);
#endif

@ -113,23 +113,26 @@ static void XPROGProtocol_EnterXPROGMode(void)
if (XPROG_SelectedProtocol == XPRG_PROTOCOL_PDI)
{
/* Enable PDI programming mode with the attached target */
PDITarget_EnableTargetPDI();
XPROGTarget_EnableTargetPDI();
/* Store the RESET key into the RESET PDI register to keep the XMEGA in reset */
PDITarget_SendByte(PDI_CMD_STCS | PDI_RESET_REG);
PDITarget_SendByte(PDI_RESET_KEY);
XPROGTarget_SendByte(PDI_CMD_STCS | PDI_RESET_REG);
XPROGTarget_SendByte(PDI_RESET_KEY);
/* Enable access to the XPROG NVM bus by sending the documented NVM access key to the device */
PDITarget_SendByte(PDI_CMD_KEY);
XPROGTarget_SendByte(PDI_CMD_KEY);
for (uint8_t i = sizeof(PDI_NVMENABLE_KEY); i > 0; i--)
PDITarget_SendByte(PDI_NVMENABLE_KEY[i - 1]);
XPROGTarget_SendByte(PDI_NVMENABLE_KEY[i - 1]);
/* Wait until the NVM bus becomes active */
NVMBusEnabled = PDITarget_WaitWhileNVMBusBusy();
NVMBusEnabled = XMEGANVM_WaitWhileNVMBusBusy();
}
else
{
// TODO
/* Enable TPI programming mode with the attached target */
XPROGTarget_EnableTargetTPI();
// TODO - enable NVM bus via KEY
}
Endpoint_Write_Byte(CMD_XPROG);
@ -149,14 +152,16 @@ static void XPROGProtocol_LeaveXPROGMode(void)
if (XPROG_SelectedProtocol == XPRG_PROTOCOL_PDI)
{
/* Clear the RESET key in the RESET PDI register to allow the XMEGA to run */
PDITarget_SendByte(PDI_CMD_STCS | PDI_RESET_REG);
PDITarget_SendByte(0x00);
XPROGTarget_SendByte(PDI_CMD_STCS | PDI_RESET_REG);
XPROGTarget_SendByte(0x00);
PDITarget_DisableTargetPDI();
XPROGTarget_DisableTargetPDI();
}
else
{
// TODO
// TODO - Disable TPI via register
XPROGTarget_DisableTargetTPI();
}
Endpoint_Write_Byte(CMD_XPROG);
@ -381,7 +386,8 @@ static void XPROGProtocol_ReadCRC(void)
}
else
{
// TODO
/* TPI does not support memory CRC */
ReturnStatus = XPRG_ERR_FAILED;
}
Endpoint_Write_Byte(CMD_XPROG);

@ -44,9 +44,8 @@
#include <LUFA/Drivers/USB/USB.h>
#include "../V2Protocol.h"
#include "PDITarget.h"
#include "XPROGTarget.h"
#include "XMEGANVM.h"
#include "TPITarget.h"
#include "TINYNVM.h"
/* Preprocessor Checks: */

@ -33,8 +33,8 @@
* Target-related functions for the PDI Protocol decoder.
*/
#define INCLUDE_FROM_PDITARGET_C
#include "PDITarget.h"
#define INCLUDE_FROM_XPROGTARGET_C
#include "XPROGTarget.h"
#if defined(ENABLE_XPROG_PROTOCOL) || defined(__DOXYGEN__)
@ -49,7 +49,53 @@ volatile uint16_t SoftUSART_Data;
#define SoftUSART_BitCount GPIOR2
/** ISR to manage the software USART when bit-banged USART mode is selected. */
/** ISR to manage the TPI software USART when bit-banged TPI 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_USART_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_USART_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--;
}
}
/** ISR to manage the PDI software USART when bit-banged PDI USART mode is selected. */
ISR(TIMER1_COMPA_vect, ISR_BLOCK)
{
/* Toggle CLOCK pin in a single cycle (see AVR datasheet) */
@ -67,13 +113,13 @@ ISR(TIMER1_COMPA_vect, ISR_BLOCK)
return;
/* Wait for the start bit when receiving */
if ((SoftUSART_BitCount == BITS_IN_PDI_FRAME) && (BITBANG_PDIDATA_PIN & BITBANG_PDIDATA_MASK))
if ((SoftUSART_BitCount == BITS_IN_USART_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_PDI_FRAME - 1));
SoftUSART_Data |= (1 << (BITS_IN_USART_FRAME - 1));
SoftUSART_Data >>= 1;
SoftUSART_BitCount--;
@ -96,8 +142,50 @@ ISR(TIMER1_COMPA_vect, ISR_BLOCK)
}
#endif
/** Enables the target's TPI interface, holding the target in reset until TPI mode is exited. */
void XPROGTarget_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(XPROG_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) */
XPROGTarget_SendBreak();
XPROGTarget_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) */
XPROGTarget_SendBreak();
XPROGTarget_SendBreak();
#endif
}
/** Enables the target's PDI interface, holding the target in reset until PDI mode is exited. */
void PDITarget_EnableTargetPDI(void)
void XPROGTarget_EnableTargetPDI(void)
{
#if defined(XPROG_VIA_HARDWARE_USART)
/* Set Tx and XCK as outputs, Rx as input */
@ -116,8 +204,8 @@ void PDITarget_EnableTargetPDI(void)
UCSR1C = (1 << UMSEL10) | (1 << UPM11) | (1 << USBS1) | (1 << UCSZ11) | (1 << UCSZ10) | (1 << UCPOL1);
/* Send two BREAKs of 12 bits each to enable PDI interface (need at least 16 idle bits) */
PDITarget_SendBreak();
PDITarget_SendBreak();
XPROGTarget_SendBreak();
XPROGTarget_SendBreak();
#else
/* Set DATA and CLOCK lines to outputs */
BITBANG_PDIDATA_DDR |= BITBANG_PDIDATA_MASK;
@ -134,13 +222,40 @@ void PDITarget_EnableTargetPDI(void)
TIMSK1 = (1 << OCIE1A);
/* Send two BREAKs of 12 bits each to enable TPI interface (need at least 16 idle bits) */
PDITarget_SendBreak();
PDITarget_SendBreak();
XPROGTarget_SendBreak();
XPROGTarget_SendBreak();
#endif
}
/** Disables the target's TPI interface, exits programming mode and starts the target's application. */
void XPROGTarget_DisableTargetTPI(void)
{
#if defined(XPROG_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;
}
/** Disables the target's PDI interface, exits programming mode and starts the target's application. */
void PDITarget_DisableTargetPDI(void)
void XPROGTarget_DisableTargetPDI(void)
{
#if defined(XPROG_VIA_HARDWARE_USART)
/* Turn off receiver and transmitter of the USART, clear settings */
@ -166,7 +281,7 @@ void PDITarget_DisableTargetPDI(void)
*
* \param[in] Byte Byte to send through the USART
*/
void PDITarget_SendByte(const uint8_t Byte)
void XPROGTarget_SendByte(const uint8_t Byte)
{
#if defined(XPROG_VIA_HARDWARE_USART)
/* Switch to Tx mode if currently in Rx mode */
@ -211,7 +326,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_PDI_FRAME;
SoftUSART_BitCount = BITS_IN_USART_FRAME;
#endif
}
@ -219,7 +334,7 @@ void PDITarget_SendByte(const uint8_t Byte)
*
* \return Received byte from the USART
*/
uint8_t PDITarget_ReceiveByte(void)
uint8_t XPROGTarget_ReceiveByte(void)
{
#if defined(XPROG_VIA_HARDWARE_USART)
/* Switch to Rx mode if currently in Tx mode */
@ -253,7 +368,7 @@ uint8_t PDITarget_ReceiveByte(void)
}
/* Wait until a byte has been received before reading */
SoftUSART_BitCount = BITS_IN_PDI_FRAME;
SoftUSART_BitCount = BITS_IN_USART_FRAME;
while (SoftUSART_BitCount);
/* Throw away the parity and stop bits to leave only the data (start bit is already discarded) */
@ -262,7 +377,7 @@ uint8_t PDITarget_ReceiveByte(void)
}
/** Sends a BREAK via the USART to the attached target, consisting of a full frame of idle bits. */
void PDITarget_SendBreak(void)
void XPROGTarget_SendBreak(void)
{
#if defined(XPROG_VIA_HARDWARE_USART)
/* Switch to Tx mode if currently in Rx mode */
@ -278,7 +393,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_PDI_FRAME; i++)
for (uint8_t i = 0; i < BITS_IN_USART_FRAME; i++)
{
/* Wait for a full cycle of the clock */
while (PIND & (1 << 5));
@ -298,38 +413,8 @@ void PDITarget_SendBreak(void)
/* Need to do nothing for a full frame to send a BREAK */
SoftUSART_Data = 0x0FFF;
SoftUSART_BitCount = BITS_IN_PDI_FRAME;
SoftUSART_BitCount = BITS_IN_USART_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 PDITarget_WaitWhileNVMBusBusy(void)
{
TCNT0 = 0;
TIFR0 = (1 << OCF1A);
uint8_t TimeoutMS = PDI_NVM_TIMEOUT_MS;
/* Poll the STATUS register to check to see if NVM access has been enabled */
while (TimeoutMS)
{
/* Send the LDCS command to read the PDI STATUS register to see the NVM bus is active */
PDITarget_SendByte(PDI_CMD_LDCS | PDI_STATUS_REG);
if (PDITarget_ReceiveByte() & PDI_STATUS_NVM)
return true;
if (TIFR0 & (1 << OCF1A))
{
TIFR0 = (1 << OCF1A);
TimeoutMS--;
}
}
return false;
}
#endif

@ -65,13 +65,20 @@
#define BITBANG_PDICLOCK_DDR RESET_LINE_DDR
#define BITBANG_PDICLOCK_PIN RESET_LINE_PIN
#define BITBANG_PDICLOCK_MASK RESET_LINE_MASK
#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)
#endif
/** Total number of bits in a single USART frame */
#define BITS_IN_PDI_FRAME 12
/** Timeout in milliseconds of a PDI busy-wait command */
#define PDI_NVM_TIMEOUT_MS 100
#define BITS_IN_USART_FRAME 12
#define PDI_CMD_LDS 0x00
#define PDI_CMD_LD 0x20
@ -99,13 +106,35 @@
#define PDI_POINTER_INDIRECT 0
#define PDI_POINTER_INDIRECT_PI 1
#define PDI_POINTER_DIRECT 2
#define TPI_CMD_SLD 0x20
#define TPI_CMD_SST 0x60
#define TPI_CMD_SSTPR 0x68
#define TPI_CMD_SIN 0x10
#define TPI_CMD_SOUT 0x90
#define TPI_CMD_SLDCS 0x80
#define TPI_CMD_SSTCS 0xC0
#define TPI_CMD_SKEY 0xE0
#define TPI_STATUS_REG 0x00
#define TPI_CTRL_REG 0x02
#define TPI_ID_REG 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 (1 << 2)
/* Function Prototypes: */
void PDITarget_EnableTargetPDI(void);
void PDITarget_DisableTargetPDI(void);
void PDITarget_SendByte(const uint8_t Byte);
uint8_t PDITarget_ReceiveByte(void);
void PDITarget_SendBreak(void);
bool PDITarget_WaitWhileNVMBusBusy(void);
void XPROGTarget_EnableTargetTPI(void);
void XPROGTarget_EnableTargetPDI(void);
void XPROGTarget_DisableTargetTPI(void);
void XPROGTarget_DisableTargetPDI(void);
void XPROGTarget_SendByte(const uint8_t Byte);
uint8_t XPROGTarget_ReceiveByte(void);
void XPROGTarget_SendBreak(void);
bool XPROGTarget_WaitWhileNVMBusBusy(void);
#endif

@ -132,9 +132,8 @@ SRC = $(TARGET).c \
Lib/ISP/ISPProtocol.c \
Lib/ISP/ISPTarget.c \
Lib/XPROG/XPROGProtocol.c \
Lib/XPROG/PDITarget.c \
Lib/XPROG/XPROGTarget.c \
Lib/XPROG/XMEGANVM.c \
Lib/XPROG/TPITarget.c \
Lib/XPROG/TINYNVM.c \
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c \
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c \

Loading…
Cancel
Save