Start of implementation of the low level TPI programming protocol in the AVRISP project.

This commit is contained in:
Dean Camera 2009-12-23 12:54:15 +00:00
commit cda88cf97c
16 changed files with 494 additions and 16 deletions

File diff suppressed because one or more lines are too long

View file

@ -9,6 +9,15 @@
* \section Sec_ChangeLogXXXXXX Version XXXXXX
*
* <b>New:</b>
* - Added TPI programming support for 6-pin ATTINY to the AVRISP programmer project
*
* <b>Changed:</b>
*
* <b>Fixed:</b>
*
* \section Sec_ChangeLog091223 Version 091223
*
* <b>New:</b>
* - Added activity LED indicators to the AVRISP project to indicate when the device is busy processing a command
* - The USB target family and allowable USB mode tokens are now public and documented (USB_CAN_BE_*, USB_SERIES_*_AVR)
* - Added new XPLAIN USB to Serial Bridge project (thanks to John Steggall for initial proof-of-concept, David Prentice

View file

@ -34,7 +34,7 @@
* - Arcade Controller: http://fletchtronics.net/arcade-controller-made-petunia
* - Bicycle POV: http://www.code.google.com/p/bicycleledpov/
* - CAMTRIG, a remote Camera Trigger device: http://code.astraw.com/projects/motmot/camtrig
* - "Fingerlicking Wingdinger" (WARNING: Bad Language if no Javascript), a MIDI controller - http://noisybox.net/electronics/wingdinger/
* - "Fingerlicking Wingdinger" (WARNING: Bad Language if no Javascript), a MIDI controller: http://noisybox.net/electronics/wingdinger/
* - Garmin GPS USB to NMEA standard serial sentence translator: http://github.com/nall/garmin-transmogrifier/tree/master
* - Generic HID Device Creator : http://generichid.sourceforge.net/
* - Mobo 4.3, some sort of Audio related device: http://sites.google.com/site/lofturj/mobo4_3

View file

@ -10,7 +10,11 @@
* to the next version released. It does not indicate all new additions to the library in each version change, only
* areas relevant to making older projects compatible with the API changes of each new release.
*
* \section Sec_MigrationXXXXXX Migrating from 091122 to XXXXXX
* \section Sec_MigrationXXXXXX Migrating from 091223 to XXXXXX
*
* <i>There is no migration information for this release.</i>
*
* \section Sec_Migration091223 Migrating from 091122 to 091223
*
* <b>Host Mode</b>
* - The Still Image Host Class driver SI_Host_USBTask() and SI_Host_ConfigurePipes() functions were misnamed, and are

View file

@ -62,10 +62,10 @@
* without an ADC converter, VTARGET will report at a fixed 5V level.
*
* When compiled for the XPLAIN board target, this will automatically configure itself for the correct connections to the
* XPLAIN's XMEGA AVR, and will enable PDI only programming support (since ISP mode is not needed).
* XPLAIN's XMEGA AVR, and will enable PDI only programming support (since ISP and TPI modes are not needed).
*
* While this application can be compiled for USB AVRs with as little as 8KB of FLASH, for full functionality 16KB or more
* of FLASH is required. On 8KB devices, either ISP or PDI programming support can be disabled to reduce program size.
* of FLASH is required. On 8KB devices, ISP, PDI or TPI programming support can be disabled to reduce program size.
*
* \section Sec_ISP ISP Connections
* Connections to the device for SPI programming (when enabled):
@ -155,6 +155,50 @@
* <b><sup>1</sup></b> <i>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.</i>
*
* \section Sec_TPI TPI Connections
* Connections to the device for TPI programming<b><sup>1</sup></b> (when enabled):
*
* <table>
* <tr>
* <td><b>Programmer Pin:</b></td>
* <td><b>Target Device Pin:</b></td>
* <td><b>PDI 6 Pin Layout:</b></td>
* </tr>
* <tr>
* <td>MISO</td>
* <td>DATA</td>
* <td>1</td>
* </tr>
* <tr>
* <td>ADCx <b><sup>1</sup></b></td>
* <td>VTARGET</td>
* <td>2</td>
* </tr>
* <tr>
* <td>SCLK</td>
* <td>CLOCK</td>
* <td>3</td>
* </tr>
* <tr>
* <td>N/A</td>
* <td>N/A</td>
* <td>4</td>
* </tr>
* <tr>
* <td>PORTx.y <b><sup>2</sup></b></td>
* <td>/RESET</td>
* <td>5</td>
* </tr>
* <tr>
* <td>GND</td>
* <td>GND</td>
* <td>6</td>
* </tr>
* </table>
*
* <b><sup>1</sup></b> <i>When TPI_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.</i>
*
* \section SSec_Options Project Options
*
* The following defines can be found in this project, which can control the project behaviour when defined, or changed in value.
@ -204,6 +248,11 @@
* <td>Define to enable XMEGA PDI programming protocol support. <i>Ignored when compiled for the XPLAIN board.</i></td>
* </tr>
* <tr>
* <td>ENABLE_TPI_PROTOCOL</td>
* <td>Makefile CDEFS</td>
* <td>Define to enable 6-PIN ATTINY TPI 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 much faster hardware USART instead of bit-banging to
@ -211,5 +260,13 @@
* seperate ISP and PDI programming headers) but increases programming speed dramatically.
* <i>Ignored when compiled for the XPLAIN board.</i></td>
* </tr>
* <tr>
* <td>TPI_VIA_HARDWARE_USART</td>
* <td>Makefile CDEFS</td>
* <td>Define to force the TPI protocol (when enabled) to use the much faster hardware USART instead of bit-banging to
* match the official AVRISP pinout. This breaks pinout compatibility with the official AVRISP MKII (and requires
* seperate ISP and TPI programming headers) but increases programming speed dramatically.
* <i>Ignored when compiled for the XPLAIN board.</i></td>
* </tr>
* </table>
*/

