Updated Benito project -- added hardware interrupt and software buffering for serial data reception to prevent missed characters, condensed pulse generation counters into a struct for clarity.

Added check to CDC_Device_BytesReceived() to ensure 0 is returned when device is not enumerated to a host.

Move AVRISP project's V2Protocol_DelayMS() function to be static inline, as it is now very minimal. Added extra project doxygen documentation.
pull/1469/head
Dean Camera 15 years ago
parent f070902bdb
commit 6d1adf7339

File diff suppressed because one or more lines are too long

@ -174,6 +174,9 @@ uint8_t CDC_Device_Flush(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo)
uint16_t CDC_Device_BytesReceived(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo)
{
if ((USB_DeviceState != DEVICE_STATE_Configured) || !(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS))
return 0;
Endpoint_SelectEndpoint(CDCInterfaceInfo->Config.DataOUTEndpointNumber);
if (Endpoint_IsOUTReceived() && !(Endpoint_BytesInEndpoint()))

@ -36,17 +36,17 @@
#include "Benito.h"
/** Counter for the number of milliseconds remaining for the target /RESET pulse being generated. */
volatile uint8_t ResetPulseMSRemaining = 0;
/** Circular buffer to hold data from the serial port before it is sent to the host. */
RingBuff_t Tx_Buffer;
/** Counter for the number of milliseconds remaining for the TX activity LED pulse being generated. */
volatile uint8_t TxPulseMSRemaining = 0;
/** Counter for the number of milliseconds remaining for the RX activity LED pulse being generated. */
volatile uint8_t RxPulseMSRemaining = 0;
/** Counter for the number of milliseconds remaining for the enumeration LED ping-pong being generated. */
volatile uint8_t PingPongMSRemaining = 0;
/** Pulse generation counters to keep track of the number of milliseconds remaining for each pulse type */
volatile struct
{
uint8_t ResetPulse; /**< Milliseconds remaining for target /RESET pulse */
uint8_t TxLEDPulse; /**< Milliseconds remaining for data Tx LED pulse */
uint8_t RxLEDPulse; /**< Milliseconds remaining for data Rx LED pulse */
uint8_t PingPongLEDPulse; /**< Milliseconds remaining for enumeration Tx/Rx ping-pong LED pulse */
} PulseMSRemaining;
/** LUFA CDC Class driver interface configuration and state information. This structure is
* passed to all CDC Class driver functions, so that multiple instances of the same class
@ -75,50 +75,52 @@ USB_ClassInfo_CDC_Device_t VirtualSerial_CDC_Interface =
int main(void)
{
SetupHardware();
Buffer_Initialize(&Tx_Buffer);
for (;;)
{
/* Echo bytes from the host to the target via the hardware USART */
if (CDC_Device_BytesReceived(&VirtualSerial_CDC_Interface) > 0)
while (CDC_Device_BytesReceived(&VirtualSerial_CDC_Interface) > 0)
{
Serial_TxByte(CDC_Device_ReceiveByte(&VirtualSerial_CDC_Interface));
LEDs_TurnOnLEDs(LEDMASK_TX);
TxPulseMSRemaining = TX_RX_LED_PULSE_MS;
PulseMSRemaining.TxLEDPulse = TX_RX_LED_PULSE_MS;
}
/* Echo bytes from the target to the host via the virtual serial port */
if (Serial_IsCharReceived())
while (Tx_Buffer.Elements > 0)
{
CDC_Device_SendByte(&VirtualSerial_CDC_Interface, Serial_RxByte());
CDC_Device_SendByte(&VirtualSerial_CDC_Interface, Buffer_GetElement(&Tx_Buffer));
LEDs_TurnOnLEDs(LEDMASK_RX);
RxPulseMSRemaining = TX_RX_LED_PULSE_MS;
PulseMSRemaining.RxLEDPulse = TX_RX_LED_PULSE_MS;
}
/* Check if the millisecond timer has elapsed */
if (TIFR0 & (1 << OCF0A))
{
/* Check if the LEDs should be ping-ponging (during enumeration) */
if (PingPongMSRemaining && !(--PingPongMSRemaining))
{
LEDs_ToggleLEDs(LEDMASK_TX | LEDMASK_RX);
PingPongMSRemaining = PING_PONG_LED_PULSE_MS;
}
/* Check if the reset pulse period has elapsed, if so tristate the target reset line */
if (ResetPulseMSRemaining && !(--ResetPulseMSRemaining))
if (PulseMSRemaining.ResetPulse && !(--PulseMSRemaining.ResetPulse))
{
LEDs_TurnOffLEDs(LEDMASK_BUSY);
AVR_RESET_LINE_DDR &= ~AVR_RESET_LINE_MASK;
}
/* Check if the LEDs should be ping-ponging (during enumeration) */
if (PulseMSRemaining.PingPongLEDPulse && !(--PulseMSRemaining.PingPongLEDPulse))
{
LEDs_ToggleLEDs(LEDMASK_TX | LEDMASK_RX);
PulseMSRemaining.PingPongLEDPulse = PING_PONG_LED_PULSE_MS;
}
/* Turn off TX LED(s) once the TX pulse period has elapsed */
if (TxPulseMSRemaining && !(--TxPulseMSRemaining))
if (PulseMSRemaining.TxLEDPulse && !(--PulseMSRemaining.TxLEDPulse))
LEDs_TurnOffLEDs(LEDMASK_TX);
/* Turn off RX LED(s) once the RX pulse period has elapsed */
if (RxPulseMSRemaining && !(--RxPulseMSRemaining))
if (PulseMSRemaining.RxLEDPulse && !(--PulseMSRemaining.RxLEDPulse))
LEDs_TurnOffLEDs(LEDMASK_RX);
/* Clear the millisecond timer CTC flag (cleared by writing logic one to the register) */
@ -158,21 +160,21 @@ void SetupHardware(void)
/** Event handler for the library USB Connection event. */
void EVENT_USB_Device_Connect(void)
{
PingPongMSRemaining = PING_PONG_LED_PULSE_MS;
PulseMSRemaining.PingPongLEDPulse = PING_PONG_LED_PULSE_MS;
LEDs_SetAllLEDs(LEDMASK_TX);
}
/** Event handler for the library USB Disconnection event. */
void EVENT_USB_Device_Disconnect(void)
{
PingPongMSRemaining = 0;
PulseMSRemaining.PingPongLEDPulse = 0;
LEDs_SetAllLEDs(LEDS_NO_LEDS);
}
/** Event handler for the library USB Configuration Changed event. */
void EVENT_USB_Device_ConfigurationChanged(void)
{
PingPongMSRemaining = 0;
PulseMSRemaining.PingPongLEDPulse = 0;
LEDs_SetAllLEDs(LEDS_NO_LEDS);
if (!(CDC_Device_ConfigureEndpoints(&VirtualSerial_CDC_Interface)))
@ -220,11 +222,22 @@ void EVENT_CDC_Device_LineEncodingChanged(USB_ClassInfo_CDC_Device_t* const CDCI
}
UCSR1A = (1 << U2X1);
UCSR1B = ((1 << TXEN1) | (1 << RXEN1));
UCSR1B = ((1 << RXCIE1) | (1 << TXEN1) | (1 << RXEN1));
UCSR1C = ConfigMask;
UBRR1 = SERIAL_2X_UBBRVAL((uint16_t)CDCInterfaceInfo->State.LineEncoding.BaudRateBPS);
}
/** ISR to manage the reception of data from the serial port, placing received bytes into a circular buffer
* for later transmission to the host.
*/
ISR(USART1_RX_vect, ISR_BLOCK)
{
uint8_t ReceivedByte = UDR1;
if (USB_DeviceState == DEVICE_STATE_Configured)
Buffer_StoreElement(&Tx_Buffer, ReceivedByte);
}
/** Event handler for the CDC Class driver Host-to-Device Line Encoding Changed event.
*
* \param[in] CDCInterfaceInfo Pointer to the CDC class interface configuration structure being referenced
@ -236,7 +249,7 @@ void EVENT_CDC_Device_ControLineStateChanged(USB_ClassInfo_CDC_Device_t* const C
{
LEDs_SetAllLEDs(LEDMASK_BUSY);
AVR_RESET_LINE_DDR |= AVR_RESET_LINE_MASK;
ResetPulseMSRemaining = AVR_RESET_PULSE_MS;
AVR_RESET_LINE_DDR |= AVR_RESET_LINE_MASK;
PulseMSRemaining.ResetPulse = AVR_RESET_PULSE_MS;
}
}

@ -43,6 +43,7 @@
#include <avr/power.h>
#include "Descriptors.h"
#include "Lib/RingBuff.h"
#include <LUFA/Version.h>
#include <LUFA/Drivers/Board/LEDs.h>

@ -0,0 +1,120 @@
/*
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.
*/
#include "RingBuff.h"
void Buffer_Initialize(RingBuff_t* Buffer)
{
BUFF_ATOMIC_BLOCK
{
Buffer->InPtr = (RingBuff_Data_t*)&Buffer->Buffer;
Buffer->OutPtr = (RingBuff_Data_t*)&Buffer->Buffer;
Buffer->Elements = 0;
}
}
void Buffer_StoreElement(RingBuff_t* Buffer, RingBuff_Data_t Data)
{
BUFF_ATOMIC_BLOCK
{
#if defined(BUFF_DROPOLD)
if (Buffer->Elements == BUFF_LENGTH)
{
Buffer->OutPtr++;
if (Buffer->OutPtr == &Buffer->Buffer[BUFF_LENGTH])
Buffer->OutPtr = (RingBuff_Data_t*)&Buffer->Buffer;
}
else
{
Buffer->Elements++;
}
#elif defined(BUFF_DROPNEW)
if (Buffer->Elements == BUFF_LENGTH)
return;
Buffer->Elements++;
#elif defined(BUFF_NODROPCHECK)
Buffer->Elements++;
#endif
*(Buffer->InPtr) = Data;
Buffer->InPtr++;
if (Buffer->InPtr == &Buffer->Buffer[BUFF_LENGTH])
Buffer->InPtr = (RingBuff_Data_t*)&Buffer->Buffer;
}
}
RingBuff_Data_t Buffer_GetElement(RingBuff_t* Buffer)
{
RingBuff_Data_t BuffData;
BUFF_ATOMIC_BLOCK
{
#if defined(BUFF_EMPTYRETURNSZERO)
if (!(Buffer->Elements))
return 0;
#elif !defined(BUFF_NOEMPTYCHECK)
#error No empty buffer check behaviour specified.
#endif
BuffData = *(Buffer->OutPtr);
Buffer->OutPtr++;
Buffer->Elements--;
if (Buffer->OutPtr == &Buffer->Buffer[BUFF_LENGTH])
Buffer->OutPtr = (RingBuff_Data_t*)&Buffer->Buffer;
}
return BuffData;
}
#if defined(BUFF_USEPEEK)
RingBuff_Data_t Buffer_PeekElement(const RingBuff_t* Buffer)
{
RingBuff_Data_t BuffData;
BUFF_ATOMIC_BLOCK
{
#if defined(BUFF_EMPTYRETURNSZERO)
if (!(Buffer->Elements))
return 0;
#elif !defined(BUFF_NOEMPTYCHECK)
#error No empty buffer check behaviour specified.
#endif
BuffData = *(Buffer->OutPtr);
}
return BuffData;
}
#endif

@ -0,0 +1,116 @@
/*
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.
*/
/* Buffer Configuration: */
/* Buffer length - select static size of created ring buffers: */
#define BUFF_STATICSIZE 128 // Set to the static ring buffer size for all ring buffers (place size after define)
/* Volatile mode - uncomment to make buffers volatile, for use in ISRs, etc: */
#define BUFF_VOLATILE // Uncomment to cause all ring buffers to become volatile (and atomic if multi-byte) in access
/* Drop mode - select behaviour when Buffer_StoreElement called on a full buffer: */
#define BUFF_DROPOLD // Uncomment to cause full ring buffers to drop the oldest character to make space when full
// #define BUFF_DROPNEW // Uncomment to cause full ring buffers to drop the new character when full
// #define BUFF_NODROPCHECK // Uncomment to ignore full ring buffer checks - checking left to user!
/* Underflow behaviour - select behaviour when Buffer_GetElement is called with an empty ring buffer: */
//#define BUFF_EMPTYRETURNSZERO // Uncomment to return 0 when an empty ring buffer is read
#define BUFF_NOEMPTYCHECK // Uncomment to disable checking of empty ring buffers - checking left to user!
/* Buffer storage type - set the datatype for the stored data */
#define BUFF_DATATYPE uint8_t // Change to the data type that is going to be stored into the buffer
/* Peek routine - uncomment to include the peek routine (fetches next byte without removing it from the buffer */
//#define BUFF_USEPEEK
#ifndef _RINGBUFF_H_
#define _RINGBUFF_H_
/* Includes: */
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/atomic.h>
#include <limits.h>
#include <LUFA/Common/Common.h>
/* Defines and checks: */
#if defined(BUFF_STATICSIZE)
#define BUFF_LENGTH BUFF_STATICSIZE
#else
#error No buffer length specified!
#endif
#if !(defined(BUFF_DROPOLD) || defined(BUFF_DROPNEW) || defined(BUFF_NODROPCHECK))
#error No buffer drop mode specified.
#endif
#if !defined(BUFF_DATATYPE)
#error Ringbuffer storage data type not specified.
#endif
#if defined(BUFF_VOLATILE)
#define BUFF_MODE volatile
#define BUFF_ATOMIC_BLOCK ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
#else
#define BUFF_MODE
#define BUFF_ATOMIC_BLOCK
#endif
#if (BUFF_STATICSIZE > LONG_MAX)
#define RingBuff_Elements_t uint64_t
#elif (BUFF_STATICSIZE > INT_MAX)
#define RingBuff_Elements_t uint32_t
#elif (BUFF_STATICSIZE > CHAR_MAX)
#define RingBuff_Elements_t uint16_t
#else
#define RingBuff_Elements_t uint8_t
#endif
/* Type Defines: */
typedef BUFF_DATATYPE RingBuff_Data_t;
typedef BUFF_MODE struct
{
RingBuff_Data_t Buffer[BUFF_LENGTH];
RingBuff_Data_t* InPtr;
RingBuff_Data_t* OutPtr;
RingBuff_Elements_t Elements;
} RingBuff_t;
/* Function Prototypes: */
void Buffer_Initialize(RingBuff_t* Buff);
void Buffer_StoreElement(RingBuff_t* Buffer, RingBuff_Data_t Data);
RingBuff_Data_t Buffer_GetElement(RingBuff_t* Buffer);
#if defined(BUFF_USEPEEK)
RingBuff_Data_t Buffer_PeekElement(const RingBuff_t* Buffer);
#endif
#endif

@ -134,6 +134,7 @@ LUFA_OPTS += -D USE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENAB
# List C source files here. (C dependencies are automatically generated.)
SRC = $(TARGET).c \
Descriptors.c \
Lib/RingBuff.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 \
@ -192,9 +193,9 @@ 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 += -DAVR_RESET_LINE_PORT="PORTB"
CDEFS += -DAVR_RESET_LINE_DDR="DDRB"
CDEFS += -DAVR_RESET_LINE_MASK="(1 << 0)"
CDEFS += -DAVR_RESET_LINE_PORT="PORTD"
CDEFS += -DAVR_RESET_LINE_DDR="DDRD"
CDEFS += -DAVR_RESET_LINE_MASK="(1 << 4)"
CDEFS += -DAVR_RESET_PULSE_MS=10
CDEFS += -DTX_RX_LED_PULSE_MS=30
CDEFS += -DPING_PONG_LED_PULSE_MS=100

@ -34,10 +34,11 @@
* the project and is responsible for the initial application hardware configuration.
*/
// TODO: Add reversed target connector checks
// TODO: Fix PROGRAM FLASH and PROGRAM EEPROM command processing
// TODO: Add in software SPI for lower programming speeds below 125KHz
// TODO: Add in VTARGET detection
// TODO: Add in software SPI for lower programming speeds
// TODO: Add reversed target connector checks
// TODO: Add Doxygen comments to functions
#include "AVRISP.h"

@ -46,7 +46,6 @@
#include <LUFA/Version.h>
#include <LUFA/Drivers/Board/LEDs.h>
#include <LUFA/Drivers/Peripheral/SPI.h>
#include <LUFA/Drivers/USB/USB.h>
#include "Lib/V2Protocol.h"

@ -38,13 +38,15 @@
/* Includes: */
#include <LUFA/Drivers/USB/USB.h>
#include <LUFA/Drivers/Peripheral/SPI.h>
#include "../Descriptors.h"
#include "V2ProtocolConstants.h"
#include "V2ProtocolParams.h"
#include "V2ProtocolTarget.h"
/* Macros: */
/* Macros: */
/** Programmer ID string, returned to the host during the CMD_SIGN_ON command processing */
#define PROGRAMMER_ID "AVRISP_MK2"
#define READ_WRITE_HIGH_BYTE_MASK (1 << 3)

@ -67,7 +67,7 @@ static ParameterItem_t ParameterTable[] =
.ParamPrivellages = PARAM_PRIV_READ },
{ .ParamID = PARAM_SCK_DURATION,
.ParamValue = 0x06,
.ParamValue = (TOTAL_PROGRAMMING_SPEEDS - 1),
.ParamPrivellages = PARAM_PRIV_READ | PARAM_PRIV_WRITE },
{ .ParamID = PARAM_RESET_POLARITY,

@ -46,15 +46,19 @@
#include "V2ProtocolConstants.h"
/* Macros: */
/* Parameter privellage mask to allow the host PC to read the parameter's value */
#define PARAM_PRIV_READ (1 << 0)
/* Parameter privellage mask to allow the host PC to change the parameter's value */
#define PARAM_PRIV_WRITE (1 << 1)
/* Type Defines: */
/** Type define for a parameter table entry indicating a PC readable or writable device parameter. */
typedef struct
{
const uint8_t ParamID;
uint8_t ParamValue;
uint8_t ParamPrivellages;
const uint8_t ParamID; /**< Parameter ID number to uniquely identify the parameter within the device */
uint8_t ParamValue; /**< Current parameter's value within the device */
uint8_t ParamPrivellages; /**< Parameter privellages to allow the host to read or write the parameter's value */
} ParameterItem_t;
/* Function Prototypes: */

@ -40,7 +40,7 @@ uint32_t CurrentAddress;
uint8_t V2Protocol_GetSPIPrescalerMask(void)
{
static const uint8_t SPIMaskFromSCKDuration[] =
static const uint8_t SPIMaskFromSCKDuration[TOTAL_PROGRAMMING_SPEEDS] =
{
#if (F_CPU == 8000000)
SPI_SPEED_FCPU_DIV_2,
@ -76,12 +76,6 @@ void V2Protocol_ChangeTargetResetLine(bool ResetTarget)
}
}
void V2Protocol_DelayMS(uint8_t MS)
{
TCNT0 = 0;
while (TCNT0 < MS);
}
uint8_t V2Protocol_WaitForProgComplete(uint8_t ProgrammingMode, uint16_t PollAddress, uint8_t PollValue,
uint8_t DelayMS, uint8_t ReadMemCommand)
{
@ -96,7 +90,7 @@ uint8_t V2Protocol_WaitForProgComplete(uint8_t ProgrammingMode, uint16_t PollAdd
break;
case PROG_MODE_WORD_VALUE_MASK:
case PROG_MODE_PAGED_VALUE_MASK:
TCNT0 = 0;
TCNT0 = 0;
do
{
@ -121,7 +115,7 @@ uint8_t V2Protocol_WaitForProgComplete(uint8_t ProgrammingMode, uint16_t PollAdd
uint8_t V2Protocol_WaitWhileTargetBusy(void)
{
TCNT0 = 0;
TCNT0 = 0;
do
{

@ -48,11 +48,22 @@
#include "V2ProtocolParams.h"
/* Macros: */
/** Total number of allowable ISP programming speeds supported by the device */
#define TOTAL_PROGRAMMING_SPEEDS 7
/** Timeout in milliseconds of target busy-wait loops waiting for a command to complete */
#define TARGET_BUSY_TIMEOUT_MS 150
/* External Variables: */
extern uint32_t CurrentAddress;
/* Inline Functions: */
static inline void V2Protocol_DelayMS(uint8_t MS)
{
TCNT0 = 0;
while (TCNT0 < MS);
}
/* Function Prototypes: */
uint8_t V2Protocol_GetSPIPrescalerMask(void);
void V2Protocol_ChangeTargetResetLine(bool ResetTarget);

Loading…
Cancel
Save