diff --git a/Projects/AVRISP/Lib/NVMTarget.c b/Projects/AVRISP/Lib/NVMTarget.c
index c2ed92d2e26ce4da545378718bf674694d67736e..d84ae6b8580d8a36230c37cbb0079ae1437c1342 100644
--- a/Projects/AVRISP/Lib/NVMTarget.c
+++ b/Projects/AVRISP/Lib/NVMTarget.c
@@ -114,6 +114,10 @@ bool NVMTarget_GetMemoryCRC(uint8_t CRCCommand, uint32_t* CRCDest)
 	NVMTarget_SendNVMRegAddress(NVM_REG_CTRLA);
 	PDITarget_SendByte(1 << 0);
 
+	/* Wait until the NVM bus is ready again */
+	if (!(PDITarget_WaitWhileNVMBusBusy()))
+	  return false;
+
 	/* Wait until the NVM controller is no longer busy */
 	if (!(NVMTarget_WaitWhileNVMControllerBusy()))
 	  return false;
@@ -180,6 +184,37 @@ bool NVMTarget_ReadMemory(uint32_t ReadAddress, uint8_t* ReadBuffer, uint16_t Re
 	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 page
+ *  \param[in]  WriteAddress      Start address to write to within the target's address space
+ *  \param[in]  WriteBuffer       Buffer to source data from
+ *  \param[in]  WriteSize         Number of bytes to write
+ *
+ *  \return Boolean true if the command sequence complete sucessfully
+ */
+bool NVMTarget_WriteByteMemory(uint8_t WriteCommand, uint32_t WriteAddress, uint8_t* WriteBuffer, uint16_t WriteSize)
+{
+	for (uint8_t i = 0; i < WriteSize; i++)
+	{
+		/* Wait until the NVM controller is no longer busy */
+		if (!(NVMTarget_WaitWhileNVMControllerBusy()))
+		  return false;
+
+		/* Send the memory write command to the target */
+		PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
+		NVMTarget_SendNVMRegAddress(NVM_REG_CMD);
+		PDITarget_SendByte(WriteCommand);
+	
+		/* Send each new memory byte to the memory to the target */
+		PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
+		NVMTarget_SendAddress(WriteAddress++);
+		PDITarget_SendByte(*(WriteBuffer++));
+	}
+	
+	return true;
+}
+
 /** Erases a specific memory space of the target.
  *
  *  \param[in] EraseCommand  NVM erase command to send to the device
diff --git a/Projects/AVRISP/Lib/NVMTarget.h b/Projects/AVRISP/Lib/NVMTarget.h
index dae55ed1212b68568f8f74d4ada9680dabb844c0..dea9ff3decd644c9819045f1574b598eb0119cb7 100644
--- a/Projects/AVRISP/Lib/NVMTarget.h
+++ b/Projects/AVRISP/Lib/NVMTarget.h
@@ -111,6 +111,8 @@
 		bool NVMTarget_WaitWhileNVMControllerBusy(void);
 		bool NVMTarget_GetMemoryCRC(uint8_t CRCCommand, uint32_t* CRCDest);
 		bool NVMTarget_ReadMemory(uint32_t ReadAddress, uint8_t* ReadBuffer, uint16_t ReadSize);
+		bool NVMTarget_WriteByteMemory(uint8_t WriteCommand, uint32_t WriteAddress, uint8_t* WriteBuffer,
+		                               uint16_t WriteSize);
 		bool NVMTarget_EraseMemory(uint8_t EraseCommand, uint32_t Address);
 
 #endif
diff --git a/Projects/AVRISP/Lib/PDIProtocol.c b/Projects/AVRISP/Lib/PDIProtocol.c
index 46d6dd417e92446ff32f8fbc2938cdd7d0cd8ee4..36aa3b4c5c9740912cf6c0699da20801f79fc5dc 100644
--- a/Projects/AVRISP/Lib/PDIProtocol.c
+++ b/Projects/AVRISP/Lib/PDIProtocol.c
@@ -162,7 +162,7 @@ static void PDIProtocol_Erase(void)
 	Endpoint_ClearOUT();
 	Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
 	
-	uint8_t EraseCommand;
+	uint8_t EraseCommand = NVM_CMD_NOOP;
 	
 	if (Erase_XPROG_Params.MemoryType == XPRG_ERASE_CHIP)
 	  EraseCommand = NVM_CMD_CHIPERASE;
@@ -198,9 +198,10 @@ static void PDIProtocol_WriteMemory(void)
 	struct
 	{
 		uint8_t  MemoryType;
+		uint8_t  PageMode;
 		uint32_t Address;
 		uint16_t Length;
-		uint8_t  ProgData[256];
+		uint8_t  ProgData[512];
 	} WriteMemory_XPROG_Params;
 	
 	Endpoint_Read_Stream_LE(&WriteMemory_XPROG_Params, (sizeof(WriteMemory_XPROG_Params) -
@@ -211,11 +212,52 @@ static void PDIProtocol_WriteMemory(void)
 
 	Endpoint_ClearOUT();
 	Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
+
+
+	uint8_t WriteCommand     = NVM_CMD_NOOP;
+	uint8_t WritePageCommand = NVM_CMD_NOOP;
+	bool    PagedMemory      = false;
+	
+	if (WriteMemory_XPROG_Params.MemoryType == XPRG_MEM_TYPE_APPL)
+	{
+		PagedMemory = true;
+	}
+	else if (WriteMemory_XPROG_Params.MemoryType == XPRG_MEM_TYPE_BOOT)
+	{
+		PagedMemory = true;
+	}
+	else if (WriteMemory_XPROG_Params.MemoryType == XPRG_MEM_TYPE_EEPROM)
+	{
+		PagedMemory = true;
+	}
+	else if (WriteMemory_XPROG_Params.MemoryType == XPRG_MEM_TYPE_USERSIG)
+	{
+		PagedMemory = true;
+	}
+	else if (WriteMemory_XPROG_Params.MemoryType == XPRG_MEM_TYPE_FUSE)
+	{
+		WriteCommand = NVM_CMD_WRITEFUSE;
+	}
+	else if (WriteMemory_XPROG_Params.MemoryType == XPRG_MEM_TYPE_LOCKBITS)
+	{
+		WriteCommand = NVM_CMD_WRITELOCK;
+	}
 	
-	// TODO: Send program command here via PDI protocol
+	if (PagedMemory)
+	{
+
+	}
+	else
+	{
+		if (!(NVMTarget_WriteByteMemory(WriteCommand, WriteMemory_XPROG_Params.Address, WriteMemory_XPROG_Params.ProgData,
+										WriteMemory_XPROG_Params.Length)))
+		{
+			ReturnStatus = XPRG_ERR_TIMEOUT;
+		}
+	}
 	
 	Endpoint_Write_Byte(CMD_XPROG);
-	Endpoint_Write_Byte(XPRG_CMD_READ_MEM);
+	Endpoint_Write_Byte(XPRG_CMD_WRITE_MEM);
 	Endpoint_Write_Byte(ReturnStatus);	
 	Endpoint_ClearIN();
 }
@@ -272,8 +314,8 @@ static void PDIProtocol_ReadCRC(void)
 	Endpoint_ClearOUT();
 	Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
 	
+	uint8_t  CRCCommand = NVM_CMD_NOOP;
 	uint32_t MemoryCRC;
-	uint8_t  CRCCommand;
 
 	if (ReadCRC_XPROG_Params.CRCType == XPRG_CRC_APP)
 	  CRCCommand = NVM_CMD_APPCRC;