Change over AVRISP project to have both hardware USART and software USART modes for the PDI protocol, when enabled. Fix up PDI initialisation routines.

Dean Camera 16 years ago
parent 7aecda6fda
commit 42cfd15793

@ -109,7 +109,7 @@
* <b><sup>2</sup></b> <i>See \ref SSec_Options section</i>
*
*
* Connections to the device for PDI programming (when enabled):
* Connections to the device for PDI programming<b><sup>1</sup></b> (when enabled):
*
* <table>
* <tr>
@ -149,6 +149,9 @@
* </tr>
* </table>
*
* <b><sup>1</sup></b> When PDI_VIA_HARDWARE_USART is set, the AVR's Tx and Rx become the DATA line when connected together
* via a pair of 300 ohm resistors, and the AVR's XCK pin becomes CLOCK.
*
* \section SSec_Options Project Options
*
* The following defines can be found in this demo, which can control the demo behaviour when defined, or changed in value.
@ -192,5 +195,11 @@
* <td>Makefile CDEFS</td>
* <td>Define to enable XMEGA PDI programming protocol support. <i>Ignored when compiled for the XPLAIN board.</i></td>
* </tr>
* <tr>
* <td>PDI_VIA_HARDWARE_USART</td>
* <td>Makefile CDEFS</td>
* <td>Define to force the PDI protocol (when enabled) to use the hardware USART instead of bit-banging to match the official
* AVRISP pinout. <i>Automatically set when compiled for the XPLAIN board.</i></td>
* </tr>
* </table>
*/

@ -104,18 +104,13 @@ static void PDIProtocol_EnterXPROGMode(void)
Endpoint_ClearOUT();
Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
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;
asm volatile ("NOP"::);
asm volatile ("NOP"::);
/* 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++)
TOGGLE_PDI_CLOCK;
/* Enable PDI programming mode with the attached target */
PDITarget_EnableTargetPDI();
/* Store the RESET ket into the RESET PDI register to complete the handshake */
PDITarget_SendByte(PDI_CMD_STCS | PD_RESET_REG);
PDITarget_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);
for (uint8_t i = 0; i < sizeof(PDI_NVMENABLE_KEY); i++)
@ -140,14 +135,8 @@ 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;
PDITarget_DisableTargetPDI();
Endpoint_Write_Byte(CMD_XPROG);
Endpoint_Write_Byte(XPRG_CMD_LEAVE_PROGMODE);
Endpoint_Write_Byte(XPRG_ERR_OK);

@ -38,90 +38,191 @@
#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[in] Byte Byte to send to the attached device
*/
void PDITarget_SendByte(uint8_t Byte)
{
uint8_t LogicOneBits = 0;
#if !defined(PDI_VIA_HARDWARE_USART)
volatile bool IsSending;
volatile uint16_t DataBits;
volatile uint8_t BitCount;
// One Start Bit
PDIDATA_LINE_PORT &= ~PDIDATA_LINE_MASK;
ISR(TIMER0_COMPA_vect, ISR_BLOCK)
{
BITBANG_PDICLOCK_PORT ^= BITBANG_PDICLOCK_MASK;
TOGGLE_PDI_CLOCK;
/* If not sending or receiving, just exit */
if (!(BitCount))
return;
// Eight Data Bits
for (uint8_t i = 0; i < 8; i++)
/* 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 (Byte & 0x01)
{
PDIDATA_LINE_PORT &= ~PDIDATA_LINE_MASK;
LogicOneBits++;
}
if (DataBits & 0x01)
BITBANG_PDIDATA_PORT &= ~BITBANG_PDIDATA_MASK;
else
{
PDIDATA_LINE_PORT |= PDIDATA_LINE_MASK;
}
Byte >>= 1;
BITBANG_PDIDATA_PORT |= BITBANG_PDIDATA_MASK;
TOGGLE_PDI_CLOCK;
DataBits >>= 1;
BitCount--;
}
else if (!IsSending && IsRisingEdge)
{
/* Wait for the start bit when receiving */
if ((BitCount == BITS_IN_FRAME) && (BITBANG_PDIDATA_PORT & BITBANG_PDIDATA_MASK))
return;
if (BITBANG_PDIDATA_PORT & BITBANG_PDIDATA_MASK)
DataBits |= (1 << (BITS_IN_FRAME - 1));
// Even Parity Bit
if (LogicOneBits & 0x01)
PDIDATA_LINE_PORT &= ~PDIDATA_LINE_MASK;
else
PDIDATA_LINE_PORT |= PDIDATA_LINE_MASK;
TOGGLE_PDI_CLOCK;
DataBits >>= 1;
BitCount--;
}
}
// Two Stop Bits
PDIDATA_LINE_PORT |= PDIDATA_LINE_MASK;
void PDITarget_EnableTargetPDI(void)
{
/* Set DATA and CLOCK lines to outputs */
BITBANG_PDIDATA_DDR |= BITBANG_PDIDATA_MASK;
BITBANG_PDICLOCK_DDR |= BITBANG_PDICLOCK_MASK;
TOGGLE_PDI_CLOCK;
TOGGLE_PDI_CLOCK;
/* 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);
}
/** 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)
void PDITarget_DisableTargetPDI(void)
{
uint8_t ReceivedByte = 0;
PDIDATA_LINE_DDR &= ~PDIDATA_LINE_MASK;
/* 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;
// One Start Bit
while (PDIDATA_LINE_PIN & PDIDATA_LINE_MASK);
TOGGLE_PDI_CLOCK;
TCCR0B = 0;
}
TOGGLE_PDI_CLOCK;
void PDITarget_SendByte(uint8_t Byte)
{
bool IsOddBitsSet = false;
// Eight Data Bits
/* Compute Even parity bit */
for (uint8_t i = 0; i < 8; i++)
{
if (!(PDIDATA_LINE_PIN & PDIDATA_LINE_MASK))
ReceivedByte |= 0x80;
if (Byte & (1 << i))
IsOddBitsSet = !(IsOddBitsSet);
}
ReceivedByte >>= 1;
/* Data shifted out LSB first, START DATA PARITY STOP STOP */
DataBits = ((uint16_t)IsOddBitsSet << 10) | ((uint16_t)Byte << 1) | (1 << 0);
TOGGLE_PDI_CLOCK;
}
BITBANG_PDIDATA_PORT |= BITBANG_PDIDATA_MASK;
BITBANG_PDIDATA_DDR |= BITBANG_PDIDATA_MASK;
// Even Parity Bit (discarded)
TOGGLE_PDI_CLOCK;
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);
}
// Two Stop Bits
TOGGLE_PDI_CLOCK;
TOGGLE_PDI_CLOCK;
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)
{
/* Set Tx and XCK as outputs, Rx as input */
DDRD |= (1 << 5) | (1 << 3);
DDRD &= ~(1 << 2);
PDIDATA_LINE_DDR |= PDIDATA_LINE_MASK;
/* Set DATA line high for 90ns to disable /RESET functionality */
PORTD |= (1 << 3);
asm volatile ("NOP"::);
asm volatile ("NOP"::);
return ReceivedByte;
/* Set up the synchronous USART for XMEGA communications -
8 data bits, even parity, 2 stop bits */
UBRR1 = 10;
UCSR1B = (1 << TXEN1);
UCSR1C = (1 << UMSEL10) | (1 << UPM11) | (1 << USBS1) | (1 << UCSZ11) | (1 << UCSZ10) | (1 << UCPOL1);
PDITarget_SendBreak();
PDITarget_SendBreak();
}
void PDITarget_DisableTargetPDI(void)
{
/* Turn of receiver and transmitter of the USART, clear settings */
UCSR1B = 0;
UCSR1C = 0;
/* Set all USART lines as input, tristate */
DDRD &= ~(1 << 5) | (1 << 3);
PORTD &= ~((1 << 5) | (1 << 3) | (1 << 2));
}
void PDITarget_SendByte(uint8_t Byte)
{
UCSR1B &= ~(1 << RXEN1);
UCSR1B |= (1 << TXEN1);
UDR1 = Byte;
while (!(UCSR1A & (1 << TXC1)));
UCSR1A |= (1 << TXC1);
}
uint8_t PDITarget_ReceiveByte(void)
{
UCSR1B &= ~(1 << TXEN1);
UCSR1B |= (1 << RXEN1);
while (!(UCSR1A & (1 << RXC1)));
UCSR1A |= (1 << RXC1);
return UDR1;
}
void PDITarget_SendBreak(void)
{
UCSR1B &= ~(1 << RXEN1);
UCSR1B |= (1 << TXEN1);
for (uint8_t i = 0; i < BITS_IN_FRAME; i++)
{
while (PIND & (1 << 5));
while (!(PIND & (1 << 5)));
}
}
#endif
#endif

@ -38,6 +38,7 @@
/* Includes: */
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdbool.h>
#include <LUFA/Common/Common.h>
@ -53,25 +54,20 @@
/* Defines: */
#if BOARD == BOARD_XPLAIN
#define PDIDATA_LINE_PORT PORTD
#define PDIDATA_LINE_DDR DDRD
#define PDIDATA_LINE_PIN PIND
#define PDIDATA_LINE_MASK (1 << 2)
#define PDICLOCK_LINE_PORT PORTD
#define PDICLOCK_LINE_DDR DDRD
#define PDICLOCK_LINE_MASK (1 << 5)
#define PDI_VIA_HARDWARE_USART
#else
#define PDIDATA_LINE_PORT PORTB
#define PDIDATA_LINE_DDR DDRB
#define PDIDATA_LINE_PIN PINB
#define PDIDATA_LINE_MASK (1 << 3)
#define BITBANG_PDIDATA_PORT PORTB
#define BITBANG_PDIDATA_DDR DDRB
#define BITBANG_PDIDATA_PIN PINB
#define BITBANG_PDIDATA_MASK (1 << 3)
#define PDICLOCK_LINE_PORT RESET_LINE_PORT
#define PDICLOCK_LINE_DDR RESET_LINE_DDR
#define PDICLOCK_LINE_MASK RESET_LINE_MASK
#define BITBANG_PDICLOCK_PORT RESET_LINE_PORT
#define BITBANG_PDICLOCK_DDR RESET_LINE_DDR
#define BITBANG_PDICLOCK_MASK RESET_LINE_MASK
#endif
#define BITS_IN_FRAME 12
#define PDI_CMD_LDS 0x00
#define PDI_CMD_LD 0x20
#define PDI_CMD_STS 0x40
@ -89,14 +85,12 @@
#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; \
asm volatile ("NOP" ::); \
PDICLOCK_LINE_PORT ^= PDICLOCK_LINE_MASK; \
asm volatile ("NOP" ::); }MACROE
/* 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);
#endif

@ -60,7 +60,7 @@
# MCU name
MCU = at90usb162
MCU = at90usb1287
# Target board (see library "Board Types" documentation, USER or blank for projects not requiring

Loading…
Cancel
Save