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

pull/1469/head
Dean Camera 15 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