View file

@ -44,6 +44,7 @@
/* Preprocessor Checks: */
#if ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1))
#undef ENABLE_ISP_PROTOCOL
#undef ENABLE_TPI_PROTOCOL
#if !defined(ENABLE_PDI_PROTOCOL)
#define ENABLE_PDI_PROTOCOL

View file

@ -50,6 +50,7 @@
/* Preprocessor Checks: */
#if ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1))
#undef ENABLE_ISP_PROTOCOL
#undef ENABLE_TPI_PROTOCOL
#if !defined(ENABLE_PDI_PROTOCOL)
#define ENABLE_PDI_PROTOCOL

View file

@ -43,11 +43,12 @@
#include "V2Protocol.h"
#include "PDITarget.h"
#include "NVMTarget.h"
#include "XMEGANVM.h"
/* Preprocessor Checks: */
#if ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1))
#undef ENABLE_ISP_PROTOCOL
#undef ENABLE_TPI_PROTOCOL
#if !defined(ENABLE_PDI_PROTOCOL)
#define ENABLE_PDI_PROTOCOL

View file

@ -67,13 +67,13 @@ ISR(TIMER1_COMPA_vect, ISR_BLOCK)
return;
/* Wait for the start bit when receiving */
if ((SoftUSART_BitCount == BITS_IN_FRAME) && (BITBANG_PDIDATA_PIN & BITBANG_PDIDATA_MASK))
if ((SoftUSART_BitCount == BITS_IN_PDI_FRAME) && (BITBANG_PDIDATA_PIN & BITBANG_PDIDATA_MASK))
return;
/* Shift in the bit one less than the frame size in position, so that the start bit will eventually
* be discarded leaving the data to be byte-aligned for quick access */
if (BITBANG_PDIDATA_PIN & BITBANG_PDIDATA_MASK)
SoftUSART_Data |= (1 << (BITS_IN_FRAME - 1));
SoftUSART_Data |= (1 << (BITS_IN_PDI_FRAME - 1));
SoftUSART_Data >>= 1;
SoftUSART_BitCount--;
@ -133,6 +133,7 @@ void PDITarget_EnableTargetPDI(void)
TCCR1B = (1 << WGM12) | (1 << CS10);
TIMSK1 = (1 << OCIE1A);
/* Send two BREAKs of 12 bits each to enable TPI interface (need at least 16 idle bits) */
PDITarget_SendBreak();
PDITarget_SendBreak();
#endif
@ -158,8 +159,6 @@ void PDITarget_DisableTargetPDI(void)
/* Tristate DATA and CLOCK lines */
BITBANG_PDIDATA_PORT &= ~BITBANG_PDIDATA_MASK;
BITBANG_PDICLOCK_PORT &= ~BITBANG_PDICLOCK_MASK;
TCCR0B = 0;
#endif
}
@ -212,7 +211,7 @@ void PDITarget_SendByte(const uint8_t Byte)
/* Data shifted out LSB first, START DATA PARITY STOP STOP */
SoftUSART_Data = NewUSARTData;
SoftUSART_BitCount = BITS_IN_FRAME;
SoftUSART_BitCount = BITS_IN_PDI_FRAME;
#endif
}
@ -254,7 +253,7 @@ uint8_t PDITarget_ReceiveByte(void)
}
/* Wait until a byte has been received before reading */
SoftUSART_BitCount = BITS_IN_FRAME;
SoftUSART_BitCount = BITS_IN_PDI_FRAME;
while (SoftUSART_BitCount);
/* Throw away the parity and stop bits to leave only the data (start bit is already discarded) */
@ -279,7 +278,7 @@ 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++)
for (uint8_t i = 0; i < BITS_IN_PDI_FRAME; i++)
{
/* Wait for a full cycle of the clock */
while (PIND & (1 << 5));
@ -299,7 +298,7 @@ void PDITarget_SendBreak(void)
/* Need to do nothing for a full frame to send a BREAK */
SoftUSART_Data = 0x0FFF;
SoftUSART_BitCount = BITS_IN_FRAME;
SoftUSART_BitCount = BITS_IN_PDI_FRAME;
#endif
}

