diff --git a/LUFA.pnproj b/LUFA.pnproj index ad42f6b394..99458124d1 100644 --- a/LUFA.pnproj +++ b/LUFA.pnproj @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/LUFA/ManPages/ChangeLog.txt b/LUFA/ManPages/ChangeLog.txt index 0daed31877..99cb773af9 100644 --- a/LUFA/ManPages/ChangeLog.txt +++ b/LUFA/ManPages/ChangeLog.txt @@ -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 diff --git a/Projects/AVRISP/AVRISP.txt b/Projects/AVRISP/AVRISP.txt index 9dd2f119fe..6eeef385c8 100644 --- a/Projects/AVRISP/AVRISP.txt +++ b/Projects/AVRISP/AVRISP.txt @@ -168,6 +168,11 @@ * PORT register for the programmer's target RESET line. Ignored when compiled for the XPLAIN board. * * + * RESET_LINE_PIN + * Makefile CDEFS + * PIN register for the programmer's target RESET line. Ignored when compiled for the XPLAIN board. + * + * * RESET_LINE_DDR * Makefile CDEFS * DDR register for the programmer's target RESET line. Ignored when compiled for the XPLAIN board. diff --git a/Projects/AVRISP/Lib/PDIProtocol.c b/Projects/AVRISP/Lib/PDIProtocol.c index 2107e2b892..7769343118 100644 --- a/Projects/AVRISP/Lib/PDIProtocol.c +++ b/Projects/AVRISP/Lib/PDIProtocol.c @@ -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(); diff --git a/Projects/AVRISP/Lib/PDITarget.c b/Projects/AVRISP/Lib/PDITarget.c index eb16e0a28c..b56fe60b61 100644 --- a/Projects/AVRISP/Lib/PDITarget.c +++ b/Projects/AVRISP/Lib/PDITarget.c @@ -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 diff --git a/Projects/AVRISP/Lib/PDITarget.h b/Projects/AVRISP/Lib/PDITarget.h index 2726555945..85f627a6a1 100644 --- a/Projects/AVRISP/Lib/PDITarget.h +++ b/Projects/AVRISP/Lib/PDITarget.h @@ -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 diff --git a/Projects/AVRISP/makefile b/Projects/AVRISP/makefile index 003eaa57aa..e8fabc5adb 100644 --- a/Projects/AVRISP/makefile +++ b/Projects/AVRISP/makefile @@ -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