Commit 307ba254 authored by Dean Camera's avatar Dean Camera
Browse files

The AVRISP project can now enter PDI mode under both bit-bang and hardware...

The AVRISP project can now enter PDI mode under both bit-bang and hardware USART connection modes, tested against the XPLAIN board hardware. Still need to complete higher level NVM access code so that the device's memories can be read and written.
parent 33a46b24
This diff is collapsed.
......@@ -17,7 +17,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
* - Added PDI programming support for XMEGA devices to the AVRISP programmer project (thanks to Justin Mattair)
* - Added support for the XPLAIN board Dataflash, with new XPLAIN_REV1 board target for the different dataflash used
* on the first revision boards compared to the one mounted on later revisions
* - Added new HID_ALIGN_DATA() macro to return the pre-retrieved value of a HID report item, left-aligned to a given datatype
......
......@@ -168,6 +168,11 @@
* <td>PORT register for the programmer's target RESET line. <i>Ignored when compiled for the XPLAIN board.</i></td>
* </tr>
* <tr>
* <td>RESET_LINE_PIN</td>
* <td>Makefile CDEFS</td>
* <td>PIN register for the programmer's target RESET line. <i>Ignored when compiled for the XPLAIN board.</i></td>
* </tr>
* <tr>
* <td>RESET_LINE_DDR</td>
* <td>Makefile CDEFS</td>
* <td>DDR register for the programmer's target RESET line. <i>Ignored when compiled for the XPLAIN board.</i></td>
......
......@@ -106,7 +106,7 @@ static void PDIProtocol_EnterXPROGMode(void)
PDITarget_EnableTargetPDI();
/* Store the RESET key into the RESET PDI register to keep the XMEGA in reset */
PDITarget_SendByte(PDI_CMD_STCS | PD_RESET_REG);
PDITarget_SendByte(PDI_CMD_STCS | PDI_RESET_REG);
PDITarget_SendByte(PDI_RESET_KEY);
/* Enable access to the XPROG NVM bus by sending the documented NVM access key to the device */
......@@ -114,20 +114,12 @@ static void PDIProtocol_EnterXPROGMode(void)
for (uint8_t i = sizeof(PDI_NVMENABLE_KEY); i > 0; i--)
PDITarget_SendByte(PDI_NVMENABLE_KEY[i - 1]);
/* Poll the STATUS register to check to see if NVM access has been enabled */
uint8_t NVMAttemptsRemaining = 255;
while (NVMAttemptsRemaining)
{
PDITarget_SendByte(PDI_CMD_LDCS | PD_STATUS_REG);
if (PDITarget_ReceiveByte() & PDI_STATUS_NVM)
break;
NVMAttemptsRemaining--;
}
/* Wait until the NVM bus becomes active */
bool NVMBusEnabled = PDITarget_WaitWhileNVMBusBusy();
Endpoint_Write_Byte(CMD_XPROG);
Endpoint_Write_Byte(XPRG_CMD_ENTER_PROGMODE);
Endpoint_Write_Byte(NVMAttemptsRemaining ? XPRG_ERR_OK : XPRG_ERR_FAILED);
Endpoint_Write_Byte(NVMBusEnabled ? XPRG_ERR_OK : XPRG_ERR_FAILED);
Endpoint_ClearIN();
}
......@@ -140,7 +132,7 @@ static void PDIProtocol_LeaveXPROGMode(void)
Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
/* Clear the RESET key into the RESET PDI register to allow the XMEGA to run */
PDITarget_SendByte(PDI_CMD_STCS | PD_RESET_REG);
PDITarget_SendByte(PDI_CMD_STCS | PDI_RESET_REG);
PDITarget_SendByte(0x00);
PDITarget_DisableTargetPDI();
......
......@@ -41,131 +41,54 @@
volatile bool IsSending;
#if !defined(PDI_VIA_HARDWARE_USART)
volatile uint16_t DataBits;
volatile uint8_t BitCount;
volatile uint16_t SoftUSART_Data;
volatile uint8_t SoftUSART_BitCount;
ISR(TIMER0_COMPA_vect, ISR_BLOCK)
{
BITBANG_PDICLOCK_PORT ^= BITBANG_PDICLOCK_MASK;
/* Toggle CLOCK pin in a single cycle (see AVR datasheet) */
BITBANG_PDICLOCK_PIN |= BITBANG_PDICLOCK_MASK;
/* If not sending or receiving, just exit */
if (!(BitCount))
if (!(SoftUSART_BitCount))
return;
/* Check to see if the current clock state is on the rising or falling edge */
bool IsRisingEdge = (BITBANG_PDICLOCK_PORT & BITBANG_PDICLOCK_MASK);
if (IsSending && !IsRisingEdge)
{
if (DataBits & 0x01)
BITBANG_PDIDATA_PORT &= ~BITBANG_PDIDATA_MASK;
if (SoftUSART_Data & 0x01)
BITBANG_PDIDATA_PORT |= BITBANG_PDIDATA_MASK;
else
BITBANG_PDIDATA_PORT |= BITBANG_PDIDATA_MASK;
BITBANG_PDIDATA_PORT &= ~BITBANG_PDIDATA_MASK;
DataBits >>= 1;
BitCount--;
SoftUSART_Data >>= 1;
SoftUSART_BitCount--;
}
else if (!IsSending && IsRisingEdge)
{
/* Wait for the start bit when receiving */
if ((BitCount == BITS_IN_FRAME) && (BITBANG_PDIDATA_PORT & BITBANG_PDIDATA_MASK))
if ((SoftUSART_BitCount == BITS_IN_FRAME) && (BITBANG_PDIDATA_PIN & BITBANG_PDIDATA_MASK))
return;
if (BITBANG_PDIDATA_PORT & BITBANG_PDIDATA_MASK)
DataBits |= (1 << (BITS_IN_FRAME - 1));
if (BITBANG_PDIDATA_PIN & BITBANG_PDIDATA_MASK)
SoftUSART_Data |= (1 << BITS_IN_FRAME);
DataBits >>= 1;
BitCount--;
SoftUSART_Data >>= 1;
SoftUSART_BitCount--;
}
}
#endif
void PDITarget_EnableTargetPDI(void)
{
/* Set DATA and CLOCK lines to outputs */
BITBANG_PDIDATA_DDR |= BITBANG_PDIDATA_MASK;
BITBANG_PDICLOCK_DDR |= BITBANG_PDICLOCK_MASK;
/* Set DATA line high for 90ns to disable /RESET functionality */
BITBANG_PDIDATA_PORT |= BITBANG_PDIDATA_MASK;
asm volatile ("NOP"::);
asm volatile ("NOP"::);
/* Fire timer compare ISR every 160 cycles */
OCR0A = 20;
TCCR0A = (1 << WGM01);
TCCR0B = (1 << CS01);
TIMSK0 = (1 << OCIE0A);
}
void PDITarget_DisableTargetPDI(void)
{
/* Set DATA and CLOCK lines to inputs */
BITBANG_PDIDATA_DDR &= ~BITBANG_PDIDATA_MASK;
BITBANG_PDICLOCK_DDR &= ~BITBANG_PDICLOCK_MASK;
/* Tristate DATA and CLOCK lines */
BITBANG_PDIDATA_PORT &= ~BITBANG_PDIDATA_MASK;
BITBANG_PDICLOCK_PORT &= ~BITBANG_PDICLOCK_MASK;
TCCR0B = 0;
}
void PDITarget_SendByte(uint8_t Byte)
{
bool IsOddBitsSet = false;
/* Compute Even parity bit */
for (uint8_t i = 0; i < 8; i++)
{
if (Byte & (1 << i))
IsOddBitsSet = !(IsOddBitsSet);
}
/* Data shifted out LSB first, START DATA PARITY STOP STOP */
DataBits = ((uint16_t)IsOddBitsSet << 10) | ((uint16_t)Byte << 1) | (1 << 0);
BITBANG_PDIDATA_PORT |= BITBANG_PDIDATA_MASK;
BITBANG_PDIDATA_DDR |= BITBANG_PDIDATA_MASK;
IsSending = true;
BitCount = BITS_IN_FRAME;
while (BitCount);
BITBANG_PDIDATA_PORT &= ~BITBANG_PDIDATA_MASK;
BITBANG_PDIDATA_DDR &= ~BITBANG_PDIDATA_MASK;
}
uint8_t PDITarget_ReceiveByte(void)
{
IsSending = false;
BitCount = BITS_IN_FRAME;
while (BitCount);
return (DataBits >> 1);
}
void PDITarget_SendBreak(void)
{
DataBits = 0;
BITBANG_PDIDATA_PORT |= BITBANG_PDIDATA_MASK;
BITBANG_PDIDATA_DDR |= BITBANG_PDIDATA_MASK;
IsSending = true;
BitCount = BITS_IN_FRAME;
while (BitCount);
BITBANG_PDIDATA_PORT &= ~BITBANG_PDIDATA_MASK;
BITBANG_PDIDATA_DDR &= ~BITBANG_PDIDATA_MASK;
}
#else
void PDITarget_EnableTargetPDI(void)
{
#if defined(PDI_VIA_HARDWARE_USART)
/* Set Tx and XCK as outputs, Rx as input */
DDRD |= (1 << 5) | (1 << 3);
DDRD &= ~(1 << 2);
/* Set DATA line high for 90ns to disable /RESET functionality */
/* Set DATA line high for at least 90ns to disable /RESET functionality */
PORTD |= (1 << 3);
asm volatile ("NOP"::);
asm volatile ("NOP"::);
......@@ -179,10 +102,30 @@ void PDITarget_EnableTargetPDI(void)
/* Send two BREAKs of 12 bits each to enable PDI interface (need at least 16 idle bits) */
PDITarget_SendBreak();
PDITarget_SendBreak();
#else
/* Set DATA and CLOCK lines to outputs */
BITBANG_PDIDATA_DDR |= BITBANG_PDIDATA_MASK;
BITBANG_PDICLOCK_DDR |= BITBANG_PDICLOCK_MASK;
/* Set DATA line high for at least 90ns to disable /RESET functionality */
BITBANG_PDIDATA_PORT |= BITBANG_PDIDATA_MASK;
asm volatile ("NOP"::);
asm volatile ("NOP"::);
/* Fire timer compare ISR every 50 cycles to manage the software USART */
OCR0A = 50;
TCCR0A = (1 << WGM01);
TCCR0B = (1 << CS00);
TIMSK0 = (1 << OCIE0A);
PDITarget_SendBreak();
PDITarget_SendBreak();
#endif
}
void PDITarget_DisableTargetPDI(void)
{
#if defined(PDI_VIA_HARDWARE_USART)
/* Turn off receiver and transmitter of the USART, clear settings */
UCSR1A |= (1 << TXC1) | (1 << RXC1);
UCSR1B = 0;
......@@ -191,10 +134,22 @@ void PDITarget_DisableTargetPDI(void)
/* 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_PDIDATA_DDR &= ~BITBANG_PDIDATA_MASK;
BITBANG_PDICLOCK_DDR &= ~BITBANG_PDICLOCK_MASK;
/* Tristate DATA and CLOCK lines */
BITBANG_PDIDATA_PORT &= ~BITBANG_PDIDATA_MASK;
BITBANG_PDICLOCK_PORT &= ~BITBANG_PDICLOCK_MASK;
TCCR0B = 0;
#endif
}
void PDITarget_SendByte(uint8_t Byte)
{
#if defined(PDI_VIA_HARDWARE_USART)
/* Switch to Tx mode if currently in Rx mode */
if (!(IsSending))
{
......@@ -210,10 +165,37 @@ void PDITarget_SendByte(uint8_t Byte)
/* Wait until there is space in the hardware Tx buffer before writing */
while (!(UCSR1A & (1 << UDRE1)));
UDR1 = Byte;
#else
/* Switch to Tx mode if currently in Rx mode */
if (!(IsSending))
{
BITBANG_PDIDATA_PORT |= BITBANG_PDIDATA_MASK;
BITBANG_PDIDATA_DDR |= BITBANG_PDIDATA_MASK;
IsSending = true;
}
bool EvenParityBit = false;
uint8_t ParityData = Byte;
/* Compute Even parity bit */
for (uint8_t i = 0; i < 8; i++)
{
EvenParityBit ^= ParityData & 0x01;
ParityData >>= 1;
}
while (SoftUSART_BitCount);
/* Data shifted out LSB first, START DATA PARITY STOP STOP */
SoftUSART_Data = ((uint16_t)EvenParityBit << 9) | ((uint16_t)Byte << 1) | (1 << 10) | (1 << 11);
SoftUSART_BitCount = BITS_IN_FRAME;
#endif
}
uint8_t PDITarget_ReceiveByte(void)
{
#if defined(PDI_VIA_HARDWARE_USART)
/* Switch to Rx mode if currently in Tx mode */
if (IsSending)
{
......@@ -232,10 +214,30 @@ uint8_t PDITarget_ReceiveByte(void)
/* Wait until a byte has been received before reading */
while (!(UCSR1A & (1 << RXC1)));
return UDR1;
#else
/* Switch to Rx mode if currently in Tx mode */
if (IsSending)
{
while (SoftUSART_BitCount);
BITBANG_PDIDATA_DDR &= ~BITBANG_PDIDATA_MASK;
BITBANG_PDIDATA_PORT &= ~BITBANG_PDIDATA_MASK;
IsSending = false;
}
/* Wait until a byte has been received before reading */
SoftUSART_BitCount = BITS_IN_FRAME;
while (SoftUSART_BitCount);
/* Throw away the start, parity and stop bits to leave only the data */
return (uint8_t)(SoftUSART_Data >> 1);
#endif
}
void PDITarget_SendBreak(void)
{
#if defined(PDI_VIA_HARDWARE_USART)
/* Switch to Tx mode if currently in Rx mode */
if (!(IsSending))
{
......@@ -251,13 +253,62 @@ void PDITarget_SendBreak(void)
/* Need to do nothing for a full frame to send a BREAK */
for (uint8_t i = 0; i <= BITS_IN_FRAME; i++)
{
/* Wait for rising edge of clock */
/* Wait for a full cycle of the clock */
while (PIND & (1 << 5));
/* Wait for falling edge of clock */
while (!(PIND & (1 << 5)));
}
}
#else
/* Switch to Tx mode if currently in Rx mode */
if (!(IsSending))
{
BITBANG_PDIDATA_PORT |= BITBANG_PDIDATA_MASK;
BITBANG_PDIDATA_DDR |= BITBANG_PDIDATA_MASK;
IsSending = true;
}
while (SoftUSART_BitCount);
/* Need to do nothing for a full frame to send a BREAK */
SoftUSART_Data = 0x0FFF;
SoftUSART_BitCount = BITS_IN_FRAME;
#endif
}
void PDITarget_SendAddress(uint32_t Address)
{
PDITarget_SendByte(Address >> 24);
PDITarget_SendByte(Address >> 26);
PDITarget_SendByte(Address >> 8);
PDITarget_SendByte(Address & 0xFF);
}
bool PDITarget_WaitWhileNVMBusBusy(void)
{
uint8_t AttemptsRemaining = 255;
/* Poll the STATUS register to check to see if NVM access has been enabled */
while (AttemptsRemaining--)
{
PDITarget_SendByte(PDI_CMD_LDCS | PDI_STATUS_REG);
if (PDITarget_ReceiveByte() & PDI_STATUS_NVM)
return true;
}
return false;
}
void PDITarget_WaitWhileNVMControllerBusy(void)
{
/* Poll the NVM STATUS register to check to see if NVM controller is busy */
for (;;)
{
PDITarget_SendByte(PDI_CMD_LDS | (PDI_DATSIZE_1BYTE << 2));
PDITarget_SendAddress(DATAMEM_BASE | DATAMEM_NVM_BASE | 0x0F);
if (!(PDITarget_ReceiveByte() & (1 << 7)))
return;
}
}
#endif
......@@ -63,34 +63,57 @@
#define BITBANG_PDICLOCK_PORT RESET_LINE_PORT
#define BITBANG_PDICLOCK_DDR RESET_LINE_DDR
#define BITBANG_PDICLOCK_PIN RESET_LINE_PIN
#define BITBANG_PDICLOCK_MASK RESET_LINE_MASK
#endif
#define BITS_IN_FRAME 12
#define BITS_IN_FRAME 12
#define PDI_CMD_LDS 0x00
#define PDI_CMD_LD 0x20
#define PDI_CMD_STS 0x40
#define PDI_CMD_ST 0x60
#define PDI_CMD_LDCS 0x80
#define PDI_CMD_REPEAT 0xA0
#define PDI_CMD_STCS 0xC0
#define PDI_CMD_KEY 0xE0
#define PDI_CMD_LDS 0x00
#define PDI_CMD_LD 0x20
#define PDI_CMD_STS 0x40
#define PDI_CMD_ST 0x60
#define PDI_CMD_LDCS 0x80
#define PDI_CMD_REPEAT 0xA0
#define PDI_CMD_STCS 0xC0
#define PDI_CMD_KEY 0xE0
#define PD_STATUS_REG 0
#define PD_RESET_REG 1
#define PD_CTRL_REG 2
#define PDI_STATUS_REG 0
#define PDI_RESET_REG 1
#define PDI_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 PDI_STATUS_NVM (1 << 1)
#define PDI_DATSIZE_1BYTE 0
#define PDI_DATSIZE_2BYTES 1
#define PDI_DATSIZE_3BYTES 2
#define PDI_DATSIZE_4BYTES 3
#define PDI_POINTER_INDIRECT 0
#define PDI_POINTER_INDIRECT_PI 1
#define PDI_POINTER_DIRECT 2
#define PDI_RESET_KEY 0x59
#define PDI_NVMENABLE_KEY (uint8_t[]){0x12, 0x89, 0xAB, 0x45, 0xCD, 0xD8, 0x88, 0xFF}
#define FLASH_BASE 0x00800000
#define EPPROM_BASE 0x008C0000
#define FUSE_BASE 0x008F0020
#define DATAMEM_BASE 0x01000000
#define PROD_SIGNATURE_BASE 0x008E0200
#define USER_SIGNATURE_BASE 0x008E0400
#define DATAMEM_NVM_BASE 0x01C0
/* Function Prototypes: */
void PDITarget_EnableTargetPDI(void);
void PDITarget_DisableTargetPDI(void);
void PDITarget_SendByte(uint8_t Byte);
uint8_t PDITarget_ReceiveByte(void);
void PDITarget_SendBreak(void);
void PDITarget_SendAddress(uint32_t Address);
bool PDITarget_WaitWhileNVMBusBusy(void);
void PDITarget_WaitWhileNVMControllerBusy(void);
#endif
......@@ -190,6 +190,7 @@ CSTANDARD = -std=gnu99
# Place -D or -U options here for C sources
CDEFS = -DF_CPU=$(F_CPU)UL -DF_CLOCK=$(F_CLOCK)UL -DBOARD=BOARD_$(BOARD) $(LUFA_OPTS)
CDEFS += -DRESET_LINE_PORT=PORTB
CDEFS += -DRESET_LINE_PIN=PINB
CDEFS += -DRESET_LINE_DDR=DDRB
CDEFS += -DRESET_LINE_MASK="(1 << 4)"
CDEFS += -DVTARGET_ADC_CHANNEL=2
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment