diff --git a/LUFA/ManPages/ChangeLog.txt b/LUFA/ManPages/ChangeLog.txt
index bd3b38f472f642cf110b47fb09ec8fe1e0aae36d..bbded93f3553abc2233c32b6b03d27eed50bc885 100644
--- a/LUFA/ManPages/ChangeLog.txt
+++ b/LUFA/ManPages/ChangeLog.txt
@@ -16,6 +16,7 @@
   *  - Added new RNDIS Ethernet Host Class Driver
   *  - Added new RNDIS Ethernet Host ClassDriver demo
   *  - Added CDC_Host_Flush() function to the CDC Host Class driver to flush sent data to the attached device
+  *  - Added PDI programming support for XMEGA devices to the AVRISP programmer project
   *
   *  <b>Changed:</b>
   *  - Removed code in the Keyboard demos to send zeroed reports between two reports with differing numbers of keycodes
diff --git a/Projects/AVRISP/AVRISP.txt b/Projects/AVRISP/AVRISP.txt
index 670c168a7afb77445a7e9bafd9ae8b54ec763c7d..c533af725139dff6b762825f58099a67379d925b 100644
--- a/Projects/AVRISP/AVRISP.txt
+++ b/Projects/AVRISP/AVRISP.txt
@@ -178,6 +178,11 @@
  *    <td>ADC channel number (on supported AVRs) to use for VTARGET level detection.</td> 
  *   </tr>
  *   <tr>
+ *    <td>ENABLE_SPI_PROTOCOL</td>
+ *    <td>Makefile CDEFS</td>
+ *    <td>Define to enable SPI programming protocol support.</td>  
+ *   </tr>
+ *   <tr>
  *    <td>ENABLE_XPROG_PROTOCOL</td>
  *    <td>Makefile CDEFS</td>
  *    <td>Define to enable XMEGA PDI programming protocol support.</td>  
diff --git a/Projects/AVRISP/Doxygen.conf b/Projects/AVRISP/Doxygen.conf
index eb8a1ab4c23879c3e54588ceb45dbff3d842bb2e..dcaaecb5e7470c29427706ba4fbeda4caef843e0 100644
--- a/Projects/AVRISP/Doxygen.conf
+++ b/Projects/AVRISP/Doxygen.conf
@@ -1221,7 +1221,7 @@ INCLUDE_FILE_PATTERNS  =
 # undefined via #undef or recursively expanded use the := operator 
 # instead of the = operator.
 
-PREDEFINED             = __DOXYGEN__
+PREDEFINED             = __DOXYGEN__ ENABLE_SPI_PROTOCOL ENABLE_PDI_PROTOCOL
 
 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
 # this tag can be used to specify a list of macro names that should be expanded. 
diff --git a/Projects/AVRISP/Lib/ISPProtocol.c b/Projects/AVRISP/Lib/ISPProtocol.c
index c023234c3a04642e169b5aae9df597f4b43f2427..4847c35fcb4ee20d5b7bd8b218f5c732616b9b21 100644
--- a/Projects/AVRISP/Lib/ISPProtocol.c
+++ b/Projects/AVRISP/Lib/ISPProtocol.c
@@ -28,6 +28,8 @@
   this software.
 */
 
+#if defined(ENABLE_SPI_PROTOCOL)
+
 /** \file
  *
  *  ISP Protocol handler, to process V2 Protocol wrapped ISP commands used in Atmel programmer devices.
@@ -468,3 +470,5 @@ void ISPProtocol_SPIMulti(void)
 	Endpoint_Write_Byte(STATUS_CMD_OK);
 	Endpoint_ClearIN();
 }
+
+#endif
\ No newline at end of file
diff --git a/Projects/AVRISP/Lib/ISPTarget.c b/Projects/AVRISP/Lib/ISPTarget.c
index 87158460bcc1f39205336f451ec0afdab912b14a..aab64a939c009a731f2b48e0522945a58bb6c43f 100644
--- a/Projects/AVRISP/Lib/ISPTarget.c
+++ b/Projects/AVRISP/Lib/ISPTarget.c
@@ -28,6 +28,8 @@
   this software.
 */
 