View file

@ -46,6 +46,7 @@
/* Preprocessor Checks: */
#if ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1))
#undef ENABLE_ISP_PROTOCOL
#undef ENABLE_TPI_PROTOCOL
#if !defined(ENABLE_PDI_PROTOCOL)
#define ENABLE_PDI_PROTOCOL
@ -67,7 +68,7 @@
#define BITBANG_PDICLOCK_MASK RESET_LINE_MASK
#endif
#define BITS_IN_FRAME 12
#define BITS_IN_PDI_FRAME 12
#define PDI_NVM_TIMEOUT_MS 200

View file

@ -0,0 +1,320 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* Target-related functions for the TPI Protocol decoder.
*/
#define INCLUDE_FROM_TPITARGET_C
#include "TPITarget.h"
#if defined(ENABLE_TPI_PROTOCOL) || defined(__DOXYGEN__)
/** Flag to indicate if the USART is currently in Tx or Rx mode. */
volatile bool IsSending;
#if !defined(TPI_VIA_HARDWARE_USART)
/** Software USART raw frame bits for transmission/reception. */
volatile uint16_t SoftUSART_Data;
/** Bits remaining to be sent or received via the software USART - set as a GPIOR for speed. */
#define SoftUSART_BitCount GPIOR2
/** ISR to manage the software USART when bit-banged USART mode is selected. */
ISR(TIMER1_CAPT_vect, ISR_BLOCK)
{
/* Toggle CLOCK pin in a single cycle (see AVR datasheet) */
BITBANG_TPICLOCK_PIN |= BITBANG_TPICLOCK_MASK;
/* If not sending or receiving, just exit */
if (!(SoftUSART_BitCount))
return;
/* Check to see if we are at a rising or falling edge of the clock */
if (BITBANG_TPICLOCK_PORT & BITBANG_TPICLOCK_MASK)
{
/* If at rising clock edge and we are in send mode, abort */
if (IsSending)
return;
/* Wait for the start bit when receiving */
if ((SoftUSART_BitCount == BITS_IN_TPI_FRAME) && (BITBANG_TPIDATA_PIN & BITBANG_TPIDATA_MASK))
return;
/* Shift in the bit one less than the frame size in position, so that the start bit will eventually
* be discarded leaving the data to be byte-aligned for quick access */
if (BITBANG_TPIDATA_PIN & BITBANG_TPIDATA_MASK)
SoftUSART_Data |= (1 << (BITS_IN_TPI_FRAME - 1));
SoftUSART_Data >>= 1;
SoftUSART_BitCount--;
}
else
{
/* If at falling clock edge and we are in receive mode, abort */
if (!IsSending)
return;
/* Set the data line to the next bit value */
if (SoftUSART_Data & 0x01)
BITBANG_TPIDATA_PORT |= BITBANG_TPIDATA_MASK;
else
BITBANG_TPIDATA_PORT &= ~BITBANG_TPIDATA_MASK;
SoftUSART_Data >>= 1;
SoftUSART_BitCount--;
}
}
#endif
/** Enables the target's TPI interface, holding the target in reset until TPI mode is exited. */
void TPITarget_EnableTargetTPI(void)
{
/* Set /RESET line low for at least 90ns to enable TPI functionality */
RESET_LINE_DDR |= RESET_LINE_MASK;
RESET_LINE_PORT &= ~RESET_LINE_MASK;
asm volatile ("NOP"::);
asm volatile ("NOP"::);
#if defined(TPI_VIA_HARDWARE_USART)
/* Set Tx and XCK as outputs, Rx as input */
DDRD |= (1 << 5) | (1 << 3);
DDRD &= ~(1 << 2);
/* Set up the synchronous USART for XMEGA communications -
8 data bits, even parity, 2 stop bits */
UBRR1 = (F_CPU / 1000000UL);
UCSR1B = (1 << TXEN1);
UCSR1C = (1 << UMSEL10) | (1 << UPM11) | (1 << USBS1) | (1 << UCSZ11) | (1 << UCSZ10) | (1 << UCPOL1);
/* Send two BREAKs of 12 bits each to enable TPI interface (need at least 16 idle bits) */
TPITarget_SendBreak();
TPITarget_SendBreak();
#else
/* Set DATA and CLOCK lines to outputs */
BITBANG_TPIDATA_DDR |= BITBANG_TPIDATA_MASK;
BITBANG_TPICLOCK_DDR |= BITBANG_TPICLOCK_MASK;
/* Set DATA line high for idle state */
BITBANG_TPIDATA_PORT |= BITBANG_TPIDATA_MASK;
/* Fire timer capture ISR every 100 cycles to manage the software USART */
OCR1A = 80;
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS10);
TIMSK1 = (1 << ICIE1);
/* Send two BREAKs of 12 bits each to enable TPI interface (need at least 16 idle bits) */
TPITarget_SendBreak();
TPITarget_SendBreak();
#endif
}
/** Disables the target's TPI interface, exits programming mode and starts the target's application. */
void TPITarget_DisableTargetTPI(void)
{
#if defined(TPI_VIA_HARDWARE_USART)
/* Turn off receiver and transmitter of the USART, clear settings */
UCSR1A |= (1 << TXC1) | (1 << RXC1);
UCSR1B = 0;
UCSR1C = 0;
/* 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_TPIDATA_DDR &= ~BITBANG_TPIDATA_MASK;
BITBANG_TPICLOCK_DDR &= ~BITBANG_TPICLOCK_MASK;
/* Tristate DATA and CLOCK lines */
BITBANG_TPIDATA_PORT &= ~BITBANG_TPIDATA_MASK;
BITBANG_TPICLOCK_PORT &= ~BITBANG_TPICLOCK_MASK;
#endif
/* Tristate target /RESET line */
RESET_LINE_DDR &= ~RESET_LINE_MASK;
RESET_LINE_PORT &= ~RESET_LINE_MASK;
}
/** Sends a byte via the USART.
*
* \param[in] Byte Byte to send through the USART
*/
void TPITarget_SendByte(const uint8_t Byte)
{
#if defined(TPI_VIA_HARDWARE_USART)
/* Switch to Tx mode if currently in Rx mode */
if (!(IsSending))
{
PORTD |= (1 << 3);
DDRD |= (1 << 3);
UCSR1B |= (1 << TXEN1);
UCSR1B &= ~(1 << RXEN1);
IsSending = true;
}
/* Wait until there is space in the hardware Tx buffer before writing */
while (!(UCSR1A & (1 << UDRE1)));
UCSR1A |= (1 << TXC1);
UDR1 = Byte;
#else
/* Switch to Tx mode if currently in Rx mode */
if (!(IsSending))
{
BITBANG_TPIDATA_PORT |= BITBANG_TPIDATA_MASK;
BITBANG_TPIDATA_DDR |= BITBANG_TPIDATA_MASK;
IsSending = true;
}
/* Calculate the new USART frame data here while while we wait for a previous byte (if any) to finish sending */
uint16_t NewUSARTData = ((1 << 11) | (1 << 10) | (0 << 9) | ((uint16_t)Byte << 1) | (0 << 0));
/* Compute Even parity - while a bit is still set, chop off lowest bit and toggle parity bit */
uint8_t ParityData = Byte;
while (ParityData)
{
NewUSARTData ^= (1 << 9);
ParityData &= (ParityData - 1);
}
/* Wait until transmitter is idle before writing new data */
while (SoftUSART_BitCount);
/* Data shifted out LSB first, START DATA PARITY STOP STOP */
SoftUSART_Data = NewUSARTData;
SoftUSART_BitCount = BITS_IN_TPI_FRAME;
#endif
}
/** Receives a byte via the software USART, blocking until data is received.
*
* \return Received byte from the USART
*/
uint8_t TPITarget_ReceiveByte(void)
{
#if defined(TPI_VIA_HARDWARE_USART)
/* Switch to Rx mode if currently in Tx mode */
if (IsSending)
{
while (!(UCSR1A & (1 << TXC1)));
UCSR1A |= (1 << TXC1);
UCSR1B &= ~(1 << TXEN1);
UCSR1B |= (1 << RXEN1);
DDRD &= ~(1 << 3);
PORTD &= ~(1 << 3);
IsSending = false;
}
/* 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_TPIDATA_DDR &= ~BITBANG_TPIDATA_MASK;
BITBANG_TPIDATA_PORT &= ~BITBANG_TPIDATA_MASK;
IsSending = false;
}
/* Wait until a byte has been received before reading */
SoftUSART_BitCount = BITS_IN_TPI_FRAME;
while (SoftUSART_BitCount);
/* Throw away the parity and stop bits to leave only the data (start bit is already discarded) */
return (uint8_t)SoftUSART_Data;
#endif
}
/** Sends a BREAK via the USART to the attached target, consisting of a full frame of idle bits. */
void TPITarget_SendBreak(void)
{
#if defined(TPI_VIA_HARDWARE_USART)
/* Switch to Tx mode if currently in Rx mode */
if (!(IsSending))
{
PORTD |= (1 << 3);
DDRD |= (1 << 3);
UCSR1B &= ~(1 << RXEN1);
UCSR1B |= (1 << TXEN1);
IsSending = true;
}
/* Need to do nothing for a full frame to send a BREAK */
for (uint8_t i = 0; i < BITS_IN_TPI_FRAME; i++)
{
/* Wait for a full cycle of the clock */
while (PIND & (1 << 5));
while (!(PIND & (1 << 5)));
}
#else
/* Switch to Tx mode if currently in Rx mode */
if (!(IsSending))
{
BITBANG_TPIDATA_PORT |= BITBANG_TPIDATA_MASK;
BITBANG_TPIDATA_DDR |= BITBANG_TPIDATA_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_TPI_FRAME;
#endif
}
/** Busy-waits while the NVM controller is busy performing a NVM operation, such as a FLASH page read or CRC
* calculation.
*
* \return Boolean true if the NVM controller became ready within the timeout period, false otherwise
*/
bool TPITarget_WaitWhileNVMBusBusy(void)
{
// TODO
return false;
}
#endif

View file

@ -0,0 +1,81 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* Header file for TPITarget.c.
*/
#ifndef _TPI_TARGET_
#define _TPI_TARGET_
/* Includes: */
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdbool.h>
#include <LUFA/Common/Common.h>
/* Preprocessor Checks: */
#if ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1))
#undef ENABLE_ISP_PROTOCOL
#undef ENABLE_TPI_PROTOCOL
#if !defined(ENABLE_PDI_PROTOCOL)
#define ENABLE_PDI_PROTOCOL
#endif
#endif
/* Defines: */
#define BITBANG_TPIDATA_PORT PORTB
#define BITBANG_TPIDATA_DDR DDRB
#define BITBANG_TPIDATA_PIN PINB
#define BITBANG_TPIDATA_MASK (1 << 3)
#define BITBANG_TPICLOCK_PORT PORTB
#define BITBANG_TPICLOCK_DDR DDRB
#define BITBANG_TPICLOCK_PIN PINB
#define BITBANG_TPICLOCK_MASK (1 << 1)
#define BITS_IN_TPI_FRAME 12
#define TPI_NVM_TIMEOUT_MS 200
#define TPI_NVMENABLE_KEY (uint8_t[]){0x12, 0x89, 0xAB, 0x45, 0xCD, 0xD8, 0x88, 0xFF}
/* Function Prototypes: */
void TPITarget_EnableTargetTPI(void);
void TPITarget_DisableTargetTPI(void);
void TPITarget_SendByte(const uint8_t Byte);
uint8_t TPITarget_ReceiveByte(void);
void TPITarget_SendBreak(void);
bool TPITarget_WaitWhileNVMBusBusy(void);
#endif

View file

@ -49,6 +49,7 @@
/* Preprocessor Checks: */
#if ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1))
#undef ENABLE_ISP_PROTOCOL
#undef ENABLE_TPI_PROTOCOL
#if !defined(ENABLE_PDI_PROTOCOL)
#define ENABLE_PDI_PROTOCOL

View file

@ -0,0 +1,332 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* Target-related functions for the target's NVM module.
*/
#define INCLUDE_FROM_NVMTARGET_C
#include "NVMTarget.h"
#if defined(ENABLE_PDI_PROTOCOL) || defined(__DOXYGEN__)
/** Sends the given NVM register address to the target.
*
* \param[in] Register NVM register whose absolute address is to be sent
*/
void NVMTarget_SendNVMRegAddress(const uint8_t Register)
{
/* Determine the absolute register address from the NVM base memory address and the NVM register address */
uint32_t Address = XPROG_Param_NVMBase | Register;
/* Send the calculated 32-bit address to the target, LSB first */
NVMTarget_SendAddress(Address);
}
/** Sends the given 32-bit absolute address to the target.
*
* \param[in] AbsoluteAddress Absolute address to send to the target
*/
void NVMTarget_SendAddress(const uint32_t AbsoluteAddress)
{
/* Send the given 32-bit address to the target, LSB first */
PDITarget_SendByte(AbsoluteAddress & 0xFF);
PDITarget_SendByte(AbsoluteAddress >> 8);
PDITarget_SendByte(AbsoluteAddress >> 16);
PDITarget_SendByte(AbsoluteAddress >> 24);
}
/** Waits while the target's NVM controller is busy performing an operation, exiting if the
* timeout period expires.
*
* \return Boolean true if the NVM controller became ready within the timeout period, false otherwise
*/
bool NVMTarget_WaitWhileNVMControllerBusy(void)
{
TCNT0 = 0;
TIFR0 = (1 << OCF1A);
uint8_t TimeoutMS = PDI_NVM_TIMEOUT_MS;
/* Poll the NVM STATUS register while the NVM controller is busy */
while (TimeoutMS)
{
/* Send a LDS command to read the NVM STATUS register to check the BUSY flag */
PDITarget_SendByte(PDI_CMD_LDS | (PDI_DATSIZE_4BYTES << 2));
NVMTarget_SendNVMRegAddress(NVM_REG_STATUS);
/* Check to see if the BUSY flag is still set */
if (!(PDITarget_ReceiveByte() & (1 << 7)))
return true;
if (TIFR0 & (1 << OCF1A))
{
TIFR0 = (1 << OCF1A);
TimeoutMS--;
}
}
return false;
}
/** Retrieves the CRC value of the given memory space.
*
* \param[in] CRCCommand NVM CRC command to issue to the target
* \param[out] CRCDest CRC Destination when read from the target
*
* \return Boolean true if the command sequence complete successfully
*/
bool NVMTarget_GetMemoryCRC(const uint8_t CRCCommand, uint32_t* const CRCDest)
{
/* Wait until the NVM controller is no longer busy */
if (!(NVMTarget_WaitWhileNVMControllerBusy()))
return false;
/* Set the NVM command to the correct CRC read command */
PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
NVMTarget_SendNVMRegAddress(NVM_REG_CMD);
PDITarget_SendByte(CRCCommand);
/* Set CMDEX bit in NVM CTRLA register to start the CRC generation */
PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
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;
*CRCDest = 0;
/* Read the first generated CRC byte value */
PDITarget_SendByte(PDI_CMD_LDS | (PDI_DATSIZE_4BYTES << 2));
NVMTarget_SendNVMRegAddress(NVM_REG_DAT0);
*CRCDest = PDITarget_ReceiveByte();
/* Read the second generated CRC byte value */
PDITarget_SendByte(PDI_CMD_LDS | (PDI_DATSIZE_4BYTES << 2));
NVMTarget_SendNVMRegAddress(NVM_REG_DAT1);
*CRCDest |= ((uint16_t)PDITarget_ReceiveByte() << 8);
/* Read the third generated CRC byte value */
PDITarget_SendByte(PDI_CMD_LDS | (PDI_DATSIZE_4BYTES << 2));
NVMTarget_SendNVMRegAddress(NVM_REG_DAT2);
*CRCDest |= ((uint32_t)PDITarget_ReceiveByte() << 16);
return true;
}
/** Reads memory from the target's memory spaces.
*
* \param[in] ReadAddress Start address to read from within the target's address space
* \param[out] ReadBuffer Buffer to store read data into
* \param[in] ReadSize Number of bytes to read
*
* \return Boolean true if the command sequence complete successfully
*/
bool NVMTarget_ReadMemory(const uint32_t ReadAddress, uint8_t* ReadBuffer, const uint16_t ReadSize)
{
/* Wait until the NVM controller is no longer busy */
if (!(NVMTarget_WaitWhileNVMControllerBusy()))
return false;
/* Send the READNVM command to the NVM controller for reading of an arbitrary location */
PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
NVMTarget_SendNVMRegAddress(NVM_REG_CMD);
PDITarget_SendByte(NVM_CMD_READNVM);
/* Load the PDI pointer register with the start address we want to read from */
PDITarget_SendByte(PDI_CMD_ST | (PDI_POINTER_DIRECT << 2) | PDI_DATSIZE_4BYTES);
NVMTarget_SendAddress(ReadAddress);
/* Send the REPEAT command with the specified number of bytes to read */
PDITarget_SendByte(PDI_CMD_REPEAT | PDI_DATSIZE_1BYTE);
PDITarget_SendByte(ReadSize - 1);
/* Send a LD command with indirect access and postincrement to read out the bytes */
PDITarget_SendByte(PDI_CMD_LD | (PDI_POINTER_INDIRECT_PI << 2) | PDI_DATSIZE_1BYTE);
for (uint16_t i = 0; i < ReadSize; i++)
*(ReadBuffer++) = PDITarget_ReceiveByte();
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 byte
* \param[in] WriteAddress Start address to write to within the target's address space
* \param[in] WriteBuffer Buffer to source data from
*
* \return Boolean true if the command sequence complete successfully
*/
bool NVMTarget_WriteByteMemory(const uint8_t WriteCommand, const uint32_t WriteAddress, const uint8_t* WriteBuffer)
{
/* 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 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;
}
/** Writes page addressed memory to the target's memory spaces.
*
* \param[in] WriteBuffCommand Command to send to the device to write a byte to the memory page buffer
* \param[in] EraseBuffCommand Command to send to the device to erase the memory page buffer
* \param[in] WritePageCommand Command to send to the device to write the page buffer to the destination memory
* \param[in] PageMode Bitfield indicating what operations need to be executed on the specified page
* \param[in] WriteAddress Start address to write the page data 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 successfully
*/
bool NVMTarget_WritePageMemory(const uint8_t WriteBuffCommand, const uint8_t EraseBuffCommand,
const uint8_t WritePageCommand, const uint8_t PageMode, const uint32_t WriteAddress,
const uint8_t* WriteBuffer, const uint16_t WriteSize)
{
if (PageMode & XPRG_PAGEMODE_ERASE)
{
/* Wait until the NVM controller is no longer busy */
if (!(NVMTarget_WaitWhileNVMControllerBusy()))
return false;
/* Send the memory buffer erase command to the target */
PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
NVMTarget_SendNVMRegAddress(NVM_REG_CMD);
PDITarget_SendByte(EraseBuffCommand);
/* Set CMDEX bit in NVM CTRLA register to start the buffer erase */
PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
NVMTarget_SendNVMRegAddress(NVM_REG_CTRLA);
PDITarget_SendByte(1 << 0);
}
if (WriteSize)
{
/* Wait until the NVM controller is no longer busy */
if (!(NVMTarget_WaitWhileNVMControllerBusy()))
return false;
/* Send the memory buffer write command to the target */
PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
NVMTarget_SendNVMRegAddress(NVM_REG_CMD);
PDITarget_SendByte(WriteBuffCommand);
/* Load the PDI pointer register with the start address we want to write to */
PDITarget_SendByte(PDI_CMD_ST | (PDI_POINTER_DIRECT << 2) | PDI_DATSIZE_4BYTES);
NVMTarget_SendAddress(WriteAddress);
/* Send the REPEAT command with the specified number of bytes to write */
PDITarget_SendByte(PDI_CMD_REPEAT | PDI_DATSIZE_1BYTE);
PDITarget_SendByte(WriteSize - 1);
/* Send a ST command with indirect access and postincrement to write the bytes */
PDITarget_SendByte(PDI_CMD_ST | (PDI_POINTER_INDIRECT_PI << 2) | PDI_DATSIZE_1BYTE);
for (uint16_t i = 0; i < WriteSize; i++)
PDITarget_SendByte(*(WriteBuffer++));
}
if (PageMode & XPRG_PAGEMODE_WRITE)
{
/* 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(WritePageCommand);
/* Send the address of the first page location to write the memory page */
PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
NVMTarget_SendAddress(WriteAddress);
PDITarget_SendByte(0x00);
}
return true;
}
/** Erases a specific memory space of the target.
*
* \param[in] EraseCommand NVM erase command to send to the device
* \param[in] Address Address inside the memory space to erase
*
* \return Boolean true if the command sequence complete successfully
*/
bool NVMTarget_EraseMemory(const uint8_t EraseCommand, const uint32_t Address)
{
/* Wait until the NVM controller is no longer busy */
if (!(NVMTarget_WaitWhileNVMControllerBusy()))
return false;
/* Send the memory erase command to the target */
PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
NVMTarget_SendNVMRegAddress(NVM_REG_CMD);
PDITarget_SendByte(EraseCommand);
/* Chip erase is handled separately, since it's procedure is different to other erase types */
if (EraseCommand == NVM_CMD_CHIPERASE)
{
/* Set CMDEX bit in NVM CTRLA register to start the chip erase */
PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
NVMTarget_SendNVMRegAddress(NVM_REG_CTRLA);
PDITarget_SendByte(1 << 0);
}
else
{
/* Other erase modes just need us to address a byte within the target memory space */
PDITarget_SendByte(PDI_CMD_STS | (PDI_DATSIZE_4BYTES << 2));
NVMTarget_SendAddress(Address);
PDITarget_SendByte(0x00);
}
/* Wait until the NVM bus is ready again */
if (!(PDITarget_WaitWhileNVMBusBusy()))
return false;
return true;
}
#endif

View file

@ -0,0 +1,121 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2009.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* Header file for NVMTarget.c.
*/
#ifndef _NVM_TARGET_
#define _NVM_TARGET_
/* Includes: */
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdbool.h>
#include <LUFA/Common/Common.h>
#include "PDIProtocol.h"
#include "PDITarget.h"
/* Preprocessor Checks: */
#if ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1))
#undef ENABLE_ISP_PROTOCOL
#undef ENABLE_TPI_PROTOCOL
#if !defined(ENABLE_PDI_PROTOCOL)
#define ENABLE_PDI_PROTOCOL
#endif
#endif
/* Defines: */
#define NVM_BUSY_TIMEOUT_MS 200
#define NVM_REG_ADDR0 0x00
#define NVM_REG_ADDR1 0x01
#define NVM_REG_ADDR2 0x02
#define NVM_REG_DAT0 0x04
#define NVM_REG_DAT1 0x05
#define NVM_REG_DAT2 0x06
#define NVM_REG_CMD 0x0A
#define NVM_REG_CTRLA 0x0B
#define NVM_REG_CTRLB 0x0C
#define NVM_REG_INTCTRL 0x0D
#define NVM_REG_STATUS 0x0F
#define NVM_REG_LOCKBITS 0x10
#define NVM_CMD_NOOP 0x00
#define NVM_CMD_CHIPERASE 0x40
#define NVM_CMD_READNVM 0x43
#define NVM_CMD_LOADFLASHPAGEBUFF 0x23
#define NVM_CMD_ERASEFLASHPAGEBUFF 0x26
#define NVM_CMD_ERASEFLASHPAGE 0x2B
#define NVM_CMD_WRITEFLASHPAGE 0x2E
#define NVM_CMD_ERASEWRITEFLASH 0x2F
#define NVM_CMD_FLASHCRC 0x78
#define NVM_CMD_ERASEAPPSEC 0x20
#define NVM_CMD_ERASEAPPSECPAGE 0x22
#define NVM_CMD_WRITEAPPSECPAGE 0x24
#define NVM_CMD_ERASEWRITEAPPSECPAGE 0x25
#define NVM_CMD_APPCRC 0x38
#define NVM_CMD_ERASEBOOTSEC 0x68
#define NVM_CMD_ERASEBOOTSECPAGE 0x2A
#define NVM_CMD_WRITEBOOTSECPAGE 0x2C
#define NVM_CMD_ERASEWRITEBOOTSECPAGE 0x2D
#define NVM_CMD_BOOTCRC 0x39
#define NVM_CMD_READUSERSIG 0x03
#define NVM_CMD_ERASEUSERSIG 0x18
#define NVM_CMD_WRITEUSERSIG 0x1A
#define NVM_CMD_READCALIBRATION 0x02
#define NVM_CMD_READFUSE 0x07
#define NVM_CMD_WRITEFUSE 0x4C
#define NVM_CMD_WRITELOCK 0x08
#define NVM_CMD_LOADEEPROMPAGEBUFF 0x33
#define NVM_CMD_ERASEEEPROMPAGEBUFF 0x36
#define NVM_CMD_ERASEEEPROM 0x30
#define NVM_CMD_ERASEEEPROMPAGE 0x32
#define NVM_CMD_WRITEEEPROMPAGE 0x34
#define NVM_CMD_ERASEWRITEEEPROMPAGE 0x35
#define NVM_CMD_READEEPROM 0x06
/* Function Prototypes: */
void NVMTarget_SendNVMRegAddress(const uint8_t Register);
void NVMTarget_SendAddress(const uint32_t AbsoluteAddress);
bool NVMTarget_WaitWhileNVMControllerBusy(void);
bool NVMTarget_GetMemoryCRC(const uint8_t CRCCommand, uint32_t* const CRCDest);
bool NVMTarget_ReadMemory(const uint32_t ReadAddress, uint8_t* ReadBuffer, const uint16_t ReadSize);
bool NVMTarget_WriteByteMemory(const uint8_t WriteCommand, const uint32_t WriteAddress, const uint8_t* WriteBuffer);
bool NVMTarget_WritePageMemory(const uint8_t WriteBuffCommand, const uint8_t EraseBuffCommand,
const uint8_t WritePageCommand, const uint8_t PageMode, const uint32_t WriteAddress,
const uint8_t* WriteBuffer, const uint16_t WriteSize);
bool NVMTarget_EraseMemory(const uint8_t EraseCommand, const uint32_t Address);
#endif

View file

@ -133,7 +133,8 @@ SRC = $(TARGET).c \
Lib/ISPTarget.c \
Lib/PDIProtocol.c \
Lib/PDITarget.c \
Lib/NVMTarget.c \
Lib/XMEGANVM.c \
Lib/TPITarget.c \
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/DevChapter9.c \
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Endpoint.c \
$(LUFA_PATH)/LUFA/Drivers/USB/LowLevel/Host.c \
@ -197,6 +198,7 @@ CDEFS += -DRESET_LINE_MASK="(1 << 4)"
CDEFS += -DVTARGET_ADC_CHANNEL=2
CDEFS += -DENABLE_ISP_PROTOCOL
CDEFS += -DENABLE_PDI_PROTOCOL
CDEFS += -DENABLE_TPI_PROTOCOL
# Place -D or -U options here for ASM sources