+#if defined(ENABLE_SPI_PROTOCOL)
+
 /** \file
  *
  *  Target-related functions for the ISP Protocol decoder.
@@ -178,3 +180,5 @@ void ISPTarget_LoadExtendedAddress(void)
 	SPI_SendByte((CurrentAddress & 0x00FF0000) >> 16);
 	SPI_SendByte(0x00);	
 }
+
+#endif
diff --git a/Projects/AVRISP/Lib/PDIProtocol.c b/Projects/AVRISP/Lib/PDIProtocol.c
index c91956143598dff9bc775ccb25b46fa5b0976a72..2ed3ff293e0aa09a110c6da05450c20955045a12 100644
--- a/Projects/AVRISP/Lib/PDIProtocol.c
+++ b/Projects/AVRISP/Lib/PDIProtocol.c
@@ -30,6 +30,8 @@
 
 #if defined(ENABLE_XPROG_PROTOCOL)
 
+#warning PDI Programming Protocol support is incomplete and not currently suitable for use.
+
 /** \file
  *
  *  PDI Protocol handler, to process V2 Protocol wrapped PDI commands used in Atmel programmer devices.
@@ -61,6 +63,9 @@ void PDIProtocol_XPROG_SetMode(void)
 	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 PDIProtocol_XPROG_Command(void)
 {
 	uint8_t XPROGCommand = Endpoint_Read_Byte();
@@ -74,7 +79,7 @@ void PDIProtocol_XPROG_Command(void)
 			PDIProtocol_LeaveXPROGMode();
 			break;
 		case XPRG_CMD_ERASE:
-			PDIProtocol_EraseChip();
+			PDIProtocol_Erase();
 			break;
 		case XPRG_CMD_WRITE_MEM:
 			PDIProtocol_WriteMemory();
@@ -91,6 +96,7 @@ void PDIProtocol_XPROG_Command(void)
 	}
 }
 
+/** Handler for the XPROG ENTER_PROGMODE command to establish a PDI connection with the attached device. */
 static void PDIProtocol_EnterXPROGMode(void)
 {
 	uint8_t ReturnStatus = XPRG_ERR_OK;
@@ -101,22 +107,20 @@ static void PDIProtocol_EnterXPROGMode(void)
 	PDIDATA_LINE_DDR  |= PDIDATA_LINE_MASK;
 	PDICLOCK_LINE_DDR |= PDICLOCK_LINE_MASK;
 	
+	/* Must hold DATA line high for at least 90nS to enable PDI interface */
 	PDIDATA_LINE_PORT |= PDIDATA_LINE_MASK;
-
 	_delay_us(1);
 	
+	/* Toggle CLOCK line 16 times within 100uS of the original 90nS timeout to keep PDI interface enabled */
 	for (uint8_t i = 0; i < 16; i++)
-	{
-		PDICLOCK_LINE_PORT ^= PDICLOCK_LINE_MASK;
-		PDICLOCK_LINE_PORT ^= PDICLOCK_LINE_MASK;
-	}
-		
-	static const uint8_t NVMKey[8] = {0x12, 0x89, 0xAB, 0x45, 0xCD, 0xD8, 0x88, 0xFF};
+	  TOGGLE_PDI_CLOCK;
 	
+	/* Enable access to the XPROG NVM bus by sending the documented NVM access key to the device */
 	PDITarget_SendByte(PDI_CMD_KEY);	
 	for (uint8_t i = 0; i < 8; i++)
-	  PDITarget_SendByte(NVMKey[i]);
+	  PDITarget_SendByte(PDI_NVMENABLE_KEY[i]);
 
+	/* Read out the STATUS register to check that NVM access was successfully enabled */
 	PDITarget_SendByte(PDI_CMD_LDCS | PD_STATUS_REG);	
 	if (!(PDITarget_ReceiveByte() & PDI_STATUS_NVM))
 	  ReturnStatus = XPRG_ERR_FAILED;
@@ -127,14 +131,19 @@ static void PDIProtocol_EnterXPROGMode(void)
 	Endpoint_ClearIN();
 }
 
+/** Handler for the XPROG LEAVE_PROGMODE command to terminate the PDI programming connection with
+ *  the attached device.
+ */
 static void PDIProtocol_LeaveXPROGMode(void)
 {
 	Endpoint_ClearOUT();
 	Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
 	
+	/* Set DATA and CLOCK lines to inputs */
 	PDIDATA_LINE_DDR   &= ~PDIDATA_LINE_MASK;
 	PDICLOCK_LINE_DDR  &= ~PDICLOCK_LINE_MASK;
-
+	
+	/* Tristate DATA and CLOCK lines */
 	PDIDATA_LINE_PORT  &= ~PDIDATA_LINE_MASK;
 	PDICLOCK_LINE_PORT &= ~PDICLOCK_LINE_MASK;
 	
@@ -144,7 +153,8 @@ static void PDIProtocol_LeaveXPROGMode(void)
 	Endpoint_ClearIN();
 }
 
-static void PDIProtocol_EraseChip(void)
+/** Handler for the XPRG ERASE command to erase a specific memory address space in the attached device. */
+static void PDIProtocol_Erase(void)
 {
 	uint8_t ReturnStatus = XPRG_ERR_OK;
 
@@ -167,6 +177,7 @@ static void PDIProtocol_EraseChip(void)
 	Endpoint_ClearIN();	
 }
 
+/** Handler for the XPROG WRITE_MEMORY command to write to a specific memory space within the attached device. */
 static void PDIProtocol_WriteMemory(void)
 {
 	uint8_t ReturnStatus = XPRG_ERR_OK;
@@ -196,6 +207,9 @@ static void PDIProtocol_WriteMemory(void)
 	Endpoint_ClearIN();
 }
 
+/** Handler for the XPROG READ_MEMORY command to read data from a specific address space within the
+ *  attached device.
+ */
 static void PDIProtocol_ReadMemory(void)
 {
 	uint8_t ReturnStatus = XPRG_ERR_OK;
@@ -219,23 +233,13 @@ static void PDIProtocol_ReadMemory(void)
 	Endpoint_Write_Byte(CMD_XPROG);
 	Endpoint_Write_Byte(XPRG_CMD_READ_MEM);
 	Endpoint_Write_Byte(ReturnStatus);
-
-	// START TEMP
-	uint8_t ProgData[256];
-	for (uint16_t i = 0; i < ReadMemory_XPROG_Params.Length; i++)
-	  ProgData[i] = i;
-	Endpoint_Write_Stream_LE(ProgData, ReadMemory_XPROG_Params.Length);
-
-	if (!Endpoint_IsReadWriteAllowed())
-	{
-		Endpoint_ClearIN();	
-		while(!(Endpoint_IsReadWriteAllowed()));
-	}
-	// END TEMP
 	
 	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 PDIProtocol_ReadCRC(void)
 {
 	uint8_t ReturnStatus = XPRG_ERR_OK;
@@ -262,6 +266,9 @@ static void PDIProtocol_ReadCRC(void)
 	Endpoint_ClearIN();	
 }
 
+/** Handler for the XPROG SET_PARAM command to set a PDI parameter for use when communicating with the
+ *  attached device.
+ */
 static void PDIProtocol_SetParam(void)
 {
 	uint8_t ReturnStatus = XPRG_ERR_OK;
diff --git a/Projects/AVRISP/Lib/PDIProtocol.h b/Projects/AVRISP/Lib/PDIProtocol.h
index 53388d0609641f45ce89a27beb2d796f872f52da..406ba273221249096480474a3cdd82c637790ec8 100644
--- a/Projects/AVRISP/Lib/PDIProtocol.h
+++ b/Projects/AVRISP/Lib/PDIProtocol.h
@@ -92,7 +92,7 @@
 			static void PDIProtocol_EnterXPROGMode(void);
 			static void PDIProtocol_LeaveXPROGMode(void);
 			static void PDIProtocol_SetParam(void);
-			static void PDIProtocol_EraseChip(void);
+			static void PDIProtocol_Erase(void);
 			static void PDIProtocol_WriteMemory(void);
 			static void PDIProtocol_ReadMemory(void);
 			static void PDIProtocol_ReadCRC(void);
diff --git a/Projects/AVRISP/Lib/PDITarget.c b/Projects/AVRISP/Lib/PDITarget.c
index 57a1a29eeba5aff34af7b783032ce43f657a35a3..d1042068f6c1403edaa235e2e251c19016e83fd5 100644
--- a/Projects/AVRISP/Lib/PDITarget.c
+++ b/Projects/AVRISP/Lib/PDITarget.c
@@ -38,12 +38,16 @@
 #define  INCLUDE_FROM_PDITARGET_C
 #include "PDITarget.h"
 
+/** Writes a given byte to the attached XMEGA device, using a RS232 frame via software through the
+ *  PDI interface.
+ *
+ *  \param Byte  Byte to send to the attached device
+ */
 void PDITarget_SendByte(uint8_t Byte)
 {
-	PDIDATA_LINE_PORT  &= ~PDIDATA_LINE_MASK;
+	PDIDATA_LINE_PORT &= ~PDIDATA_LINE_MASK;
 
-	PDICLOCK_LINE_PORT ^= PDICLOCK_LINE_MASK;
-	PDICLOCK_LINE_PORT ^= PDICLOCK_LINE_MASK;	
+	TOGGLE_PDI_CLOCK;
 
 	for (uint8_t i = 0; i < 8; i++)
 	{
@@ -54,33 +58,28 @@ void PDITarget_SendByte(uint8_t Byte)
 		  
 		Byte >>= 1;
 
-		PDICLOCK_LINE_PORT ^= PDICLOCK_LINE_MASK;
-		PDICLOCK_LINE_PORT ^= PDICLOCK_LINE_MASK;	
+		TOGGLE_PDI_CLOCK;
 	}
 
-	PDIDATA_LINE_PORT  |= PDIDATA_LINE_MASK;
+	PDIDATA_LINE_PORT |= PDIDATA_LINE_MASK;
 
-	PDICLOCK_LINE_PORT ^= PDICLOCK_LINE_MASK;
-	PDICLOCK_LINE_PORT ^= PDICLOCK_LINE_MASK;
-	PDICLOCK_LINE_PORT ^= PDICLOCK_LINE_MASK;
-	PDICLOCK_LINE_PORT ^= PDICLOCK_LINE_MASK;
+	TOGGLE_PDI_CLOCK;
+	TOGGLE_PDI_CLOCK;
 }
 
+/** Reads a given byte from the attached XMEGA device, encoded in a RS232 frame through the PDI interface.
+ *
+ *  \return Received byte from the attached device
+ */
 uint8_t PDITarget_ReceiveByte(void)
 {
 	uint8_t ReceivedByte = 0;
 
-	PDIDATA_LINE_DDR   &= ~PDIDATA_LINE_MASK;
+	PDIDATA_LINE_DDR &= ~PDIDATA_LINE_MASK;
 
-	bool FoundStartBit;
-
-	do
-	{
-		PDICLOCK_LINE_PORT ^= PDICLOCK_LINE_MASK;
-		PDICLOCK_LINE_PORT ^= PDICLOCK_LINE_MASK;
-		FoundStartBit = !(PDIDATA_LINE_PIN & PDIDATA_LINE_MASK);
-	} while (!FoundStartBit);
-	
+	while (PDIDATA_LINE_PIN & PDIDATA_LINE_MASK);
+	  TOGGLE_PDI_CLOCK;
+	  
 	for (uint8_t i = 0; i < 8; i++)
 	{
 		if (PDIDATA_LINE_PIN & PDIDATA_LINE_MASK)
@@ -88,16 +87,13 @@ uint8_t PDITarget_ReceiveByte(void)
 
 		ReceivedByte <<= 1;
 
-		PDICLOCK_LINE_PORT ^= PDICLOCK_LINE_MASK;
-		PDICLOCK_LINE_PORT ^= PDICLOCK_LINE_MASK;	
+		TOGGLE_PDI_CLOCK;	
 	}
 
-	PDICLOCK_LINE_PORT ^= PDICLOCK_LINE_MASK;
-	PDICLOCK_LINE_PORT ^= PDICLOCK_LINE_MASK;
-	PDICLOCK_LINE_PORT ^= PDICLOCK_LINE_MASK;
-	PDICLOCK_LINE_PORT ^= PDICLOCK_LINE_MASK;
+	TOGGLE_PDI_CLOCK;
+	TOGGLE_PDI_CLOCK;
 	
-	PDIDATA_LINE_DDR   |= PDIDATA_LINE_MASK;
+	PDIDATA_LINE_DDR |= PDIDATA_LINE_MASK;
 	
 	return ReceivedByte;
 }
diff --git a/Projects/AVRISP/Lib/PDITarget.h b/Projects/AVRISP/Lib/PDITarget.h
index cc8c7dbc5ca91bcf9b25f16cb105746ff23cc1f1..55a1a95622dac978a7cd92c25dd122d3ad421480 100644
--- a/Projects/AVRISP/Lib/PDITarget.h
+++ b/Projects/AVRISP/Lib/PDITarget.h
@@ -39,6 +39,8 @@
 	/* Includes: */
 		#include <avr/io.h>
 		#include <stdbool.h>
+		
+		#include <LUFA/Common/Common.h>
 	
 	/* Defines: */
 		#define PDIDATA_LINE_PORT     PORTB
@@ -64,8 +66,12 @@
 		#define PD_CTRL_REG           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 TOGGLE_PDI_CLOCK      MACROS{ PDICLOCK_LINE_PORT ^= PDICLOCK_LINE_MASK; \
+		                                      PDICLOCK_LINE_PORT ^= PDICLOCK_LINE_MASK; }MACROE
 		
 	/* Function Prototypes: */
 		void    PDITarget_SendByte(uint8_t Byte);
diff --git a/Projects/AVRISP/Lib/V2Protocol.c b/Projects/AVRISP/Lib/V2Protocol.c
index d2e0b168671ac8de419c45f7b38968e63e4c1c16..24f208046c0b528cc0283cae03073be781456c4c 100644
--- a/Projects/AVRISP/Lib/V2Protocol.c
+++ b/Projects/AVRISP/Lib/V2Protocol.c
@@ -66,6 +66,7 @@ void V2Protocol_ProcessCommand(void)
 		case CMD_RESET_PROTECTION:
 			V2Protocol_ResetProtection();
 			break;
+#if defined(ENABLE_SPI_PROTOCOL)
 		case CMD_ENTER_PROGMODE_ISP:
 			ISPProtocol_EnterISPMode();
 			break;
@@ -83,14 +84,6 @@ void V2Protocol_ProcessCommand(void)
 		case CMD_CHIP_ERASE_ISP:
 			ISPProtocol_ChipErase();
 			break;
-#if defined(ENABLE_XPROG_PROTOCOL)
-		case CMD_XPROG_SETMODE:
-			PDIProtocol_XPROG_SetMode();
-			break;
-		case CMD_XPROG:
-			PDIProtocol_XPROG_Command();
-			break;
-#endif
 		case CMD_READ_FUSE_ISP:
 		case CMD_READ_LOCK_ISP:
 		case CMD_READ_SIGNATURE_ISP:
@@ -104,6 +97,15 @@ void V2Protocol_ProcessCommand(void)
 		case CMD_SPI_MULTI:
 			ISPProtocol_SPIMulti();
 			break;
+#endif
+#if defined(ENABLE_XPROG_PROTOCOL)
+		case CMD_XPROG_SETMODE:
+			PDIProtocol_XPROG_SetMode();
+			break;
+		case CMD_XPROG:
+			PDIProtocol_XPROG_Command();
+			break;
+#endif
 		default:
 			V2Protocol_UnknownCommand(V2Command);
 			break;
diff --git a/Projects/AVRISP/makefile b/Projects/AVRISP/makefile
index cf4fa0078302752f339fe922c0f6fb2cecac1da2..d7fe4ac196100e240d7a5503df7d9eb71787d0c4 100644
--- a/Projects/AVRISP/makefile
+++ b/Projects/AVRISP/makefile
@@ -193,6 +193,7 @@ CDEFS += -DRESET_LINE_PORT=PORTB
 CDEFS += -DRESET_LINE_DDR=DDRB
 CDEFS += -DRESET_LINE_MASK="(1 << 4)"
 CDEFS += -DVTARGET_ADC_CHANNEL=2
+CDEFS += -DENABLE_SPI_PROTOCOL
 CDEFS += -DENABLE_XPROG_PROTOCOL