Rename architecture specific driver files, to make them appear with uniquely identifying filenames in the documentation.

This commit is contained in:
Dean Camera 2011-02-20 18:21:04 +00:00
commit b6a3c78fa3
46 changed files with 66 additions and 66 deletions

File diff suppressed because one or more lines are too long

View file

@ -68,7 +68,7 @@
/* Includes: */
#if (ARCH == ARCH_AVR8)
#include "AVR8/ADC.h"
#include "AVR8/ADC_AVR8.h"
#else
#error The ADC peripheral driver is not currently available for your selected architecture.
#endif

View file

@ -0,0 +1,453 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2011.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2011 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, 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
* \brief ADC Peripheral Driver (AVR8)
*
* On-chip Analogue-to-Digital converter (ADC) driver for supported U4, U6 and U7 model AVRs that contain an ADC
* peripheral internally.
*
* \note This file should not be included directly. It is automatically included as needed by the ADC driver
* dispatch header located in LUFA/Drivers/Peripheral/ADC.h.
*/
/** \ingroup Group_ADC
* \defgroup Group_ADC_AVR8 ADC Peripheral Driver (AVR8)
*
* \section Sec_ModDescription Module Description
* On-chip Analogue-to-Digital converter (ADC) driver for supported U4, U6 and U7 model AVRs that contain an ADC
* peripheral internally.
*
* \note This file should not be included directly. It is automatically included as needed by the ADC driver
* dispatch header located in LUFA/Drivers/Peripheral/ADC.h.
*
* \section Sec_ExampleUsage Example Usage
* The following snippet is an example of how this module may be used within a typical
* application.
*
* \code
* // Initialise the ADC driver before first use
* ADC_Init(ADC_FREE_RUNNING | ADC_PRESCALE_32);
*
* // Must setup the ADC channel to read beforehand
* ADC_SetupChannel(1);
*
* // Perform a single conversion of the ADC channel 1
* ADC_GetChannelReading(ADC_REFERENCE_AVCC | ADC_RIGHT_ADJUSTED | ADC_CHANNEL1);
* printf("Conversion Result: %d\r\n", ADC_GetResult());
*
* // Start reading ADC channel 1 in free running (continuous conversion) mode
* ADC_StartReading(ADC_REFERENCE_AVCC | ADC_RIGHT_ADJUSTED | ADC_CHANNEL1);
* while (!(ADC_IsReadingComplete())) {};
* printf("Conversion Result: %d\r\n", ADC_GetResult());
* \endcode
*
* @{
*/
#ifndef __ADC_AVR8_H__
#define __ADC_AVR8_H__
/* Includes: */
#include "../../../Common/Common.h"
/* Enable C linkage for C++ Compilers: */
#if defined(__cplusplus)
extern "C" {
#endif
/* Preprocessor Checks: */
#if !defined(__INCLUDE_FROM_ADC_H)
#error Do not include this file directly. Include LUFA/Drivers/Peripheral/ADC.h instead.
#endif
#if !(defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB646__) || \
defined(__AVR_AT90USB1287__) || defined(__AVR_AT90USB647__) || \
defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__) || \
defined(__AVR_ATmega32U6__))
#error The ADC peripheral driver is not currently available for your selected microcontroller model.
#endif
/* Private Interface - For use in library only: */
#if !defined(__DOXYGEN__)
/* Macros: */
#define _ADC_GET_MUX_MASK2(y) ADC_CHANNEL ## y
#define _ADC_GET_MUX_MASK(y) _ADC_GET_MUX_MASK2(y)
#endif
/* Public Interface - May be used in end-application: */
/* Macros: */
/** \name ADC Reference Configuration Masks */
//@{
/** Reference mask, for using the voltage present at the AVR's AREF pin for the ADC reference. */
#define ADC_REFERENCE_AREF 0
/** Reference mask, for using the voltage present at the AVR's AVCC pin for the ADC reference. */
#define ADC_REFERENCE_AVCC (1 << REFS0)
/** Reference mask, for using the internally generated 2.56V reference voltage as the ADC reference. */
#define ADC_REFERENCE_INT2560MV ((1 << REFS1) | (1 << REFS0))
//@}
/** \name ADC Result Adjustment Configuration Masks */
//@{
/** Left-adjusts the 10-bit ADC result, so that the upper 8 bits of the value returned by the
* \ref ADC_GetResult() macro contain the 8 most significant bits of the result.
*/
#define ADC_LEFT_ADJUSTED (1 << ADLAR)
/** Right-adjusts the 10-bit ADC result, so that the lower 8 bits of the value returned by the
* \ref ADC_GetResult() macro contain the 8 least significant bits of the result.
*/
#define ADC_RIGHT_ADJUSTED (0 << ADLAR)
//@}
/** \name ADC Mode Configuration Masks */
//@{
/** Sets the ADC mode to free running, so that conversions take place continuously as fast as the ADC
* is capable of at the given input clock speed.
*/
#define ADC_FREE_RUNNING (1 << ADATE)
/** Sets the ADC mode to single conversion, so that only a single conversion will take place before
* the ADC returns to idle.
*/
#define ADC_SINGLE_CONVERSION (0 << ADATE)
//@}
/** \name ADC Prescaler Configuration Masks */
//@{
/** Sets the ADC input clock to prescale by a factor of 2 the AVR's system clock. */
#define ADC_PRESCALE_2 (1 << ADPS0)
/** Sets the ADC input clock to prescale by a factor of 4 the AVR's system clock. */
#define ADC_PRESCALE_4 (1 << ADPS1)
/** Sets the ADC input clock to prescale by a factor of 8 the AVR's system clock. */
#define ADC_PRESCALE_8 ((1 << ADPS0) | (1 << ADPS1))
/** Sets the ADC input clock to prescale by a factor of 16 the AVR's system clock. */
#define ADC_PRESCALE_16 (1 << ADPS2)
/** Sets the ADC input clock to prescale by a factor of 32 the AVR's system clock. */
#define ADC_PRESCALE_32 ((1 << ADPS2) | (1 << ADPS0))
/** Sets the ADC input clock to prescale by a factor of 64 the AVR's system clock. */
#define ADC_PRESCALE_64 ((1 << ADPS2) | (1 << ADPS1))
/** Sets the ADC input clock to prescale by a factor of 128 the AVR's system clock. */
#define ADC_PRESCALE_128 ((1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0))
//@}
/** \name ADC MUX Masks */
//@{
/** MUX mask define for the ADC0 channel of the ADC. See \ref ADC_StartReading() and \ref ADC_GetChannelReading(). */
#define ADC_CHANNEL0 (0x00 << MUX0)
/** MUX mask define for the ADC1 channel of the ADC. See \ref ADC_StartReading() and \ref ADC_GetChannelReading(). */
#define ADC_CHANNEL1 (0x01 << MUX0)
#if !(defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__) || defined(__DOXYGEN__))
/** MUX mask define for the ADC2 channel of the ADC. See \ref ADC_StartReading() and \ref ADC_GetChannelReading().
*
* \note Not available on all AVR models.
*/
#define ADC_CHANNEL2 (0x02 << MUX0)
/** MUX mask define for the ADC3 channel of the ADC. See \ref ADC_StartReading() and \ref ADC_GetChannelReading().
*
* \note Not available on all AVR models.
*/
#define ADC_CHANNEL3 (0x03 << MUX0)
#endif
/** MUX mask define for the ADC4 channel of the ADC. See \ref ADC_StartReading() and \ref ADC_GetChannelReading(). */
#define ADC_CHANNEL4 (0x04 << MUX0)
/** MUX mask define for the ADC5 channel of the ADC. See \ref ADC_StartReading() and \ref ADC_GetChannelReading(). */
#define ADC_CHANNEL5 (0x05 << MUX0)
/** MUX mask define for the ADC6 channel of the ADC. See \ref ADC_StartReading() and \ref ADC_GetChannelReading(). */
#define ADC_CHANNEL6 (0x06 << MUX0)
/** MUX mask define for the ADC7 channel of the ADC. See \ref ADC_StartReading and \ref ADC_GetChannelReading. */
#define ADC_CHANNEL7 (0x07 << MUX0)
/** MUX mask define for the internal 1.1V bandgap channel of the ADC. See \ref ADC_StartReading() and \ref ADC_GetChannelReading(). */
#define ADC_1100MV_BANDGAP (0x1E << MUX0)
#if (defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__) || defined(__DOXYGEN__))
/** MUX mask define for the ADC8 channel of the ADC. See \ref ADC_StartReading() and \ref ADC_GetChannelReading().
*
* \note Not available on all AVR models.
*/
#define ADC_CHANNEL8 ((1 << 8) | (0x00 << MUX0))
/** MUX mask define for the ADC9 channel of the ADC. See \ref ADC_StartReading() and \ref ADC_GetChannelReading().
*
* \note Not available on all AVR models.
*/
#define ADC_CHANNEL9 ((1 << 8) | (0x01 << MUX0))
/** MUX mask define for the ADC10 channel of the ADC. See \ref ADC_StartReading() and \ref ADC_GetChannelReading().
*
* \note Not available on all AVR models.
*/
#define ADC_CHANNEL10 ((1 << 8) | (0x02 << MUX0))
/** MUX mask define for the ADC11 channel of the ADC. See \ref ADC_StartReading() and \ref ADC_GetChannelReading().
*
* \note Not available on all AVR models.
*/
#define ADC_CHANNEL11 ((1 << 8) | (0x03 << MUX0))
/** MUX mask define for the ADC12 channel of the ADC. See \ref ADC_StartReading() and \ref ADC_GetChannelReading().
*
* \note Not available on all AVR models.
*/
#define ADC_CHANNEL12 ((1 << 8) | (0x04 << MUX0))
/** MUX mask define for the ADC13 channel of the ADC. See \ref ADC_StartReading() and \ref ADC_GetChannelReading().
*
* \note Not available on all AVR models.
*/
#define ADC_CHANNEL13 ((1 << 8) | (0x05 << MUX0))
/** MUX mask define for the internal temperature sensor channel of the ADC. See \ref ADC_StartReading() and
* \ref ADC_GetChannelReading().
*
* \note Not available on all AVR models.
*/
#define ADC_INT_TEMP_SENS ((1 << 8) | (0x07 << MUX0))
#endif
/** Retrieves the ADC MUX mask for the given ADC channel number.
*
* \note This macro will only work correctly on channel numbers that are compile-time
* constants defined by the preprocessor.
*
* \param[in] Channel Index of the ADC channel whose MUX mask is to be retrieved.
*/
#define ADC_GET_CHANNEL_MASK(Channel) _ADC_GET_MUX_MASK(Channel)
//@}
/* Inline Functions: */
/** Configures the given ADC channel, ready for ADC conversions. This function sets the
* associated port pin as an input and disables the digital portion of the I/O to reduce
* power consumption.
*
* \note This must only be called for ADC channels with are connected to a physical port
* pin of the AVR, denoted by its special alternative function ADCx.
* \n\n
*
* \note The channel number must be specified as an integer, and <b>not</b> a \c ADC_CHANNEL* mask.
*
* \param[in] ChannelIndex ADC channel number to set up for conversions.
*/
static inline void ADC_SetupChannel(const uint8_t ChannelIndex)
{
#if (defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB646__) || \
defined(__AVR_AT90USB1287__) || defined(__AVR_AT90USB647__) || \
defined(__AVR_ATmega32U6__))
DDRF &= ~(1 << ChannelIndex);
DIDR0 |= (1 << ChannelIndex);
#elif (defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__))
if (ChannelIndex < 8)
{
DDRF &= ~(1 << ChannelIndex);
DIDR0 |= (1 << ChannelIndex);
}
else if (ChannelIndex == 8)
{
DDRD &= ~(1 << 4);
DIDR2 |= (1 << 0);
}
else if (ChannelIndex < 11)
{
DDRD &= ~(1 << (ChannelIndex - 3));
DIDR2 |= (1 << (ChannelIndex - 8));
}
else
{
DDRB &= ~(1 << (ChannelIndex - 7));
DIDR2 |= (1 << (ChannelIndex - 8));
}
#endif
}
/** De-configures the given ADC channel, re-enabling digital I/O mode instead of analog. This
* function sets the associated port pin as an input and re-enabled the digital portion of
* the I/O.
*
* \note This must only be called for ADC channels with are connected to a physical port
* pin of the AVR, denoted by its special alternative function ADCx.
* \n\n
*
* \note The channel number must be specified as an integer, and <b>not</b> a \c ADC_CHANNEL* mask.
*
* \param[in] ChannelIndex ADC channel number to set up for conversions.
*/
static inline void ADC_DisableChannel(const uint8_t ChannelIndex)
{
#if (defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB646__) || \
defined(__AVR_AT90USB1287__) || defined(__AVR_AT90USB647__) || \
defined(__AVR_ATmega32U6__))
DDRF &= ~(1 << ChannelIndex);
DIDR0 &= ~(1 << ChannelIndex);
#elif (defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__))
if (ChannelIndex < 8)
{
DDRF &= ~(1 << ChannelIndex);
DIDR0 &= ~(1 << ChannelIndex);
}
else if (ChannelIndex == 8)
{
DDRD &= ~(1 << 4);
DIDR2 &= ~(1 << 0);
}
else if (ChannelIndex < 11)
{
DDRD &= ~(1 << (ChannelIndex - 3));
DIDR2 &= ~(1 << (ChannelIndex - 8));
}
else
{
DDRB &= ~(1 << (ChannelIndex - 7));
DIDR2 &= ~(1 << (ChannelIndex - 8));
}
#endif
}
/** Starts the reading of the given channel, but does not wait until the conversion has completed.
* Once executed, the conversion status can be determined via the \ref ADC_IsReadingComplete() macro and
* the result read via the \ref ADC_GetResult() macro.
*
* If the ADC has been initialized in free running mode, calling this function once will begin the repeated
* conversions. If the ADC is in single conversion mode (or the channel to convert from is to be changed),
* this function must be called each time a conversion is to take place.
*
* \param[in] MUXMask ADC channel mask, reference mask and adjustment mask.
*/
static inline void ADC_StartReading(const uint16_t MUXMask)
{
ADMUX = MUXMask;
#if (defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__) || defined(__DOXYGEN__))
if (MUXMask & (1 << 8))
ADCSRB |= (1 << MUX5);
else
ADCSRB &= ~(1 << MUX5);
#endif
ADCSRA |= (1 << ADSC);
}
/** Indicates if the current ADC conversion is completed, or still in progress.
*
* \return Boolean false if the reading is still taking place, or true if the conversion is
* complete and ready to be read out with \ref ADC_GetResult().
*/
static inline bool ADC_IsReadingComplete(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline bool ADC_IsReadingComplete(void)
{
return ((ADCSRA & (1 << ADIF)) ? true : false);
}
/** Retrieves the conversion value of the last completed ADC conversion and clears the reading
* completion flag.
*
* \return The result of the last ADC conversion as an unsigned value.
*/
static inline uint16_t ADC_GetResult(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline uint16_t ADC_GetResult(void)
{
ADCSRA |= (1 << ADIF);
return ADC;
}
/** Performs a complete single reading from channel, including a polling spin-loop to wait for the
* conversion to complete, and the returning of the converted value.
*
* \note For free running mode, the automated conversions should be initialized with a single call
* to \ref ADC_StartReading() to select the channel and begin the automated conversions, and
* the results read directly from the \ref ADC_GetResult() instead to reduce overhead.
*
* \param[in] MUXMask Mask comprising of an ADC channel mask, reference mask and adjustment mask.
*/
static inline uint16_t ADC_GetChannelReading(const uint16_t MUXMask) ATTR_WARN_UNUSED_RESULT;
static inline uint16_t ADC_GetChannelReading(const uint16_t MUXMask)
{
ADC_StartReading(MUXMask);
while (!(ADC_IsReadingComplete()));
return ADC_GetResult();
}
/** Initialises the ADC, ready for conversions. This must be called before any other ADC operations.
* The "mode" parameter should be a mask comprised of a conversion mode (free running or single) and
* prescaler masks.
*
* \param[in] Mode Mask of ADC prescale and mode settings.
*/
static inline void ADC_Init(uint8_t Mode) ATTR_ALWAYS_INLINE;
static inline void ADC_Init(uint8_t Mode)
{
ADCSRA = ((1 << ADEN) | Mode);
}
/** Turns off the ADC. If this is called, any further ADC operations will require a call to
* \ref ADC_Init() before the ADC can be used again.
*/
static inline void ADC_Disable(void) ATTR_ALWAYS_INLINE;
static inline void ADC_Disable(void)
{
ADCSRA = 0;
}
/** Indicates if the ADC is currently enabled.
*
* \return Boolean \c true if the ADC subsystem is currently enabled, \c false otherwise.
*/
static inline bool ADC_GetStatus(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline bool ADC_GetStatus(void)
{
return ((ADCSRA & (1 << ADEN)) ? true : false);
}
/* Disable C linkage for C++ Compilers: */
#if defined(__cplusplus)
}
#endif
#endif
/** @} */

View file

@ -0,0 +1,239 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2011.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2011 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, 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
* \brief SPI Peripheral Driver (AVR8)
*
* On-chip SPI driver for the 8-bit AVR microcontrollers.
*
* \note This file should not be included directly. It is automatically included as needed by the SPI driver
* dispatch header located in LUFA/Drivers/Peripheral/SPI.h.
*/
/** \ingroup Group_SPI
* \defgroup Group_SPI_AVR8 SPI Peripheral Driver (AVR8)
*
* \section Sec_ModDescription Module Description
* Driver for the hardware SPI port available on most 8-bit AVR microcontroller models. This
* module provides an easy to use driver for the setup and transfer of data over the
* AVR's SPI port.
*
* \note This file should not be included directly. It is automatically included as needed by the SPI driver
* dispatch header located in LUFA/Drivers/Peripheral/SPI.h.
*
* \section Sec_ExampleUsage Example Usage
* The following snippet is an example of how this module may be used within a typical
* application.
*
* \code
* // Initialise the SPI driver before first use
* SPI_Init(SPI_SPEED_FCPU_DIV_2 | SPI_ORDER_MSB_FIRST | SPI_SCK_LEAD_FALLING |
* SPI_SAMPLE_TRAILING | SPI_MODE_MASTER);
*
* // Send several bytes, ignoring the returned data
* SPI_SendByte(0x01);
* SPI_SendByte(0x02);
* SPI_SendByte(0x03);
*
* // Receive several bytes, sending a dummy 0x00 byte each time
* uint8_t Byte1 = SPI_ReceiveByte();
* uint8_t Byte2 = SPI_ReceiveByte();
* uint8_t Byte3 = SPI_ReceiveByte();
*
* // Send a byte, and store the received byte from the same transaction
* uint8_t ResponseByte = SPI_TransferByte(0xDC);
* \endcode
*
* @{
*/
#ifndef __SPI_AVR8_H__
#define __SPI_AVR8_H__
/* Includes: */
#include "../../../Common/Common.h"
/* Enable C linkage for C++ Compilers: */
#if defined(__cplusplus)
extern "C" {
#endif
/* Preprocessor Checks: */
#if !defined(__INCLUDE_FROM_SPI_H)
#error Do not include this file directly. Include LUFA/Drivers/Peripheral/SPI.h instead.
#endif
/* Private Interface - For use in library only: */
#if !defined(__DOXYGEN__)
/* Macros: */
#define SPI_USE_DOUBLESPEED (1 << SPE)
#endif
/* Public Interface - May be used in end-application: */
/* Macros: */
/** \name SPI Prescaler Configuration Masks */
//@{
/** SPI prescaler mask for \c SPI_Init(). Divides the system clock by a factor of 2. */
#define SPI_SPEED_FCPU_DIV_2 SPI_USE_DOUBLESPEED
/** SPI prescaler mask for \c SPI_Init(). Divides the system clock by a factor of 4. */
#define SPI_SPEED_FCPU_DIV_4 0
/** SPI prescaler mask for \c SPI_Init(). Divides the system clock by a factor of 8. */
#define SPI_SPEED_FCPU_DIV_8 (SPI_USE_DOUBLESPEED | (1 << SPR0))
/** SPI prescaler mask for \c SPI_Init(). Divides the system clock by a factor of 16. */
#define SPI_SPEED_FCPU_DIV_16 (1 << SPR0)
/** SPI prescaler mask for \c SPI_Init(). Divides the system clock by a factor of 32. */
#define SPI_SPEED_FCPU_DIV_32 (SPI_USE_DOUBLESPEED | (1 << SPR1))
/** SPI prescaler mask for \c SPI_Init(). Divides the system clock by a factor of 64. */
#define SPI_SPEED_FCPU_DIV_64 (SPI_USE_DOUBLESPEED | (1 << SPR1) | (1 << SPR0))
/** SPI prescaler mask for \c SPI_Init(). Divides the system clock by a factor of 128. */
#define SPI_SPEED_FCPU_DIV_128 ((1 << SPR1) | (1 << SPR0))
//@}
/** \name SPI SCK Polarity Configuration Masks */
//@{
/** SPI clock polarity mask for \c SPI_Init(). Indicates that the SCK should lead on the rising edge. */
#define SPI_SCK_LEAD_RISING (0 << CPOL)
/** SPI clock polarity mask for \c SPI_Init(). Indicates that the SCK should lead on the falling edge. */
#define SPI_SCK_LEAD_FALLING (1 << CPOL)
//@}
/** \name SPI Sample Edge Configuration Masks */
//@{
/** SPI data sample mode mask for \c SPI_Init(). Indicates that the data should sampled on the leading edge. */
#define SPI_SAMPLE_LEADING (0 << CPHA)
/** SPI data sample mode mask for \c SPI_Init(). Indicates that the data should be sampled on the trailing edge. */
#define SPI_SAMPLE_TRAILING (1 << CPHA)
//@}
/** \name SPI Data Ordering Configuration Masks */
//@{
/** SPI data order mask for \c SPI_Init(). Indicates that data should be shifted out MSB first. */
#define SPI_ORDER_MSB_FIRST (0 << DORD)
/** SPI data order mask for \c SPI_Init(). Indicates that data should be shifted out MSB first. */
#define SPI_ORDER_LSB_FIRST (1 << DORD)
//@}
/** \name SPI Mode Configuration Masks */
//@{
/** SPI mode mask for \c SPI_Init(). Indicates that the SPI interface should be initialized into slave mode. */
#define SPI_MODE_SLAVE (0 << MSTR)
/** SPI mode mask for \c SPI_Init(). Indicates that the SPI interface should be initialized into master mode. */
#define SPI_MODE_MASTER (1 << MSTR)
//@}
/* Inline Functions: */
/** Initialises the SPI subsystem, ready for transfers. Must be called before calling any other
* SPI routines.
*
* \param[in] SPIOptions SPI Options, a mask consisting of one of each of the \c SPI_SPEED_*,
* \c SPI_SCK_*, \c SPI_SAMPLE_*, \c SPI_ORDER_* and \c SPI_MODE_* masks.
*/
static inline void SPI_Init(const uint8_t SPIOptions)
{
DDRB |= ((1 << 1) | (1 << 2));
DDRB &= ~((1 << 0) | (1 << 3));
PORTB |= ((1 << 0) | (1 << 3));
SPCR = ((1 << SPE) | SPIOptions);
if (SPIOptions & SPI_USE_DOUBLESPEED)
SPSR |= (1 << SPI2X);
else
SPSR &= ~(1 << SPI2X);
}
/** Turns off the SPI driver, disabling and returning used hardware to their default configuration. */
static inline void SPI_Disable(void)
{
DDRB &= ~((1 << 1) | (1 << 2));
PORTB &= ~((1 << 0) | (1 << 3));
SPCR = 0;
SPSR = 0;
}
/** Sends and receives a byte through the SPI interface, blocking until the transfer is complete.
*
* \param[in] Byte Byte to send through the SPI interface.
*
* \return Response byte from the attached SPI device.
*/
static inline uint8_t SPI_TransferByte(const uint8_t Byte) ATTR_ALWAYS_INLINE;
static inline uint8_t SPI_TransferByte(const uint8_t Byte)
{
SPDR = Byte;
while (!(SPSR & (1 << SPIF)));
return SPDR;
}
/** Sends a byte through the SPI interface, blocking until the transfer is complete. The response
* byte sent to from the attached SPI device is ignored.
*
* \param[in] Byte Byte to send through the SPI interface.
*/
static inline void SPI_SendByte(const uint8_t Byte) ATTR_ALWAYS_INLINE;
static inline void SPI_SendByte(const uint8_t Byte)
{
SPDR = Byte;
while (!(SPSR & (1 << SPIF)));
}
/** Sends a dummy byte through the SPI interface, blocking until the transfer is complete. The response
* byte from the attached SPI device is returned.
*
* \return The response byte from the attached SPI device.
*/
static inline uint8_t SPI_ReceiveByte(void) ATTR_ALWAYS_INLINE ATTR_WARN_UNUSED_RESULT;
static inline uint8_t SPI_ReceiveByte(void)
{
SPDR = 0x00;
while (!(SPSR & (1 << SPIF)));
return SPDR;
}
/* Disable C linkage for C++ Compilers: */
#if defined(__cplusplus)
}
#endif
#endif
/** @} */

View file

@ -0,0 +1,89 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2011.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2011 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, 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.
*/
#define __INCLUDE_FROM_SERIAL_C
#include "Serial.h"
FILE USARTSerialStream;
int Serial_putchar(char DataByte,
FILE *Stream)
{
(void)Stream;
Serial_SendByte(DataByte);
return 0;
}
int Serial_getchar(FILE *Stream)
{
(void)Stream;
if (!(Serial_IsCharReceived()))
return _FDEV_EOF;
return Serial_ReceiveByte();
}
int Serial_getchar_Blocking(FILE *Stream)
{
(void)Stream;
while (!(Serial_IsCharReceived()));
return Serial_ReceiveByte();
}
void Serial_SendString_P(const char* FlashStringPtr)
{
uint8_t CurrByte;
while ((CurrByte = pgm_read_byte(FlashStringPtr)) != 0x00)
{
Serial_SendByte(CurrByte);
FlashStringPtr++;
}
}
void Serial_SendString(const char* StringPtr)
{
uint8_t CurrByte;
while ((CurrByte = *StringPtr) != 0x00)
{
Serial_SendByte(CurrByte);
StringPtr++;
}
}
void Serial_SendData(const uint8_t* Buffer, uint16_t Length)
{
while (Length--)
Serial_SendByte(*(Buffer++));
}

View file

@ -0,0 +1,251 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2011.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2011 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, 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
* \brief Serial USART Peripheral Driver (AVR8)
*
* On-chip serial USART driver for the 8-bit AVR microcontrollers.
*
* \note This file should not be included directly. It is automatically included as needed by the USART driver
* dispatch header located in LUFA/Drivers/Peripheral/Serial.h.
*/
/** \ingroup Group_Serial
* \defgroup Group_Serial_AVR8 Serial USART Peripheral Driver (AVR8)
*
* \section Sec_ModDescription Module Description
* On-chip serial USART driver for the 8-bit AVR microcontrollers.
*
* \note This file should not be included directly. It is automatically included as needed by the ADC driver
* dispatch header located in LUFA/Drivers/Peripheral/Serial.h.
*
* \section Sec_ExampleUsage Example Usage
* The following snippet is an example of how this module may be used within a typical
* application.
*
* \code
* // Initialise the serial USART driver before first use, with 9600 baud (and no double-speed mode)
* Serial_Init(9600, false);
*
* // Send a string through the USART
* Serial_TxString("Test String\r\n");
*
* // Receive a byte through the USART
* uint8_t DataByte = Serial_RxByte();
* \endcode
*
* @{
*/
#ifndef __SERIAL_AVR8_H__
#define __SERIAL_AVR8_H__
/* Includes: */
#include "../../../Common/Common.h"
#include "../../Misc/TerminalCodes.h"
#include <stdio.h>
/* Enable C linkage for C++ Compilers: */
#if defined(__cplusplus)
extern "C" {
#endif
/* Preprocessor Checks: */
#if !defined(__INCLUDE_FROM_SERIAL_H) && !defined(__INCLUDE_FROM_SERIAL_C)
#error Do not include this file directly. Include LUFA/Drivers/Peripheral/Serial.h instead.
#endif
/* Private Interface - For use in library only: */
#if !defined(__DOXYGEN__)
/* External Variables: */
extern FILE USARTSerialStream;
/* Function Prototypes: */
int Serial_putchar(char DataByte,
FILE *Stream);
int Serial_getchar(FILE *Stream);
int Serial_getchar_Blocking(FILE *Stream);
#endif
/* Public Interface - May be used in end-application: */
/* Macros: */
/** Macro for calculating the baud value from a given baud rate when the U2X (double speed) bit is
* not set.
*/
#define SERIAL_UBBRVAL(baud) ((((F_CPU / 16) + (baud / 2)) / (baud)) - 1)
/** Macro for calculating the baud value from a given baud rate when the U2X (double speed) bit is
* set.
*/
#define SERIAL_2X_UBBRVAL(baud) ((((F_CPU / 8) + (baud / 2)) / (baud)) - 1)
/* Function Prototypes: */
/** Transmits a given string located in program space (FLASH) through the USART.
*
* \param[in] FlashStringPtr Pointer to a string located in program space.
*/
void Serial_SendString_P(const char* FlashStringPtr) ATTR_NON_NULL_PTR_ARG(1);
/** Transmits a given string located in SRAM memory through the USART.
*
* \param[in] StringPtr Pointer to a string located in SRAM space.
*/
void Serial_SendString(const char* StringPtr) ATTR_NON_NULL_PTR_ARG(1);
/** Transmits a given buffer located in SRAM memory through the USART.
*
* \param[in] Buffer Pointer to a buffer containing the data to send.
* \param[in] Length Length of the data to send, in bytes.
*/
void Serial_SendData(const uint8_t* Buffer, uint16_t Length) ATTR_NON_NULL_PTR_ARG(1);
/* Inline Functions: */
/** Initializes the USART, ready for serial data transmission and reception. This initializes the interface to
* standard 8-bit, no parity, 1 stop bit settings suitable for most applications.
*
* \param[in] BaudRate Serial baud rate, in bits per second.
* \param[in] DoubleSpeed Enables double speed mode when set, halving the sample time to double the baud rate.
*/
static inline void Serial_Init(const uint32_t BaudRate,
const bool DoubleSpeed)
{
UBRR1 = (DoubleSpeed ? SERIAL_2X_UBBRVAL(BaudRate) : SERIAL_UBBRVAL(BaudRate));
UCSR1C = ((1 << UCSZ11) | (1 << UCSZ10));
UCSR1A = (DoubleSpeed ? (1 << U2X1) : 0);
UCSR1B = ((1 << TXEN1) | (1 << RXEN1));
DDRD |= (1 << 3);
PORTD |= (1 << 2);
}
/** Turns off the USART driver, disabling and returning used hardware to their default configuration. */
static inline void Serial_Disable(void)
{
UCSR1B = 0;
UCSR1A = 0;
UCSR1C = 0;
UBRR1 = 0;
DDRD &= ~(1 << 3);
PORTD &= ~(1 << 2);
}
/** Creates a standard character stream from the USART so that it can be used with all the regular functions
* in the avr-libc \c <stdio.h> library that accept a \c FILE stream as a destination (e.g. \c fprintf). The created
* stream is bidirectional and can be used for both input and output functions.
*
* Reading data from this stream is non-blocking, i.e. in most instances, complete strings cannot be read in by a single
* fetch, as the endpoint will not be ready at some point in the transmission, aborting the transfer. However, this may
* be used when the read data is processed byte-per-bye (via \c getc()) or when the user application will implement its own
* line buffering.
*
* \param[in,out] Stream Pointer to a FILE structure where the created stream should be placed, if \c NULL stdio
* and stdin will be configured to use the USART.
*
* \pre The USART must first be configured via a call to \ref Serial_Init() before the stream is used.
*/
static inline void Serial_CreateStream(FILE* Stream)
{
if (!(Stream))
{
Stream = &USARTSerialStream;
stdin = Stream;
stdout = Stream;
}
*Stream = (FILE)FDEV_SETUP_STREAM(Serial_putchar, Serial_getchar, _FDEV_SETUP_RW);
}
/** Identical to \ref Serial_CreateStream(), except that reads are blocking until the calling stream function terminates
* the transfer.
*
* \param[in,out] Stream Pointer to a FILE structure where the created stream should be placed, if \c NULL stdio
* and stdin will be configured to use the USART.
*
* \pre The USART must first be configured via a call to \ref Serial_Init() before the stream is used.
*/
static inline void Serial_CreateBlockingStream(FILE* Stream)
{
if (!(Stream))
{
Stream = &USARTSerialStream;
stdin = Stream;
stdout = Stream;
}
*Stream = (FILE)FDEV_SETUP_STREAM(Serial_putchar, Serial_getchar_Blocking, _FDEV_SETUP_RW);
}
/** Indicates whether a character has been received through the USART.
*
* \return Boolean \c true if a character has been received, \c false otherwise.
*/
static inline bool Serial_IsCharReceived(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline bool Serial_IsCharReceived(void)
{
return ((UCSR1A & (1 << RXC1)) ? true : false);
}
/** Transmits a given byte through the USART.
*
* \param[in] DataByte Byte to transmit through the USART.
*/
static inline void Serial_SendByte(const char DataByte) ATTR_ALWAYS_INLINE;
static inline void Serial_SendByte(const char DataByte)
{
while (!(UCSR1A & (1 << UDRE1)));
UDR1 = DataByte;
}
/** Receives the next byte from the USART.
*
* \return Next byte received from the USART, or a negative value if no byte has been received.
*/
static inline int16_t Serial_ReceiveByte(void) ATTR_ALWAYS_INLINE;
static inline int16_t Serial_ReceiveByte(void)
{
if (!(Serial_IsCharReceived()))
return -1;
return UDR1;
}
/* Disable C linkage for C++ Compilers: */
#if defined(__cplusplus)
}
#endif
#endif
/** @} */

View file

@ -0,0 +1,144 @@
/*
Copyright (C) Dean Camera, 2011.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
#define __INCLUDE_FROM_TWI_C
#include "TWI.h"
uint8_t TWI_StartTransmission(const uint8_t SlaveAddress,
const uint8_t TimeoutMS)
{
for (;;)
{
bool BusCaptured = false;
uint16_t TimeoutRemaining;
TWCR = ((1 << TWINT) | (1 << TWSTA) | (1 << TWEN));
TimeoutRemaining = (TimeoutMS * 100);
while (TimeoutRemaining-- && !(BusCaptured))
{
if (TWCR & (1 << TWINT))
{
switch (TWSR & TW_STATUS_MASK)
{
case TW_START:
case TW_REP_START:
BusCaptured = true;
break;
case TW_MT_ARB_LOST:
TWCR = ((1 << TWINT) | (1 << TWSTA) | (1 << TWEN));
continue;
default:
TWCR = (1 << TWEN);
return TWI_ERROR_BusFault;
}
}
_delay_us(10);
}
if (!(TimeoutRemaining))
{
TWCR = (1 << TWEN);
return TWI_ERROR_BusCaptureTimeout;
}
TWDR = SlaveAddress;
TWCR = ((1 << TWINT) | (1 << TWEN));
TimeoutRemaining = (TimeoutMS * 100);
while (TimeoutRemaining--)
{
if (TWCR & (1 << TWINT))
break;
_delay_us(10);
}
if (!(TimeoutRemaining))
return TWI_ERROR_SlaveResponseTimeout;
switch (TWSR & TW_STATUS_MASK)
{
case TW_MT_SLA_ACK:
case TW_MR_SLA_ACK:
return TWI_ERROR_NoError;
default:
TWCR = ((1 << TWINT) | (1 << TWSTO) | (1 << TWEN));
return TWI_ERROR_SlaveNotReady;
}
}
}
uint8_t TWI_ReadPacket(const uint8_t SlaveAddress,
const uint8_t TimeoutMS,
const uint8_t* InternalAddress,
uint8_t InternalAddressLen,
uint8_t* Buffer,
uint8_t Length)
{
uint8_t ErrorCode;
if ((ErrorCode = TWI_WritePacket(SlaveAddress, TimeoutMS, InternalAddress, InternalAddressLen,
NULL, 0)) != TWI_ERROR_NoError)
{
return ErrorCode;
}
if ((ErrorCode = TWI_StartTransmission((SlaveAddress & TWI_DEVICE_ADDRESS_MASK) | TWI_ADDRESS_READ,
TimeoutMS)) == TWI_ERROR_NoError)
{
while (Length--)
{
if (!(TWI_ReceiveByte(Buffer++, (Length == 0))))
{
ErrorCode = TWI_ERROR_SlaveNAK;
break;
}
}
TWI_StopTransmission();
}
return ErrorCode;
}
uint8_t TWI_WritePacket(const uint8_t SlaveAddress,
const uint8_t TimeoutMS,
const uint8_t* InternalAddress,
uint8_t InternalAddressLen,
const uint8_t* Buffer,
uint8_t Length)
{
uint8_t ErrorCode;
if ((ErrorCode = TWI_StartTransmission((SlaveAddress & TWI_DEVICE_ADDRESS_MASK) | TWI_ADDRESS_WRITE,
TimeoutMS)) == TWI_ERROR_NoError)
{
while (InternalAddressLen--)
{
if (!(TWI_SendByte(*(InternalAddress++))))
{
ErrorCode = TWI_ERROR_SlaveNAK;
break;
}
}
while (Length--)
{
if (!(TWI_SendByte(*(Buffer++))))
{
ErrorCode = TWI_ERROR_SlaveNAK;
break;
}
}
TWI_StopTransmission();
}
return ErrorCode;
}

View file

@ -0,0 +1,286 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2011.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2011 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, 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
* \brief TWI Peripheral Driver (AVR8)
*
* On-chip TWI driver for the 8-bit AVR microcontrollers.
*
* \note This file should not be included directly. It is automatically included as needed by the TWI driver
* dispatch header located in LUFA/Drivers/Peripheral/TWI.h.
*/
/** \ingroup Group_TWI
* \defgroup Group_TWI_AVR8 TWI Peripheral Driver (AVR8)
*
* \section Sec_ModDescription Module Description
* Master mode TWI driver for the 8-bit AVR microcontrollers which contain a hardware TWI module.
*
* \note This file should not be included directly. It is automatically included as needed by the TWI driver
* dispatch header located in LUFA/Drivers/Peripheral/TWI.h.
*
* \section Sec_ExampleUsage Example Usage
* The following snippet is an example of how this module may be used within a typical
* application.
*
* <b>Low Level API Example:</b>
* \code
* // Initialise the TWI driver before first use
* TWI_Init();
*
* // Start a write session to device at device address 0xA0, internal address 0xDC with a 10ms timeout
* if (TWI_StartTransmission(0xA0 | TWI_ADDRESS_WRITE, 10))
* {
* TWI_SendByte(0xDC);
*
* TWI_SendByte(0x01);
* TWI_SendByte(0x02);
* TWI_SendByte(0x03);
*
* // Must stop transmission afterwards to release the bus
* TWI_StopTransmission();
* }
*
* // Start a read session to device at address 0xA0, internal address 0xDC with a 10ms timeout
* if (TWI_StartTransmission(0xA0 | TWI_ADDRESS_WRITE, 10))
* {
* TWI_SendByte(0xDC);
* TWI_StopTransmission();
*
* if (TWI_StartTransmission(0xA0 | TWI_ADDRESS_READ, 10))
* {
* uint8_t Byte1, Byte2, Byte3;
*
* // Read three bytes, acknowledge after the third byte is received
* TWI_ReceiveByte(&Byte1, false);
* TWI_ReceiveByte(&Byte2, false);
* TWI_ReceiveByte(&Byte3, true);
*
* // Must stop transmission afterwards to release the bus
* TWI_StopTransmission();
* }
* }
* \endcode
*
* <b>High Level API Example:</b>
* \code
* // Initialise the TWI driver before first use
* TWI_Init();
*
* // Start a write session to device at device address 0xA0, internal address 0xDC with a 10ms timeout
* uint8_t InternalWriteAddress = 0xDC;
* uint8_t WritePacket[3] = {0x01, 0x02, 0x03};
*
* TWI_WritePacket(0xA0, 10, &InternalWriteAddress, sizeof(InternalWriteAddress),
* &WritePacket, sizeof(WritePacket);
*
* // Start a read session to device at address 0xA0, internal address 0xDC with a 10ms timeout
* uint8_t InternalReadAddress = 0xDC;
* uint8_t ReadPacket[3];
*
* TWI_ReadPacket(0xA0, 10, &InternalReadAddress, sizeof(InternalReadAddress),
* &ReadPacket, sizeof(ReadPacket);
* \endcode
*
* @{
*/
#ifndef __TWI_AVR8_H__
#define __TWI_AVR8_H__
/* Includes: */
#include "../../../Common/Common.h"
#include <stdio.h>
#include <util/twi.h>
/* Enable C linkage for C++ Compilers: */
#if defined(__cplusplus)
extern "C" {
#endif
/* Preprocessor Checks: */
#if !defined(__INCLUDE_FROM_TWI_H) && !defined(__INCLUDE_FROM_TWI_C)
#error Do not include this file directly. Include LUFA/Drivers/Peripheral/TWI.h instead.
#endif
#if !(defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB646__) || \
defined(__AVR_AT90USB1287__) || defined(__AVR_AT90USB647__) || \
defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__) || \
defined(__AVR_ATmega32U6__))
#error The TWI peripheral driver is not currently available for your selected microcontroller model.
#endif
/* Public Interface - May be used in end-application: */
/* Macros: */
/** TWI slave device address mask for a read session. Mask with a slave device base address to obtain
* the correct TWI bus address for the slave device when reading data from it.
*/
#define TWI_ADDRESS_READ 0x00
/** TWI slave device address mask for a write session. Mask with a slave device base address to obtain
* the correct TWI bus address for the slave device when writing data to it.
*/
#define TWI_ADDRESS_WRITE 0x01
/** Mask to retrieve the base address for a TWI device, which can then be ORed with \ref TWI_ADDRESS_READ
* or \ref TWI_ADDRESS_WRITE to obtain the device's read and write address respectively.
*/
#define TWI_DEVICE_ADDRESS_MASK 0xFE
/* Enums: */
/** Enum for the possible return codes of the TWI transfer start routine and other dependant TWI functions. */
enum TWI_ErrorCodes_t
{
TWI_ERROR_NoError = 0, /**< Indicates that the command completed sucessfully. */
TWI_ERROR_BusFault = 1, /**< A TWI bus fault occurred while attempting to capture the bus. */
TWI_ERROR_BusCaptureTimeout = 2, /**< A timeout occurred whilst waiting for the bus to be ready. */
TWI_ERROR_SlaveResponseTimeout = 3, /**< No ACK received at the nominated slave address within the timeout period. */
TWI_ERROR_SlaveNotReady = 4, /**< Slave NAKed the TWI bus START condition. */
TWI_ERROR_SlaveNAK = 5, /**< Slave NAKed whilst attempting to send data to the device. */
};
/* Inline Functions: */
/** Initialises the TWI hardware into master mode, ready for data transmission and reception. This must be
* before any other TWI operations.
*/
static inline void TWI_Init(void) ATTR_ALWAYS_INLINE;
static inline void TWI_Init(void)
{
TWCR |= (1 << TWEN);
}
/** Turns off the TWI driver hardware. If this is called, any further TWI operations will require a call to
* \ref TWI_Init() before the TWI can be used again.
*/
static inline void TWI_Disable(void) ATTR_ALWAYS_INLINE;
static inline void TWI_Disable(void)
{
TWCR &= ~(1 << TWEN);
}
/** Sends a TWI STOP onto the TWI bus, terminating communication with the currently addressed device. */
static inline void TWI_StopTransmission(void) ATTR_ALWAYS_INLINE;
static inline void TWI_StopTransmission(void)
{
TWCR = ((1 << TWINT) | (1 << TWSTO) | (1 << TWEN));
}
/** Sends a byte to the currently addressed device on the TWI bus.
*
* \param[in] Byte Byte to send to the currently addressed device
*
* \return Boolean \c true if the recipient ACKed the byte, \c false otherwise
*/
static inline bool TWI_SendByte(const uint8_t Byte)
{
TWDR = Byte;
TWCR = ((1 << TWINT) | (1 << TWEN));
while (!(TWCR & (1 << TWINT)));
return ((TWSR & TW_STATUS_MASK) == TW_MT_DATA_ACK);
}
/** Receives a byte from the currently addressed device on the TWI bus.
*
* \param[in] Byte Location where the read byte is to be stored
* \param[in] LastByte Indicates if the byte should be ACKed if false, NAKed if true
*
* \return Boolean \c true if the byte reception successfully completed, \c false otherwise
*/
static inline uint8_t TWI_ReceiveByte(uint8_t* const Byte,
const bool LastByte)
{
uint8_t TWCRMask = ((1 << TWINT) | (1 << TWEN));
if (!(LastByte))
TWCRMask |= (1 << TWEA);
TWCR = TWCRMask;
while (!(TWCR & (1 << TWINT)));
*Byte = TWDR;
return ((TWSR & TW_STATUS_MASK) == TW_MR_DATA_ACK);
}
/* Function Prototypes: */
/** Begins a master mode TWI bus communication with the given slave device address.
*
* \param[in] SlaveAddress Address of the slave TWI device to communicate with
* \param[in] TimeoutMS Timeout period within which the slave must respond, in milliseconds
*
* \return A value from the \ref TWI_ErrorCodes_t enum
*/
uint8_t TWI_StartTransmission(const uint8_t SlaveAddress,
const uint8_t TimeoutMS);
/** High level function to perform a complete packet transfer over the TWI bus to the specified
* device.
*
* \param[in] SlaveAddress Base address of the TWI slave device to communicate with
* \param[in] TimeoutMS Timeout for bus capture and slave START ACK, in milliseconds
* \param[in] InternalAddress Pointer to a location where the internal slave read start address is stored
* \param[in] InternalAddressLen Size of the internal device address, in bytes
* \param[in] Buffer Pointer to a buffer where the read packet data is to be stored
* \param[in] Length Size of the packet to read, in bytes
*/
uint8_t TWI_ReadPacket(const uint8_t SlaveAddress,
const uint8_t TimeoutMS,
const uint8_t* InternalAddress,
uint8_t InternalAddressLen,
uint8_t* Buffer,
uint8_t Length);
/** High level function to perform a complete packet transfer over the TWI bus from the specified
* device.
*
* \param[in] SlaveAddress Base address of the TWI slave device to communicate with
* \param[in] TimeoutMS Timeout for bus capture and slave START ACK, in milliseconds
* \param[in] InternalAddress Pointer to a location where the internal slave write start address is stored
* \param[in] InternalAddressLen Size of the internal device address, in bytes
* \param[in] Buffer Pointer to a buffer where the packet data to send is stored
* \param[in] Length Size of the packet to send, in bytes
*/
uint8_t TWI_WritePacket(const uint8_t SlaveAddress,
const uint8_t TimeoutMS,
const uint8_t* InternalAddress,
uint8_t InternalAddressLen,
const uint8_t* Buffer,
uint8_t Length);
/* Disable C linkage for C++ Compilers: */
#if defined(__cplusplus)
}
#endif
#endif
/** @} */

View file

@ -67,7 +67,7 @@
/* Includes: */
#if (ARCH == ARCH_AVR8)
#include "AVR8/SPI.h"
#include "AVR8/SPI_AVR8.h"
#else
#error The SPI peripheral driver is not currently available for your selected architecture.
#endif

View file

@ -44,7 +44,7 @@
*
* \section Sec_Dependencies Module Source Dependencies
* The following files must be built with any user project that uses this module:
* - LUFA/Drivers/Peripheral/<i>ARCH</i>/Serial.c <i>(Makefile source module name: LUFA_SRC_SERIAL)</i>
* - LUFA/Drivers/Peripheral/<i>ARCH</i>/Serial_<i>ARCH</i>.c <i>(Makefile source module name: LUFA_SRC_SERIAL)</i>
*
* \section Sec_ModDescription Module Description
* Hardware serial USART driver. This module provides an easy to use driver for the setup and transfer
@ -67,7 +67,7 @@
/* Includes: */
#if (ARCH == ARCH_AVR8)
#include "AVR8/Serial.h"
#include "AVR8/Serial_AVR8.h"
#else
#error The Serial peripheral driver is not currently available for your selected architecture.
#endif

View file

@ -44,7 +44,7 @@
*
* \section Sec_Dependencies Module Source Dependencies
* The following files must be built with any user project that uses this module:
* - LUFA/Drivers/Peripheral/<i>ARCH</i>/TWI.c <i>(Makefile source module name: LUFA_SRC_TWI)</i>
* - LUFA/Drivers/Peripheral/<i>ARCH</i>/TWI_<i>ARCH</i>.c <i>(Makefile source module name: LUFA_SRC_TWI)</i>
*
* \section Sec_ModDescription Module Description
* Hardware TWI driver. This module provides an easy to use driver for the setup and transfer of data over
@ -67,7 +67,7 @@
/* Includes: */
#if (ARCH == ARCH_AVR8)
#include "AVR8/TWI.h"
#include "AVR8/TWI_AVR8.h"
#else
#error The TWI peripheral driver is not currently available for your selected architecture.
#endif

View file

@ -0,0 +1,53 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2011.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2011 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, 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.
*/
#define __INCLUDE_FROM_USB_DRIVER
#include "../USBMode.h"
#if defined(USB_CAN_BE_DEVICE)
#include "../Device.h"
void USB_Device_SendRemoteWakeup(void)
{
if (!(USB_Options & USB_OPT_MANUAL_PLL))
{
USB_PLL_On();
while (!(USB_PLL_IsReady()));
}
USB_CLK_Unfreeze();
UDCON |= (1 << RMWKUP);
while (!(UDCON & (1 << RMWKUP)));
}
#endif

View file

@ -0,0 +1,258 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2011.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2011 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, 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
* \brief USB Device definitions for the AVR8 microcontrollers.
* \copydetails Group_Device_AVR8
*
* \note This file should not be included directly. It is automatically included as needed by the USB driver
* dispatch header located in LUFA/Drivers/USB/USB.h.
*/
/** \ingroup Group_Device
* \defgroup Group_Device_AVR8 Device Management (AVR8)
* \brief USB Device definitions for the AVR8 microcontrollers.
*
* Architecture specific USB Device definitions for the Atmel 8-bit AVR microcontrollers.
*
* @{
*/
#ifndef __USBDEVICE_AVR8_H__
#define __USBDEVICE_AVR8_H__
/* Includes: */
#include "../../../../Common/Common.h"
#include "../StdDescriptors.h"
#include "../USBInterrupt.h"
#include "../Endpoint.h"
/* Preprocessor Checks: */
#if !defined(__INCLUDE_FROM_USB_DRIVER)
#error Do not include this file directly. Include LUFA/Drivers/USB/USB.h instead.
#endif
#if (defined(USE_RAM_DESCRIPTORS) && defined(USE_EEPROM_DESCRIPTORS))
#error USE_RAM_DESCRIPTORS and USE_EEPROM_DESCRIPTORS are mutually exclusive.
#endif
/* Public Interface - May be used in end-application: */
/* Macros: */
/** \name USB Device Mode Option Masks */
//@{
#if defined(USB_SERIES_4_AVR) || defined(USB_SERIES_6_AVR) || defined(USB_SERIES_7_AVR) || defined(__DOXYGEN__)
/** Mask for the Options parameter of the \ref USB_Init() function. This indicates that the
* USB interface should be initialized in low speed (1.5Mb/s) mode.
*
* \note Low Speed mode is not available on all USB AVR models.
* \n
*
* \note Restrictions apply on the number, size and type of endpoints which can be used
* when running in low speed mode - refer to the USB 2.0 specification.
*/
#define USB_DEVICE_OPT_LOWSPEED (1 << 0)
#endif
/** Mask for the Options parameter of the \ref USB_Init() function. This indicates that the
* USB interface should be initialized in full speed (12Mb/s) mode.
*/
#define USB_DEVICE_OPT_FULLSPEED (0 << 0)
//@}
#if (!defined(NO_INTERNAL_SERIAL) && \
(defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1287__) || \
defined(__AVR_ATmega32U6__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) || \
defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega8U2__)))
/** String descriptor index for the device's unique serial number string descriptor within the device.
* This unique serial number is used by the host to associate resources to the device (such as drivers or COM port
* number allocations) to a device regardless of the port it is plugged in to on the host. Some USB AVRs contain
* a unique serial number internally, and setting the device descriptors serial number string index to this value
* will cause it to use the internal serial number.
*
* On unsupported devices, this will evaluate to NO_DESCRIPTOR and so will force the host to create a pseudo-serial
* number for the device.
*/
#define USE_INTERNAL_SERIAL 0xDC
#else
#define USE_INTERNAL_SERIAL NO_DESCRIPTOR
#endif
/* Function Prototypes: */
/** Sends a Remote Wakeup request to the host. This signals to the host that the device should
* be taken out of suspended mode, and communications should resume.
*
* Typically, this is implemented so that HID devices (mice, keyboards, etc.) can wake up the
* host computer when the host has suspended all USB devices to enter a low power state.
*
* \note This macro should only be used if the device has indicated to the host that it
* supports the Remote Wakeup feature in the device descriptors, and should only be
* issued if the host is currently allowing remote wakeup events from the device (i.e.,
* the \ref USB_RemoteWakeupEnabled flag is set). When the \c NO_DEVICE_REMOTE_WAKEUP compile
* time option is used, this macro is unavailable.
* \n\n
*
* \note The USB clock must be running for this function to operate. If the stack is initialized with
* the \ref USB_OPT_MANUAL_PLL option enabled, the user must ensure that the PLL is running
* before attempting to call this function.
*
* \see \ref Group_StdDescriptors for more information on the RMWAKEUP feature and device descriptors.
*/
void USB_Device_SendRemoteWakeup(void);
/* Type Defines: */
enum USB_Device_States_t
{
DEVICE_STATE_Unattached = 0, /**< Internally implemented by the library. This state indicates
* that the device is not currently connected to a host.
*/
DEVICE_STATE_Powered = 1, /**< Internally implemented by the library. This state indicates
* that the device is connected to a host, but enumeration has not
* yet begun.
*/
DEVICE_STATE_Default = 2, /**< Internally implemented by the library. This state indicates
* that the device's USB bus has been reset by the host and it is
* now waiting for the host to begin the enumeration process.
*/
DEVICE_STATE_Addressed = 3, /**< Internally implemented by the library. This state indicates
* that the device has been addressed by the USB Host, but is not
* yet configured.
*/
DEVICE_STATE_Configured = 4, /**< May be implemented by the user project. This state indicates
* that the device has been enumerated by the host and is ready
* for USB communications to begin.
*/
DEVICE_STATE_Suspended = 5, /**< May be implemented by the user project. This state indicates
* that the USB bus has been suspended by the host, and the device
* should power down to a minimal power level until the bus is
* resumed.
*/
};
/* Inline Functions: */
/** Returns the current USB frame number, when in device mode. Every millisecond the USB bus is active (i.e. enumerated to a host)
* the frame number is incremented by one.
*/
static inline uint16_t USB_Device_GetFrameNumber(void)
{
return UDFNUM;
}
#if !defined(NO_SOF_EVENTS)
/** Enables the device mode Start Of Frame events. When enabled, this causes the
* \ref EVENT_USB_Device_StartOfFrame() event to fire once per millisecond, synchronized to the USB bus,
* at the start of each USB frame when enumerated in device mode.
*
* \note Not available when the \c NO_SOF_EVENTS compile time token is defined.
*/
static inline void USB_Device_EnableSOFEvents(void) ATTR_ALWAYS_INLINE;
static inline void USB_Device_EnableSOFEvents(void)
{
USB_INT_Enable(USB_INT_SOFI);
}
/** Disables the device mode Start Of Frame events. When disabled, this stops the firing of the
* \ref EVENT_USB_Device_StartOfFrame() event when enumerated in device mode.
*
* \note Not available when the \c NO_SOF_EVENTS compile time token is defined.
*/
static inline void USB_Device_DisableSOFEvents(void) ATTR_ALWAYS_INLINE;
static inline void USB_Device_DisableSOFEvents(void)
{
USB_INT_Disable(USB_INT_SOFI);
}
#endif
/* Private Interface - For use in library only: */
#if !defined(__DOXYGEN__)
/* Inline Functions: */
#if (defined(USB_SERIES_4_AVR) || defined(USB_SERIES_6_AVR) || defined(USB_SERIES_7_AVR))
static inline void USB_Device_SetLowSpeed(void) ATTR_ALWAYS_INLINE;
static inline void USB_Device_SetLowSpeed(void)
{
UDCON |= (1 << LSM);
}
static inline void USB_Device_SetFullSpeed(void) ATTR_ALWAYS_INLINE;
static inline void USB_Device_SetFullSpeed(void)
{
UDCON &= ~(1 << LSM);
}
#endif
static inline void USB_Device_SetDeviceAddress(const uint8_t Address) ATTR_ALWAYS_INLINE;
static inline void USB_Device_SetDeviceAddress(const uint8_t Address)
{
UDADDR = ((UDADDR & (1 << ADDEN)) | (Address & 0x7F));
UDADDR |= (1 << ADDEN);
}
static inline bool USB_Device_IsAddressSet(void) ATTR_ALWAYS_INLINE;
static inline bool USB_Device_IsAddressSet(void)
{
return (UDADDR & (1 << ADDEN));
}
static inline uint8_t USB_Device_GetSerialString(wchar_t* UnicodeString, const uint8_t MaxLen)
{
uint8_t SerialCharNum = 0;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
uint8_t SigReadAddress = 0x0E;
for (SerialCharNum = 0; SerialCharNum < MIN(MaxLen, 20); SerialCharNum++)
{
if (SerialCharNum == MaxLen)
break;
uint8_t SerialByte = boot_signature_byte_get(SigReadAddress);
if (SerialCharNum & 0x01)
{
SerialByte >>= 4;
SigReadAddress++;
}
SerialByte &= 0x0F;
UnicodeString[SerialCharNum] = (SerialByte >= 10) ?
(('A' - 10) + SerialByte) : ('0' + SerialByte);
}
}
return SerialCharNum;
}
#endif
#endif
/** @} */

View file

@ -0,0 +1,182 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2011.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2011 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, 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.
*/
#define __INCLUDE_FROM_USB_DRIVER
#include "../USBMode.h"
#if defined(USB_CAN_BE_DEVICE)
#include "../Endpoint.h"
#if !defined(FIXED_CONTROL_ENDPOINT_SIZE)
uint8_t USB_ControlEndpointSize = ENDPOINT_CONTROLEP_DEFAULT_SIZE;
#endif
bool Endpoint_ConfigureEndpoint_Prv(const uint8_t Number,
const uint8_t UECFG0XData,
const uint8_t UECFG1XData)
{
#if defined(CONTROL_ONLY_DEVICE) || defined(ORDERED_EP_CONFIG)
Endpoint_SelectEndpoint(Number);
Endpoint_EnableEndpoint();
UECFG1X = 0;
UECFG0X = UECFG0XData;
UECFG1X = UECFG1XData;
return Endpoint_IsConfigured();
#else
for (uint8_t EPNum = Number; EPNum < ENDPOINT_TOTAL_ENDPOINTS; EPNum++)
{
uint8_t UECFG0XTemp;
uint8_t UECFG1XTemp;
uint8_t UEIENXTemp;
Endpoint_SelectEndpoint(EPNum);
if (EPNum == Number)
{
UECFG0XTemp = UECFG0XData;
UECFG1XTemp = UECFG1XData;
UEIENXTemp = 0;
}
else
{
UECFG0XTemp = UECFG0X;
UECFG1XTemp = UECFG1X;
UEIENXTemp = UEIENX;
}
if (!(UECFG1XTemp & (1 << ALLOC)))
continue;
Endpoint_DisableEndpoint();
UECFG1X &= (1 << ALLOC);
Endpoint_EnableEndpoint();
UECFG0X = UECFG0XTemp;
UECFG1X = UECFG1XTemp;
UEIENX = UEIENXTemp;
if (!(Endpoint_IsConfigured()))
return false;
}
Endpoint_SelectEndpoint(Number);
return true;
#endif
}
void Endpoint_ClearEndpoints(void)
{
UEINT = 0;
for (uint8_t EPNum = 0; EPNum < ENDPOINT_TOTAL_ENDPOINTS; EPNum++)
{
Endpoint_SelectEndpoint(EPNum);
UEIENX = 0;
UEINTX = 0;
UECFG1X = 0;
Endpoint_DisableEndpoint();
}
}
void Endpoint_ClearStatusStage(void)
{
if (USB_ControlRequest.bmRequestType & REQDIR_DEVICETOHOST)
{
while (!(Endpoint_IsOUTReceived()))
{
if (USB_DeviceState == DEVICE_STATE_Unattached)
return;
}
Endpoint_ClearOUT();
}
else
{
while (!(Endpoint_IsINReady()))
{
if (USB_DeviceState == DEVICE_STATE_Unattached)
return;
}
Endpoint_ClearIN();
}
}
#if !defined(CONTROL_ONLY_DEVICE)
uint8_t Endpoint_WaitUntilReady(void)
{
#if (USB_STREAM_TIMEOUT_MS < 0xFF)
uint8_t TimeoutMSRem = USB_STREAM_TIMEOUT_MS;
#else
uint16_t TimeoutMSRem = USB_STREAM_TIMEOUT_MS;
#endif
uint16_t PreviousFrameNumber = USB_Device_GetFrameNumber();
for (;;)
{
if (Endpoint_GetEndpointDirection() == ENDPOINT_DIR_IN)
{
if (Endpoint_IsINReady())
return ENDPOINT_READYWAIT_NoError;
}
else
{
if (Endpoint_IsOUTReceived())
return ENDPOINT_READYWAIT_NoError;
}
uint8_t USB_DeviceState_LCL = USB_DeviceState;
if (USB_DeviceState_LCL == DEVICE_STATE_Unattached)
return ENDPOINT_READYWAIT_DeviceDisconnected;
else if (USB_DeviceState_LCL == DEVICE_STATE_Suspended)
return ENDPOINT_READYWAIT_BusSuspended;
else if (Endpoint_IsStalled())
return ENDPOINT_READYWAIT_EndpointStalled;
uint16_t CurrentFrameNumber = USB_Device_GetFrameNumber();
if (CurrentFrameNumber != PreviousFrameNumber)
{
PreviousFrameNumber = CurrentFrameNumber;
if (!(TimeoutMSRem--))
return ENDPOINT_READYWAIT_Timeout;
}
}
}
#endif
#endif

View file

@ -0,0 +1,894 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2011.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2011 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, 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
* \brief USB Endpoint definitions for the AVR8 microcontrollers.
* \copydetails Group_EndpointManagement_AVR8
*
* \note This file should not be included directly. It is automatically included as needed by the USB driver
* dispatch header located in LUFA/Drivers/USB/USB.h.
*/
/** \ingroup Group_EndpointRW
* \defgroup Group_EndpointRW_AVR8 Endpoint Data Reading and Writing (AVR8)
* \brief Endpoint data read/write definitions for the Atmel AVR8 architecture.
*
* Functions, macros, variables, enums and types related to data reading and writing from and to endpoints.
*/
/** \ingroup Group_EndpointPrimitiveRW
* \defgroup Group_EndpointPrimitiveRW_AVR8 Read/Write of Primitive Data Types (AVR8)
* \brief Endpoint primative read/write definitions for the Atmel AVR8 architecture.
*
* Functions, macros, variables, enums and types related to data reading and writing of primitive data types
* from and to endpoints.
*/
/** \ingroup Group_EndpointPacketManagement
* \defgroup Group_EndpointPacketManagement_AVR8 Endpoint Packet Management (AVR8)
* \brief Endpoint packet management definitions for the Atmel AVR8 architecture.
*
* Functions, macros, variables, enums and types related to packet management of endpoints.
*/
/** \ingroup Group_EndpointManagement
* \defgroup Group_EndpointManagement_AVR8 Endpoint Management (AVR8)
* \brief Endpoint management definitions for the Atmel AVR8 architecture.
*
* Functions, macros and enums related to endpoint management when in USB Device mode. This
* module contains the endpoint management macros, as well as endpoint interrupt and data
* send/receive functions for various data types.
*
* @{
*/
#ifndef __ENDPOINT_AVR8_H__
#define __ENDPOINT_AVR8_H__
/* Includes: */
#include "../../../../Common/Common.h"
#include "../USBTask.h"
#include "../USBInterrupt.h"
/* Enable C linkage for C++ Compilers: */
#if defined(__cplusplus)
extern "C" {
#endif
/* Preprocessor Checks: */
#if !defined(__INCLUDE_FROM_USB_DRIVER)
#error Do not include this file directly. Include LUFA/Drivers/USB/USB.h instead.
#endif
/* Private Interface - For use in library only: */
#if !defined(__DOXYGEN__)
/* Macros: */
#define _ENDPOINT_GET_MAXSIZE(EPIndex) _ENDPOINT_GET_MAXSIZE2(ENDPOINT_DETAILS_EP ## EPIndex)
#define _ENDPOINT_GET_MAXSIZE2(EPDetails) _ENDPOINT_GET_MAXSIZE3(EPDetails)
#define _ENDPOINT_GET_MAXSIZE3(MaxSize, Banks) (MaxSize)
#define _ENDPOINT_GET_BANKS(EPIndex) _ENDPOINT_GET_BANKS2(ENDPOINT_DETAILS_EP ## EPIndex)
#define _ENDPOINT_GET_BANKS2(EPDetails) _ENDPOINT_GET_BANKS3(EPDetails)
#define _ENDPOINT_GET_BANKS3(MaxSize, Banks) (Banks)
#if defined(USB_SERIES_4_AVR) || defined(USB_SERIES_6_AVR) || defined(USB_SERIES_7_AVR)
#define ENDPOINT_DETAILS_MAXEP 7
#define ENDPOINT_DETAILS_EP0 64, 2
#define ENDPOINT_DETAILS_EP1 256, 2
#define ENDPOINT_DETAILS_EP2 64, 2
#define ENDPOINT_DETAILS_EP3 64, 2
#define ENDPOINT_DETAILS_EP4 64, 2
#define ENDPOINT_DETAILS_EP5 64, 2
#define ENDPOINT_DETAILS_EP6 64, 2
#else
#define ENDPOINT_DETAILS_MAXEP 5
#define ENDPOINT_DETAILS_EP0 64, 2
#define ENDPOINT_DETAILS_EP1 64, 1
#define ENDPOINT_DETAILS_EP2 64, 1
#define ENDPOINT_DETAILS_EP3 64, 2
#define ENDPOINT_DETAILS_EP4 64, 2
#endif
/* Inline Functions: */
static inline uint8_t Endpoint_BytesToEPSizeMask(const uint16_t Bytes) ATTR_WARN_UNUSED_RESULT ATTR_CONST
ATTR_ALWAYS_INLINE;
static inline uint8_t Endpoint_BytesToEPSizeMask(const uint16_t Bytes)
{
uint8_t MaskVal = 0;
uint16_t CheckBytes = 8;
while (CheckBytes < Bytes)
{
MaskVal++;
CheckBytes <<= 1;
}
return (MaskVal << EPSIZE0);
}
/* Function Prototypes: */
void Endpoint_ClearEndpoints(void);
bool Endpoint_ConfigureEndpoint_Prv(const uint8_t Number,
const uint8_t UECFG0XData,
const uint8_t UECFG1XData);
#endif
/* Public Interface - May be used in end-application: */
/* Macros: */
/** \name Endpoint Direction Masks */
//@{
/** Endpoint data direction mask for \ref Endpoint_ConfigureEndpoint(). This indicates that the endpoint
* should be initialized in the OUT direction - i.e. data flows from host to device.
*/
#define ENDPOINT_DIR_OUT (0 << EPDIR)
/** Endpoint data direction mask for \ref Endpoint_ConfigureEndpoint(). This indicates that the endpoint
* should be initialized in the IN direction - i.e. data flows from device to host.
*/
#define ENDPOINT_DIR_IN (1 << EPDIR)
//@}
/** \name Endpoint Bank Mode Masks */
//@{
/** Mask for the bank mode selection for the \ref Endpoint_ConfigureEndpoint() macro. This indicates
* that the endpoint should have one single bank, which requires less USB FIFO memory but results
* in slower transfers as only one USB device (the AVR or the host) can access the endpoint's
* bank at the one time.
*/
#define ENDPOINT_BANK_SINGLE (0 << EPBK0)
/** Mask for the bank mode selection for the \ref Endpoint_ConfigureEndpoint() macro. This indicates
* that the endpoint should have two banks, which requires more USB FIFO memory but results
* in faster transfers as one USB device (the AVR or the host) can access one bank while the other
* accesses the second bank.
*/
#define ENDPOINT_BANK_DOUBLE (1 << EPBK0)
//@}
/** Endpoint address for the default control endpoint, which always resides in address 0. This is
* defined for convenience to give more readable code when used with the endpoint macros.
*/
#define ENDPOINT_CONTROLEP 0
#if (!defined(FIXED_CONTROL_ENDPOINT_SIZE) || defined(__DOXYGEN__))
/** Default size of the default control endpoint's bank, until altered by the control endpoint bank size
* value in the device descriptor. Not available if the \c FIXED_CONTROL_ENDPOINT_SIZE token is defined.
*/
#define ENDPOINT_CONTROLEP_DEFAULT_SIZE 8
#endif
/** Endpoint number mask, for masking against endpoint addresses to retrieve the endpoint's
* numerical address in the device.
*/
#define ENDPOINT_EPNUM_MASK 0x07
/** Endpoint direction mask, for masking against endpoint addresses to retrieve the endpoint's
* direction for comparing with the \c ENDPOINT_DESCRIPTOR_DIR_* masks.
*/
#define ENDPOINT_EPDIR_MASK 0x80
/** Retrives the maximum bank size in bytes of a given endpoint.
*
* \note This macro will only work correctly on endpoint indexes that are compile-time constants
* defined by the preprocessor.
*
* \param[in] EPIndex Endpoint number, a value between 0 and (\ref ENDPOINT_TOTAL_ENDPOINTS - 1)
*/
#define ENDPOINT_MAX_SIZE(EPIndex) _ENDPOINT_GET_MAXSIZE(EPIndex)
/** Retrieves the total number of banks supported by the given endpoint.
*
* \note This macro will only work correctly on endpoint indexes that are compile-time constants
* defined by the preprocessor.
*
* \param[in] EPIndex Endpoint number, a value between 0 and (\ref ENDPOINT_TOTAL_ENDPOINTS - 1)
*/
#define ENDPOINT_BANKS_SUPPORTED(EPIndex) _ENDPOINT_GET_BANKS(EPIndex)
#if !defined(CONTROL_ONLY_DEVICE) || defined(__DOXYGEN__)
/** Total number of endpoints (including the default control endpoint at address 0) which may
* be used in the device. Different USB AVR models support different amounts of endpoints,
* this value reflects the maximum number of endpoints for the currently selected AVR model.
*/
#define ENDPOINT_TOTAL_ENDPOINTS ENDPOINT_DETAILS_MAXEP
#else
#define ENDPOINT_TOTAL_ENDPOINTS 1
#endif
/* Enums: */
/** Enum for the possible error return codes of the \ref Endpoint_WaitUntilReady() function.
*
* \ingroup Group_EndpointRW_AVR8
*/
enum Endpoint_WaitUntilReady_ErrorCodes_t
{
ENDPOINT_READYWAIT_NoError = 0, /**< Endpoint is ready for next packet, no error. */
ENDPOINT_READYWAIT_EndpointStalled = 1, /**< The endpoint was stalled during the stream
* transfer by the host or device.
*/
ENDPOINT_READYWAIT_DeviceDisconnected = 2, /**< Device was disconnected from the host while
* waiting for the endpoint to become ready.
*/
ENDPOINT_READYWAIT_BusSuspended = 3, /**< The USB bus has been suspended by the host and
* no USB endpoint traffic can occur until the bus
* has resumed.
*/
ENDPOINT_READYWAIT_Timeout = 4, /**< The host failed to accept or send the next packet
* within the software timeout period set by the
* \ref USB_STREAM_TIMEOUT_MS macro.
*/
};
/* Inline Functions: */
/** Configures the specified endpoint number with the given endpoint type, direction, bank size
* and banking mode. Once configured, the endpoint may be read from or written to, depending
* on its direction.
*
* \param[in] Number Endpoint number to configure. This must be more than 0 and less than
* \ref ENDPOINT_TOTAL_ENDPOINTS.
*
* \param[in] Type Type of endpoint to configure, a \c EP_TYPE_* mask. Not all endpoint types
* are available on Low Speed USB devices - refer to the USB 2.0 specification.
*
* \param[in] Direction Endpoint data direction, either \ref ENDPOINT_DIR_OUT or \ref ENDPOINT_DIR_IN.
* All endpoints (except Control type) are unidirectional - data may only be read
* from or written to the endpoint bank based on its direction, not both.
*
* \param[in] Size Size of the endpoint's bank, where packets are stored before they are transmitted
* to the USB host, or after they have been received from the USB host (depending on
* the endpoint's data direction). The bank size must indicate the maximum packet size
* that the endpoint can handle.
*
* \param[in] Banks Number of banks to use for the endpoint being configured, an \c ENDPOINT_BANK_* mask.
* More banks uses more USB DPRAM, but offers better performance. Isochronous type
* endpoints <b>must</b> have at least two banks.
*
* \note When the \c ORDERED_EP_CONFIG compile time option is used, Endpoints <b>must</b> be configured in
* ascending order, or bank corruption will occur.
* \n\n
*
* \note Certain models of USB AVR's endpoints may have different maximum packet sizes based on the endpoint's
* index - refer to the chosen USB AVR's datasheet to determine the maximum bank size for each endpoint.
* \n\n
*
* \note The default control endpoint should not be manually configured by the user application, as
* it is automatically configured by the library internally.
* \n\n
*
* \note This routine will automatically select the specified endpoint upon success. Upon failure, the endpoint
* which failed to reconfigure correctly will be selected.
*
* \return Boolean \c true if the configuration succeeded, \c false otherwise.
*/
static inline bool Endpoint_ConfigureEndpoint(const uint8_t Number,
const uint8_t Type,
const uint8_t Direction,
const uint16_t Size,
const uint8_t Banks) ATTR_ALWAYS_INLINE;
static inline bool Endpoint_ConfigureEndpoint(const uint8_t Number,
const uint8_t Type,
const uint8_t Direction,
const uint16_t Size,
const uint8_t Banks)
{
return Endpoint_ConfigureEndpoint_Prv(Number, ((Type << EPTYPE0) | Direction),
((1 << ALLOC) | Banks | Endpoint_BytesToEPSizeMask(Size)));
}
/** Indicates the number of bytes currently stored in the current endpoint's selected bank.
*
* \note The return width of this function may differ, depending on the maximum endpoint bank size
* of the selected AVR model.
*
* \ingroup Group_EndpointRW_AVR8
*
* \return Total number of bytes in the currently selected Endpoint's FIFO buffer.
*/
static inline uint16_t Endpoint_BytesInEndpoint(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline uint16_t Endpoint_BytesInEndpoint(void)
{
#if defined(USB_SERIES_6_AVR) || defined(USB_SERIES_7_AVR)
return UEBCX;
#elif defined(USB_SERIES_4_AVR)
return (((uint16_t)UEBCHX << 8) | UEBCLX);
#elif defined(USB_SERIES_2_AVR)
return UEBCLX;
#endif
}
/** Get the endpoint address of the currently selected endpoint. This is typically used to save
* the currently selected endpoint number so that it can be restored after another endpoint has
* been manipulated.
*
* \return Index of the currently selected endpoint.
*/
static inline uint8_t Endpoint_GetCurrentEndpoint(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline uint8_t Endpoint_GetCurrentEndpoint(void)
{
#if !defined(CONTROL_ONLY_DEVICE)
return (UENUM & ENDPOINT_EPNUM_MASK);
#else
return ENDPOINT_CONTROLEP;
#endif
}
/** Selects the given endpoint number. If the address from the device descriptors is used, the
* value should be masked with the \ref ENDPOINT_EPNUM_MASK constant to extract only the endpoint
* number (and discarding the endpoint direction bit).
*
* Any endpoint operations which do not require the endpoint number to be indicated will operate on
* the currently selected endpoint.
*
* \param[in] EndpointNumber Endpoint number to select.
*/
static inline void Endpoint_SelectEndpoint(const uint8_t EndpointNumber) ATTR_ALWAYS_INLINE;
static inline void Endpoint_SelectEndpoint(const uint8_t EndpointNumber)
{
#if !defined(CONTROL_ONLY_DEVICE)
UENUM = EndpointNumber;
#endif
}
/** Resets the endpoint bank FIFO. This clears all the endpoint banks and resets the USB controller's
* data In and Out pointers to the bank's contents.
*
* \param[in] EndpointNumber Endpoint number whose FIFO buffers are to be reset.
*/
static inline void Endpoint_ResetFIFO(const uint8_t EndpointNumber) ATTR_ALWAYS_INLINE;
static inline void Endpoint_ResetFIFO(const uint8_t EndpointNumber)
{
UERST = (1 << EndpointNumber);
UERST = 0;
}
/** Enables the currently selected endpoint so that data can be sent and received through it to
* and from a host.
*
* \note Endpoints must first be configured properly via \ref Endpoint_ConfigureEndpoint().
*/
static inline void Endpoint_EnableEndpoint(void) ATTR_ALWAYS_INLINE;
static inline void Endpoint_EnableEndpoint(void)
{
UECONX |= (1 << EPEN);
}
/** Disables the currently selected endpoint so that data cannot be sent and received through it
* to and from a host.
*/
static inline void Endpoint_DisableEndpoint(void) ATTR_ALWAYS_INLINE;
static inline void Endpoint_DisableEndpoint(void)
{
UECONX &= ~(1 << EPEN);
}
/** Determines if the currently selected endpoint is enabled, but not necessarily configured.
*
* \return Boolean \c true if the currently selected endpoint is enabled, \c false otherwise.
*/
static inline bool Endpoint_IsEnabled(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline bool Endpoint_IsEnabled(void)
{
return ((UECONX & (1 << EPEN)) ? true : false);
}
/** Retrieves the number of busy banks in the currently selected endpoint, which have been queued for
* transmission via the \ref Endpoint_ClearIN() command, or are awaiting acknowledgement via the
* \ref Endpoint_ClearOUT() command.
*
* \ingroup Group_EndpointPacketManagement_AVR8
*
* \return Total number of busy banks in the selected endpoint.
*/
static inline uint8_t Endpoint_GetBusyBanks(void)
{
return (UESTA0X & (0x03 << NBUSYBK0));
}
/** Aborts all pending IN transactions on the currently selected endpoint, once the bank
* has been queued for transmission to the host via \ref Endpoint_ClearIN(). This function
* will terminate all queued transactions, resetting the endpoint banks ready for a new
* packet.
*
* \ingroup Group_EndpointPacketManagement_AVR8
*/
static inline void Endpoint_AbortPendingIN(void)
{
while (Endpoint_GetBusyBanks() != 0)
{
UEINTX |= (1 << RXOUTI);
while (UEINTX & (1 << RXOUTI));
}
}
/** Determines if the currently selected endpoint may be read from (if data is waiting in the endpoint
* bank and the endpoint is an OUT direction, or if the bank is not yet full if the endpoint is an IN
* direction). This function will return false if an error has occurred in the endpoint, if the endpoint
* is an OUT direction and no packet (or an empty packet) has been received, or if the endpoint is an IN
* direction and the endpoint bank is full.
*
* \ingroup Group_EndpointPacketManagement_AVR8
*
* \return Boolean \c true if the currently selected endpoint may be read from or written to, depending
* on its direction.
*/
static inline bool Endpoint_IsReadWriteAllowed(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline bool Endpoint_IsReadWriteAllowed(void)
{
return ((UEINTX & (1 << RWAL)) ? true : false);
}
/** Determines if the currently selected endpoint is configured.
*
* \return Boolean \c true if the currently selected endpoint has been configured, \c false otherwise.
*/
static inline bool Endpoint_IsConfigured(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline bool Endpoint_IsConfigured(void)
{
return ((UESTA0X & (1 << CFGOK)) ? true : false);
}
/** Returns a mask indicating which INTERRUPT type endpoints have interrupted - i.e. their
* interrupt duration has elapsed. Which endpoints have interrupted can be determined by
* masking the return value against <tt>(1 << <i>{Endpoint Number}</i>)</tt>.
*
* \return Mask whose bits indicate which endpoints have interrupted.
*/
static inline uint8_t Endpoint_GetEndpointInterrupts(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline uint8_t Endpoint_GetEndpointInterrupts(void)
{
return UEINT;
}
/** Determines if the specified endpoint number has interrupted (valid only for INTERRUPT type
* endpoints).
*
* \param[in] EndpointNumber Index of the endpoint whose interrupt flag should be tested.
*
* \return Boolean \c true if the specified endpoint has interrupted, \c false otherwise.
*/
static inline bool Endpoint_HasEndpointInterrupted(const uint8_t EndpointNumber) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline bool Endpoint_HasEndpointInterrupted(const uint8_t EndpointNumber)
{
return ((Endpoint_GetEndpointInterrupts() & (1 << EndpointNumber)) ? true : false);
}
/** Determines if the selected IN endpoint is ready for a new packet to be sent to the host.
*
* \ingroup Group_EndpointPacketManagement_AVR8
*
* \return Boolean \c true if the current endpoint is ready for an IN packet, \c false otherwise.
*/
static inline bool Endpoint_IsINReady(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline bool Endpoint_IsINReady(void)
{
return ((UEINTX & (1 << TXINI)) ? true : false);
}
/** Determines if the selected OUT endpoint has received new packet from the host.
*
* \ingroup Group_EndpointPacketManagement_AVR8
*
* \return Boolean \c true if current endpoint is has received an OUT packet, \c false otherwise.
*/
static inline bool Endpoint_IsOUTReceived(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline bool Endpoint_IsOUTReceived(void)
{
return ((UEINTX & (1 << RXOUTI)) ? true : false);
}
/** Determines if the current CONTROL type endpoint has received a SETUP packet.
*
* \ingroup Group_EndpointPacketManagement_AVR8
*
* \return Boolean \c true if the selected endpoint has received a SETUP packet, \c false otherwise.
*/
static inline bool Endpoint_IsSETUPReceived(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline bool Endpoint_IsSETUPReceived(void)
{
return ((UEINTX & (1 << RXSTPI)) ? true : false);
}
/** Clears a received SETUP packet on the currently selected CONTROL type endpoint, freeing up the
* endpoint for the next packet.
*
* \ingroup Group_EndpointPacketManagement_AVR8
*
* \note This is not applicable for non CONTROL type endpoints.
*/
static inline void Endpoint_ClearSETUP(void) ATTR_ALWAYS_INLINE;
static inline void Endpoint_ClearSETUP(void)
{
UEINTX &= ~(1 << RXSTPI);
}
/** Sends an IN packet to the host on the currently selected endpoint, freeing up the endpoint for the
* next packet and switching to the alternative endpoint bank if double banked.
*
* \ingroup Group_EndpointPacketManagement_AVR8
*/
static inline void Endpoint_ClearIN(void) ATTR_ALWAYS_INLINE;
static inline void Endpoint_ClearIN(void)
{
#if !defined(CONTROL_ONLY_DEVICE)
UEINTX &= ~((1 << TXINI) | (1 << FIFOCON));
#else
UEINTX &= ~(1 << TXINI);
#endif
}
/** Acknowledges an OUT packet to the host on the currently selected endpoint, freeing up the endpoint
* for the next packet and switching to the alternative endpoint bank if double banked.
*
* \ingroup Group_EndpointPacketManagement_AVR8
*/
static inline void Endpoint_ClearOUT(void) ATTR_ALWAYS_INLINE;
static inline void Endpoint_ClearOUT(void)
{
#if !defined(CONTROL_ONLY_DEVICE)
UEINTX &= ~((1 << RXOUTI) | (1 << FIFOCON));
#else
UEINTX &= ~(1 << RXOUTI);
#endif
}
/** Stalls the current endpoint, indicating to the host that a logical problem occurred with the
* indicated endpoint and that the current transfer sequence should be aborted. This provides a
* way for devices to indicate invalid commands to the host so that the current transfer can be
* aborted and the host can begin its own recovery sequence.
*
* The currently selected endpoint remains stalled until either the \ref Endpoint_ClearStall() macro
* is called, or the host issues a CLEAR FEATURE request to the device for the currently selected
* endpoint.
*
* \ingroup Group_EndpointPacketManagement_AVR8
*/
static inline void Endpoint_StallTransaction(void) ATTR_ALWAYS_INLINE;
static inline void Endpoint_StallTransaction(void)
{
UECONX |= (1 << STALLRQ);
}
/** Clears the STALL condition on the currently selected endpoint.
*
* \ingroup Group_EndpointPacketManagement_AVR8
*/
static inline void Endpoint_ClearStall(void) ATTR_ALWAYS_INLINE;
static inline void Endpoint_ClearStall(void)
{
UECONX |= (1 << STALLRQC);
}
/** Determines if the currently selected endpoint is stalled, false otherwise.
*
* \ingroup Group_EndpointPacketManagement_AVR8
*
* \return Boolean \c true if the currently selected endpoint is stalled, \c false otherwise.
*/
static inline bool Endpoint_IsStalled(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline bool Endpoint_IsStalled(void)
{
return ((UECONX & (1 << STALLRQ)) ? true : false);
}
/** Resets the data toggle of the currently selected endpoint. */
static inline void Endpoint_ResetDataToggle(void) ATTR_ALWAYS_INLINE;
static inline void Endpoint_ResetDataToggle(void)
{
UECONX |= (1 << RSTDT);
}
/** Determines the currently selected endpoint's direction.
*
* \return The currently selected endpoint's direction, as a \c ENDPOINT_DIR_* mask.
*/
static inline uint8_t Endpoint_GetEndpointDirection(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline uint8_t Endpoint_GetEndpointDirection(void)
{
return (UECFG0X & ENDPOINT_DIR_IN);
}
/** Sets the direction of the currently selected endpoint.
*
* \param[in] DirectionMask New endpoint direction, as a \c ENDPOINT_DIR_* mask.
*/
static inline void Endpoint_SetEndpointDirection(const uint8_t DirectionMask) ATTR_ALWAYS_INLINE;
static inline void Endpoint_SetEndpointDirection(const uint8_t DirectionMask)
{
UECFG0X = ((UECFG0X & ~ENDPOINT_DIR_IN) | DirectionMask);
}
/** Reads one byte from the currently selected endpoint's bank, for OUT direction endpoints.
*
* \ingroup Group_EndpointPrimitiveRW_AVR8
*
* \return Next byte in the currently selected endpoint's FIFO buffer.
*/
static inline uint8_t Endpoint_Read_Byte(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline uint8_t Endpoint_Read_Byte(void)
{
return UEDATX;
}
/** Writes one byte from the currently selected endpoint's bank, for IN direction endpoints.
*
* \ingroup Group_EndpointPrimitiveRW_AVR8
*
* \param[in] Byte Next byte to write into the the currently selected endpoint's FIFO buffer.
*/
static inline void Endpoint_Write_Byte(const uint8_t Byte) ATTR_ALWAYS_INLINE;
static inline void Endpoint_Write_Byte(const uint8_t Byte)
{
UEDATX = Byte;
}
/** Discards one byte from the currently selected endpoint's bank, for OUT direction endpoints.
*
* \ingroup Group_EndpointPrimitiveRW_AVR8
*/
static inline void Endpoint_Discard_Byte(void) ATTR_ALWAYS_INLINE;
static inline void Endpoint_Discard_Byte(void)
{
uint8_t Dummy;
Dummy = UEDATX;
}
/** Reads two bytes from the currently selected endpoint's bank in little endian format, for OUT
* direction endpoints.
*
* \ingroup Group_EndpointPrimitiveRW_AVR8
*
* \return Next word in the currently selected endpoint's FIFO buffer.
*/
static inline uint16_t Endpoint_Read_Word_LE(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline uint16_t Endpoint_Read_Word_LE(void)
{
union
{
uint16_t Word;
uint8_t Bytes[2];
} Data;
Data.Bytes[0] = UEDATX;
Data.Bytes[1] = UEDATX;
return Data.Word;
}
/** Reads two bytes from the currently selected endpoint's bank in big endian format, for OUT
* direction endpoints.
*
* \ingroup Group_EndpointPrimitiveRW_AVR8
*
* \return Next word in the currently selected endpoint's FIFO buffer.
*/
static inline uint16_t Endpoint_Read_Word_BE(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline uint16_t Endpoint_Read_Word_BE(void)
{
union
{
uint16_t Word;
uint8_t Bytes[2];
} Data;
Data.Bytes[1] = UEDATX;
Data.Bytes[0] = UEDATX;
return Data.Word;
}
/** Writes two bytes to the currently selected endpoint's bank in little endian format, for IN
* direction endpoints.
*
* \ingroup Group_EndpointPrimitiveRW_AVR8
*
* \param[in] Word Next word to write to the currently selected endpoint's FIFO buffer.
*/
static inline void Endpoint_Write_Word_LE(const uint16_t Word) ATTR_ALWAYS_INLINE;
static inline void Endpoint_Write_Word_LE(const uint16_t Word)
{
UEDATX = (Word & 0xFF);
UEDATX = (Word >> 8);
}
/** Writes two bytes to the currently selected endpoint's bank in big endian format, for IN
* direction endpoints.
*
* \ingroup Group_EndpointPrimitiveRW_AVR8
*
* \param[in] Word Next word to write to the currently selected endpoint's FIFO buffer.
*/
static inline void Endpoint_Write_Word_BE(const uint16_t Word) ATTR_ALWAYS_INLINE;
static inline void Endpoint_Write_Word_BE(const uint16_t Word)
{
UEDATX = (Word >> 8);
UEDATX = (Word & 0xFF);
}
/** Discards two bytes from the currently selected endpoint's bank, for OUT direction endpoints.
*
* \ingroup Group_EndpointPrimitiveRW_AVR8
*/
static inline void Endpoint_Discard_Word(void) ATTR_ALWAYS_INLINE;
static inline void Endpoint_Discard_Word(void)
{
uint8_t Dummy;
Dummy = UEDATX;
Dummy = UEDATX;
}
/** Reads four bytes from the currently selected endpoint's bank in little endian format, for OUT
* direction endpoints.
*
* \ingroup Group_EndpointPrimitiveRW_AVR8
*
* \return Next double word in the currently selected endpoint's FIFO buffer.
*/
static inline uint32_t Endpoint_Read_DWord_LE(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline uint32_t Endpoint_Read_DWord_LE(void)
{
union
{
uint32_t DWord;
uint8_t Bytes[4];
} Data;
Data.Bytes[0] = UEDATX;
Data.Bytes[1] = UEDATX;
Data.Bytes[2] = UEDATX;
Data.Bytes[3] = UEDATX;
return Data.DWord;
}
/** Reads four bytes from the currently selected endpoint's bank in big endian format, for OUT
* direction endpoints.
*
* \ingroup Group_EndpointPrimitiveRW_AVR8
*
* \return Next double word in the currently selected endpoint's FIFO buffer.
*/
static inline uint32_t Endpoint_Read_DWord_BE(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline uint32_t Endpoint_Read_DWord_BE(void)
{
union
{
uint32_t DWord;
uint8_t Bytes[4];
} Data;
Data.Bytes[3] = UEDATX;
Data.Bytes[2] = UEDATX;
Data.Bytes[1] = UEDATX;
Data.Bytes[0] = UEDATX;
return Data.DWord;
}
/** Writes four bytes to the currently selected endpoint's bank in little endian format, for IN
* direction endpoints.
*
* \ingroup Group_EndpointPrimitiveRW_AVR8
*
* \param[in] DWord Next double word to write to the currently selected endpoint's FIFO buffer.
*/
static inline void Endpoint_Write_DWord_LE(const uint32_t DWord) ATTR_ALWAYS_INLINE;
static inline void Endpoint_Write_DWord_LE(const uint32_t DWord)
{
UEDATX = (DWord & 0xFF);
UEDATX = (DWord >> 8);
UEDATX = (DWord >> 16);
UEDATX = (DWord >> 24);
}
/** Writes four bytes to the currently selected endpoint's bank in big endian format, for IN
* direction endpoints.
*
* \ingroup Group_EndpointPrimitiveRW_AVR8
*
* \param[in] DWord Next double word to write to the currently selected endpoint's FIFO buffer.
*/
static inline void Endpoint_Write_DWord_BE(const uint32_t DWord) ATTR_ALWAYS_INLINE;
static inline void Endpoint_Write_DWord_BE(const uint32_t DWord)
{
UEDATX = (DWord >> 24);
UEDATX = (DWord >> 16);
UEDATX = (DWord >> 8);
UEDATX = (DWord & 0xFF);
}
/** Discards four bytes from the currently selected endpoint's bank, for OUT direction endpoints.
*
* \ingroup Group_EndpointPrimitiveRW_AVR8
*/
static inline void Endpoint_Discard_DWord(void) ATTR_ALWAYS_INLINE;
static inline void Endpoint_Discard_DWord(void)
{
uint8_t Dummy;
Dummy = UEDATX;
Dummy = UEDATX;
Dummy = UEDATX;
Dummy = UEDATX;
}
/* External Variables: */
/** Global indicating the maximum packet size of the default control endpoint located at address
* 0 in the device. This value is set to the value indicated in the device descriptor in the user
* project once the USB interface is initialized into device mode.
*
* If space is an issue, it is possible to fix this to a static value by defining the control
* endpoint size in the \c FIXED_CONTROL_ENDPOINT_SIZE token passed to the compiler in the makefile
* via the -D switch. When a fixed control endpoint size is used, the size is no longer dynamically
* read from the descriptors at runtime and instead fixed to the given value. When used, it is
* important that the descriptor control endpoint size value matches the size given as the
* \c FIXED_CONTROL_ENDPOINT_SIZE token - it is recommended that the \c FIXED_CONTROL_ENDPOINT_SIZE token
* be used in the device descriptors to ensure this.
*
* \note This variable should be treated as read-only in the user application, and never manually
* changed in value.
*/
#if (!defined(FIXED_CONTROL_ENDPOINT_SIZE) || defined(__DOXYGEN__))
extern uint8_t USB_ControlEndpointSize;
#else
#define USB_ControlEndpointSize FIXED_CONTROL_ENDPOINT_SIZE
#endif
/* Function Prototypes: */
/** Completes the status stage of a control transfer on a CONTROL type endpoint automatically,
* with respect to the data direction. This is a convenience function which can be used to
* simplify user control request handling.
*/
void Endpoint_ClearStatusStage(void);
/** Spin-loops until the currently selected non-control endpoint is ready for the next packet of data
* to be read or written to it.
*
* \note This routine should not be called on CONTROL type endpoints.
*
* \ingroup Group_EndpointRW_AVR8
*
* \return A value from the \ref Endpoint_WaitUntilReady_ErrorCodes_t enum.
*/
uint8_t Endpoint_WaitUntilReady(void);
/* Disable C linkage for C++ Compilers: */
#if defined(__cplusplus)
}
#endif
#endif
/** @} */

View file

@ -0,0 +1,355 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2011.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2011 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, 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.
*/
#define __INCLUDE_FROM_USB_DRIVER
#include "../USBMode.h"
#if defined(USB_CAN_BE_HOST)
#define __INCLUDE_FROM_HOST_C
#include "../Host.h"
void USB_Host_ProcessNextHostState(void)
{
uint8_t ErrorCode = HOST_ENUMERROR_NoError;
uint8_t SubErrorCode = HOST_ENUMERROR_NoError;
static uint16_t WaitMSRemaining;
static uint8_t PostWaitState;
switch (USB_HostState)
{
case HOST_STATE_WaitForDevice:
if (WaitMSRemaining)
{
if ((SubErrorCode = USB_Host_WaitMS(1)) != HOST_WAITERROR_Successful)
{
USB_HostState = PostWaitState;
ErrorCode = HOST_ENUMERROR_WaitStage;
break;
}
if (!(--WaitMSRemaining))
USB_HostState = PostWaitState;
}
break;
case HOST_STATE_Powered:
WaitMSRemaining = HOST_DEVICE_SETTLE_DELAY_MS;
USB_HostState = HOST_STATE_Powered_WaitForDeviceSettle;
break;
case HOST_STATE_Powered_WaitForDeviceSettle:
if (WaitMSRemaining--)
{
_delay_ms(1);
break;
}
else
{
USB_Host_VBUS_Manual_Off();
USB_OTGPAD_On();
USB_Host_VBUS_Auto_Enable();
USB_Host_VBUS_Auto_On();
USB_HostState = HOST_STATE_Powered_WaitForConnect;
}
break;
case HOST_STATE_Powered_WaitForConnect:
if (USB_INT_HasOccurred(USB_INT_DCONNI))
{
USB_INT_Clear(USB_INT_DCONNI);
USB_INT_Clear(USB_INT_DDISCI);
USB_INT_Clear(USB_INT_VBERRI);
USB_INT_Enable(USB_INT_VBERRI);
USB_Host_ResumeBus();
Pipe_ClearPipes();
HOST_TASK_NONBLOCK_WAIT(100, HOST_STATE_Powered_DoReset);
}
break;
case HOST_STATE_Powered_DoReset:
USB_Host_ResetDevice();
HOST_TASK_NONBLOCK_WAIT(200, HOST_STATE_Powered_ConfigPipe);
break;
case HOST_STATE_Powered_ConfigPipe:
Pipe_ConfigurePipe(PIPE_CONTROLPIPE, EP_TYPE_CONTROL,
PIPE_TOKEN_SETUP, ENDPOINT_CONTROLEP,
PIPE_CONTROLPIPE_DEFAULT_SIZE, PIPE_BANK_SINGLE);
if (!(Pipe_IsConfigured()))
{
ErrorCode = HOST_ENUMERROR_PipeConfigError;
SubErrorCode = 0;
break;
}
USB_HostState = HOST_STATE_Default;
break;
case HOST_STATE_Default:
USB_ControlRequest = (USB_Request_Header_t)
{
.bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_DEVICE),
.bRequest = REQ_GetDescriptor,
.wValue = (DTYPE_Device << 8),
.wIndex = 0,
.wLength = 8,
};
uint8_t DataBuffer[8];
if ((SubErrorCode = USB_Host_SendControlRequest(DataBuffer)) != HOST_SENDCONTROL_Successful)
{
ErrorCode = HOST_ENUMERROR_ControlError;
break;
}
USB_ControlPipeSize = DataBuffer[offsetof(USB_Descriptor_Device_t, Endpoint0Size)];
USB_Host_ResetDevice();
HOST_TASK_NONBLOCK_WAIT(200, HOST_STATE_Default_PostReset);
break;
case HOST_STATE_Default_PostReset:
Pipe_ConfigurePipe(PIPE_CONTROLPIPE, EP_TYPE_CONTROL,
PIPE_TOKEN_SETUP, ENDPOINT_CONTROLEP,
USB_ControlPipeSize, PIPE_BANK_SINGLE);
if (!(Pipe_IsConfigured()))
{
ErrorCode = HOST_ENUMERROR_PipeConfigError;
SubErrorCode = 0;
break;
}
USB_ControlRequest = (USB_Request_Header_t)
{
.bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_DEVICE),
.bRequest = REQ_SetAddress,
.wValue = USB_HOST_DEVICEADDRESS,
.wIndex = 0,
.wLength = 0,
};
if ((SubErrorCode = USB_Host_SendControlRequest(NULL)) != HOST_SENDCONTROL_Successful)
{
ErrorCode = HOST_ENUMERROR_ControlError;
break;
}
HOST_TASK_NONBLOCK_WAIT(100, HOST_STATE_Default_PostAddressSet);
break;
case HOST_STATE_Default_PostAddressSet:
USB_Host_SetDeviceAddress(USB_HOST_DEVICEADDRESS);
EVENT_USB_Host_DeviceEnumerationComplete();
USB_HostState = HOST_STATE_Addressed;
break;
}
if ((ErrorCode != HOST_ENUMERROR_NoError) && (USB_HostState != HOST_STATE_Unattached))
{
EVENT_USB_Host_DeviceEnumerationFailed(ErrorCode, SubErrorCode);
USB_Host_VBUS_Auto_Off();
EVENT_USB_Host_DeviceUnattached();
USB_ResetInterface();
}
}
uint8_t USB_Host_WaitMS(uint8_t MS)
{
bool BusSuspended = USB_Host_IsBusSuspended();
uint8_t ErrorCode = HOST_WAITERROR_Successful;
bool HSOFIEnabled = USB_INT_IsEnabled(USB_INT_HSOFI);
USB_INT_Disable(USB_INT_HSOFI);
USB_INT_Clear(USB_INT_HSOFI);
USB_Host_ResumeBus();
while (MS)
{
if (USB_INT_HasOccurred(USB_INT_HSOFI))
{
USB_INT_Clear(USB_INT_HSOFI);
MS--;
}
if ((USB_HostState == HOST_STATE_Unattached) || (USB_CurrentMode != USB_MODE_Host))
{
ErrorCode = HOST_WAITERROR_DeviceDisconnect;
break;
}
if (Pipe_IsError() == true)
{
Pipe_ClearError();
ErrorCode = HOST_WAITERROR_PipeError;
break;
}
if (Pipe_IsStalled() == true)
{
Pipe_ClearStall();
ErrorCode = HOST_WAITERROR_SetupStalled;
break;
}
}
if (BusSuspended)
USB_Host_SuspendBus();
if (HSOFIEnabled)
USB_INT_Enable(USB_INT_HSOFI);
return ErrorCode;
}
static void USB_Host_ResetDevice(void)
{
bool BusSuspended = USB_Host_IsBusSuspended();
USB_INT_Disable(USB_INT_DDISCI);
USB_Host_ResetBus();
while (!(USB_Host_IsBusResetComplete()));
USB_Host_ResumeBus();
bool HSOFIEnabled = USB_INT_IsEnabled(USB_INT_HSOFI);
USB_INT_Disable(USB_INT_HSOFI);
USB_INT_Clear(USB_INT_HSOFI);
for (uint8_t MSRem = 10; MSRem != 0; MSRem--)
{
/* Workaround for powerless-pull-up devices. After a USB bus reset,
all disconnection interrupts are suppressed while a USB frame is
looked for - if it is found within 10ms, the device is still
present. */
if (USB_INT_HasOccurred(USB_INT_HSOFI))
{
USB_INT_Clear(USB_INT_HSOFI);
USB_INT_Clear(USB_INT_DDISCI);
break;
}
_delay_ms(1);
}
if (HSOFIEnabled)
USB_INT_Enable(USB_INT_HSOFI);
if (BusSuspended)
USB_Host_SuspendBus();
USB_INT_Enable(USB_INT_DDISCI);
}
uint8_t USB_Host_SetDeviceConfiguration(const uint8_t ConfigNumber)
{
USB_ControlRequest = (USB_Request_Header_t)
{
.bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_DEVICE),
.bRequest = REQ_SetConfiguration,
.wValue = ConfigNumber,
.wIndex = 0,
.wLength = 0,
};
Pipe_SelectPipe(PIPE_CONTROLPIPE);
return USB_Host_SendControlRequest(NULL);
}
uint8_t USB_Host_GetDeviceDescriptor(void* const DeviceDescriptorPtr)
{
USB_ControlRequest = (USB_Request_Header_t)
{
.bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_DEVICE),
.bRequest = REQ_GetDescriptor,
.wValue = (DTYPE_Device << 8),
.wIndex = 0,
.wLength = sizeof(USB_Descriptor_Device_t),
};
Pipe_SelectPipe(PIPE_CONTROLPIPE);
return USB_Host_SendControlRequest(DeviceDescriptorPtr);
}
uint8_t USB_Host_GetDeviceStringDescriptor(const uint8_t Index,
void* const Buffer,
const uint8_t BufferLength)
{
USB_ControlRequest = (USB_Request_Header_t)
{
.bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_DEVICE),
.bRequest = REQ_GetDescriptor,
.wValue = (DTYPE_String << 8) | Index,
.wIndex = 0,
.wLength = BufferLength,
};
Pipe_SelectPipe(PIPE_CONTROLPIPE);
return USB_Host_SendControlRequest(Buffer);
}
uint8_t USB_Host_ClearPipeStall(const uint8_t EndpointNum)
{
USB_ControlRequest = (USB_Request_Header_t)
{
.bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_ENDPOINT),
.bRequest = REQ_ClearFeature,
.wValue = FEATURE_SEL_EndpointHalt,
.wIndex = EndpointNum,
.wLength = 0,
};
Pipe_SelectPipe(PIPE_CONTROLPIPE);
return USB_Host_SendControlRequest(NULL);
}
#endif

View file

@ -0,0 +1,522 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2011.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2011 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, 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
* \brief USB Host definitions for the AVR8 microcontrollers.
* \copydetails Group_Host_AVR8
*
* \note This file should not be included directly. It is automatically included as needed by the USB driver
* dispatch header located in LUFA/Drivers/USB/USB.h.
*/
/** \ingroup Group_Host
* \defgroup Group_Host_AVR8 Host Management (AVR8)
* \brief USB Host definitions for the AVR8 microcontrollers.
*
* Architecture specific USB Host definitions for the Atmel 8-bit AVR microcontrollers.
*
* @{
*/
#ifndef __USBHOST_AVR8_H__
#define __USBHOST_AVR8_H__
/* Includes: */
#include "../../../../Common/Common.h"
#include "../StdDescriptors.h"
#include "../Pipe.h"
#include "../USBInterrupt.h"
/* Enable C linkage for C++ Compilers: */
#if defined(__cplusplus)
extern "C" {
#endif
/* Preprocessor Checks: */
#if !defined(__INCLUDE_FROM_USB_DRIVER)
#error Do not include this file directly. Include LUFA/Drivers/USB/USB.h instead.
#endif
/* Public Interface - May be used in end-application: */
/* Macros: */
/** Indicates the fixed USB device address which any attached device is enumerated to when in
* host mode. As only one USB device may be attached to the AVR in host mode at any one time
* and that the address used is not important (other than the fact that it is non-zero), a
* fixed value is specified by the library.
*/
#define USB_HOST_DEVICEADDRESS 1
#if !defined(USB_HOST_TIMEOUT_MS) || defined(__DOXYGEN__)
/** Constant for the maximum software timeout period of sent USB control transactions to an attached
* device. If a device fails to respond to a sent control request within this period, the
* library will return a timeout error code.
*
* This value may be overridden in the user project makefile as the value of the
* \ref USB_HOST_TIMEOUT_MS token, and passed to the compiler using the -D switch.
*/
#define USB_HOST_TIMEOUT_MS 1000
#endif
#if !defined(HOST_DEVICE_SETTLE_DELAY_MS) || defined(__DOXYGEN__)
/** Constant for the delay in milliseconds after a device is connected before the library
* will start the enumeration process. Some devices require a delay of up to 5 seconds
* after connection before the enumeration process can start or incorrect operation will
* occur.
*
* The default delay value may be overridden in the user project makefile by defining the
* \c HOST_DEVICE_SETTLE_DELAY_MS token to the required delay in milliseconds, and passed to the
* compiler using the -D switch.
*/
#define HOST_DEVICE_SETTLE_DELAY_MS 1000
#endif
/* Enums: */
/** Enum for the various states of the USB Host state machine. Only some states are
* implemented in the LUFA library - other states are left to the user to implement.
*
* For information on each possible USB host state, refer to the USB 2.0 specification.
* Several of the USB host states are broken up further into multiple smaller sub-states,
* so that they can be internally implemented inside the library in an efficient manner.
*
* \see \ref USB_HostState, which stores the current host state machine state.
*/
enum USB_Host_States_t
{
HOST_STATE_WaitForDeviceRemoval = 0, /**< Internally implemented by the library. This state can be
* used by the library to wait until the attached device is
* removed by the user - useful for when an error occurs or
* further communication with the device is not needed. This
* allows for other code to run while the state machine is
* effectively disabled.
*/
HOST_STATE_WaitForDevice = 1, /**< Internally implemented by the library. This state indicates
* that the stack is waiting for an interval to elapse before
* continuing with the next step of the device enumeration
* process.
*
* \note Do not manually change to this state in the user code.
*/
HOST_STATE_Unattached = 2, /**< Internally implemented by the library. This state indicates
* that the host state machine is waiting for a device to be
* attached so that it can start the enumeration process.
*
* \note Do not manually change to this state in the user code.
*/
HOST_STATE_Powered = 3, /**< Internally implemented by the library. This state indicates
* that a device has been attached, and the library's internals
* are being configured to begin the enumeration process.
*
* \note Do not manually change to this state in the user code.
*/
HOST_STATE_Powered_WaitForDeviceSettle = 4, /**< Internally implemented by the library. This state indicates
* that the stack is waiting for the initial settling period to
* elapse before beginning the enumeration process.
*
* \note Do not manually change to this state in the user code.
*/
HOST_STATE_Powered_WaitForConnect = 5, /**< Internally implemented by the library. This state indicates
* that the stack is waiting for a connection event from the USB
* controller to indicate a valid USB device has been attached to
* the bus and is ready to be enumerated.
*
* \note Do not manually change to this state in the user code.
*/
HOST_STATE_Powered_DoReset = 6, /**< Internally implemented by the library. This state indicates
* that a valid USB device has been attached, and that it is
* will now be reset to ensure it is ready for enumeration.
*
* \note Do not manually change to this state in the user code.
*/
HOST_STATE_Powered_ConfigPipe = 7, /**< Internally implemented by the library. This state indicates
* that the attached device is currently powered and reset, and
* that the control pipe is now being configured by the stack.
*
* \note Do not manually change to this state in the user code.
*/
HOST_STATE_Default = 8, /**< Internally implemented by the library. This state indicates
* that the stack is currently retrieving the control endpoint's
* size from the device, so that the control pipe can be altered
* to match.
*
* \note Do not manually change to this state in the user code.
*/
HOST_STATE_Default_PostReset = 9, /**< Internally implemented by the library. This state indicates that
* the control pipe is being reconfigured to match the retrieved
* control endpoint size from the device, and the device's USB bus
* address is being set.
*
* \note Do not manually change to this state in the user code.
*/
HOST_STATE_Default_PostAddressSet = 10, /**< Internally implemented by the library. This state indicates that
* the device's address has now been set, and the stack is has now
* completed the device enumeration process. This state causes the
* stack to change the current USB device address to that set for
* the connected device, before progressing to the user-implemented
* \ref HOST_STATE_Addressed state for further communications.
*
* \note Do not manually change to this state in the user code.
*/
HOST_STATE_Addressed = 11, /**< May be implemented by the user project. This state should
* set the device configuration before progressing to the
* \ref HOST_STATE_Configured state. Other processing (such as the
* retrieval and processing of the device descriptor) should also
* be placed in this state.
*/
HOST_STATE_Configured = 12, /**< May be implemented by the user project. This state should implement the
* actual work performed on the attached device and changed to the
* \ref HOST_STATE_Suspended or \ref HOST_STATE_WaitForDeviceRemoval states as needed.
*/
HOST_STATE_Suspended = 15, /**< May be implemented by the user project. This state should be maintained
* while the bus is suspended, and changed to either the \ref HOST_STATE_Configured
* (after resuming the bus with the USB_Host_ResumeBus() macro) or the
* \ref HOST_STATE_WaitForDeviceRemoval states as needed.
*/
};
/** Enum for the error codes for the \ref EVENT_USB_Host_HostError() event.
*
* \see \ref Group_Events for more information on this event.
*/
enum USB_Host_ErrorCodes_t
{
HOST_ERROR_VBusVoltageDip = 0, /**< VBUS voltage dipped to an unacceptable level. This
* error may be the result of an attached device drawing
* too much current from the VBUS line, or due to the
* AVR's power source being unable to supply sufficient
* current.
*/
};
/** Enum for the error codes for the \ref EVENT_USB_Host_DeviceEnumerationFailed() event.
*
* \see \ref Group_Events for more information on this event.
*/
enum USB_Host_EnumerationErrorCodes_t
{
HOST_ENUMERROR_NoError = 0, /**< No error occurred. Used internally, this is not a valid
* ErrorCode parameter value for the \ref EVENT_USB_Host_DeviceEnumerationFailed()
* event.
*/
HOST_ENUMERROR_WaitStage = 1, /**< One of the delays between enumeration steps failed
* to complete successfully, due to a timeout or other
* error.
*/
HOST_ENUMERROR_NoDeviceDetected = 2, /**< No device was detected, despite the USB data lines
* indicating the attachment of a device.
*/
HOST_ENUMERROR_ControlError = 3, /**< One of the enumeration control requests failed to
* complete successfully.
*/
HOST_ENUMERROR_PipeConfigError = 4, /**< The default control pipe (address 0) failed to
* configure correctly.
*/
};
/* Inline Functions: */
/** Returns the current USB frame number, when in host mode. Every millisecond the USB bus is active (i.e. not suspended)
* the frame number is incremented by one.
*/
static inline uint16_t USB_Host_GetFrameNumber(void)
{
return UHFNUM;
}
#if !defined(NO_SOF_EVENTS)
/** Enables the host mode Start Of Frame events. When enabled, this causes the
* \ref EVENT_USB_Host_StartOfFrame() event to fire once per millisecond, synchronized to the USB bus,
* at the start of each USB frame when a device is enumerated while in host mode.
*
* \note Not available when the \c NO_SOF_EVENTS compile time token is defined.
*/
static inline void USB_Host_EnableSOFEvents(void) ATTR_ALWAYS_INLINE;
static inline void USB_Host_EnableSOFEvents(void)
{
USB_INT_Enable(USB_INT_HSOFI);
}
/** Disables the host mode Start Of Frame events. When disabled, this stops the firing of the
* \ref EVENT_USB_Host_StartOfFrame() event when enumerated in host mode.
*
* \note Not available when the NO_SOF_EVENTS compile time token is defined.
*/
static inline void USB_Host_DisableSOFEvents(void) ATTR_ALWAYS_INLINE;
static inline void USB_Host_DisableSOFEvents(void)
{
USB_INT_Disable(USB_INT_HSOFI);
}
#endif
/** Resets the USB bus, including the endpoints in any attached device and pipes on the AVR host.
* USB bus resets leave the default control pipe configured (if already configured).
*
* If the USB bus has been suspended prior to issuing a bus reset, the attached device will be
* woken up automatically and the bus resumed after the reset has been correctly issued.
*/
static inline void USB_Host_ResetBus(void) ATTR_ALWAYS_INLINE;
static inline void USB_Host_ResetBus(void)
{
UHCON |= (1 << RESET);
}
/** Determines if a previously issued bus reset (via the \ref USB_Host_ResetBus() macro) has
* completed.
*
* \return Boolean \c true if no bus reset is currently being sent, \c false otherwise.
*/
static inline bool USB_Host_IsBusResetComplete(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline bool USB_Host_IsBusResetComplete(void)
{
return ((UHCON & (1 << RESET)) ? false : true);
}
/** Resumes USB communications with an attached and enumerated device, by resuming the transmission
* of the 1MS Start Of Frame messages to the device. When resumed, USB communications between the
* host and attached device may occur.
*/
static inline void USB_Host_ResumeBus(void) ATTR_ALWAYS_INLINE;
static inline void USB_Host_ResumeBus(void)
{
UHCON |= (1 << SOFEN);
}
/** Suspends the USB bus, preventing any communications from occurring between the host and attached
* device until the bus has been resumed. This stops the transmission of the 1MS Start Of Frame
* messages to the device.
*/
static inline void USB_Host_SuspendBus(void) ATTR_ALWAYS_INLINE;
static inline void USB_Host_SuspendBus(void)
{
UHCON &= ~(1 << SOFEN);
}
/** Determines if the USB bus has been suspended via the use of the \ref USB_Host_SuspendBus() macro,
* false otherwise. While suspended, no USB communications can occur until the bus is resumed,
* except for the Remote Wakeup event from the device if supported.
*
* \return Boolean \c true if the bus is currently suspended, \c false otherwise.
*/
static inline bool USB_Host_IsBusSuspended(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline bool USB_Host_IsBusSuspended(void)
{
return ((UHCON & (1 << SOFEN)) ? false : true);
}
/** Determines if the attached device is currently enumerated in Full Speed mode (12Mb/s), or
* false if the attached device is enumerated in Low Speed mode (1.5Mb/s).
*
* \return Boolean \c true if the attached device is enumerated in Full Speed mode, \c false otherwise.
*/
static inline bool USB_Host_IsDeviceFullSpeed(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline bool USB_Host_IsDeviceFullSpeed(void)
{
return ((USBSTA & (1 << SPEED)) ? true : false);
}
/** Determines if the attached device is currently issuing a Remote Wakeup request, requesting
* that the host resume the USB bus and wake up the device, false otherwise.
*
* \return Boolean \c true if the attached device has sent a Remote Wakeup request, \c false otherwise.
*/
static inline bool USB_Host_IsRemoteWakeupSent(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline bool USB_Host_IsRemoteWakeupSent(void)
{
return ((UHINT & (1 << RXRSMI)) ? true : false);
}
/** Clears the flag indicating that a Remote Wakeup request has been issued by an attached device. */
static inline void USB_Host_ClearRemoteWakeupSent(void) ATTR_ALWAYS_INLINE;
static inline void USB_Host_ClearRemoteWakeupSent(void)
{
UHINT &= ~(1 << RXRSMI);
}
/** Accepts a Remote Wakeup request from an attached device. This must be issued in response to
* a device's Remote Wakeup request within 2ms for the request to be accepted and the bus to
* be resumed.
*/
static inline void USB_Host_ResumeFromWakeupRequest(void) ATTR_ALWAYS_INLINE;
static inline void USB_Host_ResumeFromWakeupRequest(void)
{
UHCON |= (1 << RESUME);
}
/** Determines if a resume from Remote Wakeup request is currently being sent to an attached
* device.
*
* \return Boolean \c true if no resume request is currently being sent, \c false otherwise.
*/
static inline bool USB_Host_IsResumeFromWakeupRequestSent(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline bool USB_Host_IsResumeFromWakeupRequestSent(void)
{
return ((UHCON & (1 << RESUME)) ? false : true);
}
/* Function Prototypes: */
/** Convenience function. This routine sends a SET CONFIGURATION standard request to the attached
* device, with the given configuration index. This can be used to easily set the device
* configuration without creating and sending the request manually.
*
* \note After this routine returns, the control pipe will be selected.
*
* \param[in] ConfigNumber Configuration index to send to the device.
*
* \return A value from the \ref USB_Host_SendControlErrorCodes_t enum to indicate the result.
*/
uint8_t USB_Host_SetDeviceConfiguration(const uint8_t ConfigNumber);
/** Convenience function. This routine sends a GET DESCRIPTOR standard request to the attached
* device, requesting the device descriptor. This can be used to easily retrieve information
* about the device such as its VID, PID and power requirements.
*
* \note After this routine returns, the control pipe will be selected.
*
* \param[out] DeviceDescriptorPtr Pointer to the destination device descriptor structure where
* the read data is to be stored.
*
* \return A value from the \ref USB_Host_SendControlErrorCodes_t enum to indicate the result.
*/
uint8_t USB_Host_GetDeviceDescriptor(void* const DeviceDescriptorPtr);
/** Convenience function. This routine sends a GET DESCRIPTOR standard request to the attached
* device, requesting the string descriptor of the specified index. This can be used to easily
* retrieve string descriptors from the device by index, after the index is obtained from the
* Device or Configuration descriptors.
*
* \note After this routine returns, the control pipe will be selected.
*
* \param[in] Index Index of the string index to retrieve.
* \param[out] Buffer Pointer to the destination buffer where the retrieved string descriptor is
* to be stored.
* \param[in] BufferLength Maximum size of the string descriptor which can be stored into the buffer.
*
* \return A value from the \ref USB_Host_SendControlErrorCodes_t enum to indicate the result.
*/
uint8_t USB_Host_GetDeviceStringDescriptor(const uint8_t Index,
void* const Buffer,
const uint8_t BufferLength);
/** Clears a stall condition on the given pipe, via a CLEAR FEATURE standard request to the attached device.
*
* \note After this routine returns, the control pipe will be selected.
*
* \param[in] EndpointIndex Index of the endpoint to clear, including the endpoint's direction.
*
* \return A value from the \ref USB_Host_SendControlErrorCodes_t enum to indicate the result.
*/
uint8_t USB_Host_ClearPipeStall(const uint8_t EndpointIndex);
/* Private Interface - For use in library only: */
#if !defined(__DOXYGEN__)
/* Macros: */
static inline void USB_Host_HostMode_On(void) ATTR_ALWAYS_INLINE;
static inline void USB_Host_HostMode_On(void)
{
USBCON |= (1 << HOST);
}
static inline void USB_Host_HostMode_Off(void) ATTR_ALWAYS_INLINE;
static inline void USB_Host_HostMode_Off(void)
{
USBCON &= ~(1 << HOST);
}
static inline void USB_Host_VBUS_Auto_Enable(void) ATTR_ALWAYS_INLINE;
static inline void USB_Host_VBUS_Auto_Enable(void)
{
OTGCON &= ~(1 << VBUSHWC);
UHWCON |= (1 << UVCONE);
}
static inline void USB_Host_VBUS_Manual_Enable(void) ATTR_ALWAYS_INLINE;
static inline void USB_Host_VBUS_Manual_Enable(void)
{
OTGCON |= (1 << VBUSHWC);
UHWCON &= ~(1 << UVCONE);
DDRE |= (1 << 7);
}
static inline void USB_Host_VBUS_Auto_On(void) ATTR_ALWAYS_INLINE;
static inline void USB_Host_VBUS_Auto_On(void)
{
OTGCON |= (1 << VBUSREQ);
}
static inline void USB_Host_VBUS_Manual_On(void) ATTR_ALWAYS_INLINE;
static inline void USB_Host_VBUS_Manual_On(void)
{
PORTE |= (1 << 7);
}
static inline void USB_Host_VBUS_Auto_Off(void) ATTR_ALWAYS_INLINE;
static inline void USB_Host_VBUS_Auto_Off(void)
{
OTGCON |= (1 << VBUSRQC);
}
static inline void USB_Host_VBUS_Manual_Off(void) ATTR_ALWAYS_INLINE;
static inline void USB_Host_VBUS_Manual_Off(void)
{
PORTE &= ~(1 << 7);
}
static inline void USB_Host_SetDeviceAddress(const uint8_t Address) ATTR_ALWAYS_INLINE;
static inline void USB_Host_SetDeviceAddress(const uint8_t Address)
{
UHADDR = (Address & 0x7F);
}
/* Enums: */
enum USB_Host_WaitMSErrorCodes_t
{
HOST_WAITERROR_Successful = 0,
HOST_WAITERROR_DeviceDisconnect = 1,
HOST_WAITERROR_PipeError = 2,
HOST_WAITERROR_SetupStalled = 3,
};
/* Function Prototypes: */
void USB_Host_ProcessNextHostState(void);
uint8_t USB_Host_WaitMS(uint8_t MS);
#if defined(__INCLUDE_FROM_HOST_C)
static void USB_Host_ResetDevice(void);
#endif
#endif
/* Disable C linkage for C++ Compilers: */
#if defined(__cplusplus)
}
#endif
#endif
/** @} */

View file

@ -0,0 +1,149 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2011.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2011 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, 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
* \brief USB OTG definitions for the AVR8 microcontrollers.
* \copydetails Group_OTG_AVR8
*
* \note This file should not be included directly. It is automatically included as needed by the USB driver
* dispatch header located in LUFA/Drivers/USB/USB.h.
*/
/** \ingroup Group_OTG
* \defgroup Group_OTG_AVR8 USB On The Go (OTG) Management (AVR8)
* \brief USB OTG definitions for the AVR8 microcontrollers.
*
* Architecture specific USB OTG definitions for the Atmel 8-bit AVR microcontrollers.
*
* @{
*/
#ifndef __USBOTG_AVR8_H__
#define __USBOTG_AVR8_H__
/* Includes: */
#include "../../../../Common/Common.h"
/* Preprocessor Checks: */
#if !defined(__INCLUDE_FROM_USB_DRIVER)
#error Do not include this file directly. Include LUFA/Drivers/USB/USB.h instead.
#endif
/* Public Interface - May be used in end-application: */
/* Macros: */
/** Mask for the VBUS pulsing method of SRP, supported by some OTG devices.
*
* \see \ref USB_OTG_Device_InitiateSRP().
*/
#define USB_OTG_SRP_VBUS (1 << SRPSEL)
/** Mask for the Data + pulsing method of SRP, supported by some OTG devices.
*
* \see \ref USB_OTG_Device_InitiateSRP().
*/
#define USB_OTG_STP_DATA 0
/* Inline Functions: */
/** Initiate a Host Negotiation Protocol request. This indicates to the other connected device
* that the device wishes to change device/host roles.
*/
static inline void USB_OTG_Device_RequestHNP(void) ATTR_ALWAYS_INLINE;
static inline void USB_OTG_Device_RequestHNP(void)
{
OTGCON |= (1 << HNPREQ);
}
/** Cancel a Host Negotiation Protocol request. This stops a pending HNP request to the other
* connected device.
*/
static inline void USB_OTG_Device_CancelHNPRequest(void) ATTR_ALWAYS_INLINE;
static inline void USB_OTG_Device_CancelHNPRequest(void)
{
OTGCON &= ~(1 << HNPREQ);
}
/** Determines if the device is currently sending a HNP to an attached host.
*
* \return Boolean \c true if currently sending a HNP to the other connected device, \c false otherwise
*/
static inline bool USB_OTG_Device_IsSendingHNP(void) ATTR_ALWAYS_INLINE;
static inline bool USB_OTG_Device_IsSendingHNP(void)
{
return ((OTGCON & (1 << HNPREQ)) ? true : false);
}
/** Initiates a Session Request Protocol request. Most OTG devices turn off VBUS when the USB
* interface is not in use, to conserve power. Sending a SRP to a USB OTG device running in
* host mode indicates that VBUS should be applied and a session started.
*
* There are two different methods of sending a SRP - either pulses on the VBUS line, or by
* pulsing the Data + line via the internal pull-up resistor.
*
* \param[in] SRPTypeMask Mask indicating the type of SRP to use, either \ref USB_OTG_SRP_VBUS or
* \ref USB_OTG_STP_DATA.
*/
static inline void USB_OTG_Device_InitiateSRP(const uint8_t SRPTypeMask) ATTR_ALWAYS_INLINE;
static inline void USB_OTG_Device_InitiateSRP(const uint8_t SRPTypeMask)
{
OTGCON = ((OTGCON & ~(1 << SRPSEL)) | (SRPTypeMask | (1 << SRPREQ)));
}
/** Accepts a HNP from a connected device, indicating that both devices should exchange
* device/host roles.
*/
static inline void USB_OTG_Host_AcceptHNP(void) ATTR_ALWAYS_INLINE;
static inline void USB_OTG_Host_AcceptHNP(void)
{
OTGCON |= (1 << HNPREQ);
}
/** Rejects a HNP from a connected device, indicating that both devices should remain in their
* current device/host roles.
*/
static inline void USB_OTG_Host_RejectHNP(void) ATTR_ALWAYS_INLINE;
static inline void USB_OTG_Host_RejectHNP(void)
{
OTGCON &= ~(1 << HNPREQ);
}
/** Indicates if the connected device is not currently sending a HNP request.
*
* \return Boolean \c true if a HNP is currently being issued by the connected device, \c false otherwise.
*/
static inline bool USB_OTG_Host_IsHNPReceived(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline bool USB_OTG_Host_IsHNPReceived(void)
{
return ((OTGCON & (1 << HNPREQ)) ? true : false);
}
#endif
/** @} */

View file

@ -0,0 +1,193 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2011.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2011 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, 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.
*/
#define __INCLUDE_FROM_USB_DRIVER
#include "../USBMode.h"
#if defined(USB_CAN_BE_HOST)
#include "../Pipe.h"
uint8_t USB_ControlPipeSize = PIPE_CONTROLPIPE_DEFAULT_SIZE;
bool Pipe_ConfigurePipe(const uint8_t Number,
const uint8_t Type,
const uint8_t Token,
const uint8_t EndpointNumber,
const uint16_t Size,
const uint8_t Banks)
{
#if defined(ORDERED_EP_CONFIG)
Pipe_SelectPipe(Number);
Pipe_EnablePipe();
UPCFG1X = 0;
UPCFG0X = ((Type << EPTYPE0) | Token | ((EndpointNumber & PIPE_EPNUM_MASK) << PEPNUM0));
UPCFG1X = ((1 << ALLOC) | Banks | Pipe_BytesToEPSizeMask(Size));
Pipe_SetInfiniteINRequests();
return Pipe_IsConfigured();
#else
for (uint8_t PNum = Number; PNum < PIPE_TOTAL_PIPES; PNum++)
{
uint8_t UPCFG0XTemp;
uint8_t UPCFG1XTemp;
uint8_t UPCFG2XTemp;
uint8_t UPCONXTemp;
uint8_t UPINRQXTemp;
uint8_t UPIENXTemp;
Pipe_SelectPipe(PNum);
if (PNum == Number)
{
UPCFG0XTemp = ((Type << EPTYPE0) | Token | ((EndpointNumber & PIPE_EPNUM_MASK) << PEPNUM0));
UPCFG1XTemp = ((1 << ALLOC) | Banks | Pipe_BytesToEPSizeMask(Size));
UPCFG2XTemp = 0;
UPCONXTemp = ((1 << PEN) | (1 << INMODE));
UPINRQXTemp = 0;
UPIENXTemp = 0;
}
else
{
UPCFG0XTemp = UPCFG0X;
UPCFG1XTemp = UPCFG1X;
UPCFG2XTemp = UPCFG2X;
UPCONXTemp = UPCONX;
UPINRQXTemp = UPINRQX;
UPIENXTemp = UPIENX;
}
if (!(UPCFG1XTemp & (1 << ALLOC)))
continue;
Pipe_DisablePipe();
UPCFG1X &= (1 << ALLOC);
Pipe_EnablePipe();
UPCFG0X = UPCFG0XTemp;
UPCFG1X = UPCFG1XTemp;
UPCFG2X = UPCFG2XTemp;
UPCONX = UPCONXTemp;
UPINRQX = UPINRQXTemp;
UPIENX = UPIENXTemp;
if (!(Pipe_IsConfigured()))
return false;
}
Pipe_SelectPipe(Number);
return true;
#endif
}
void Pipe_ClearPipes(void)
{
UPINT = 0;
for (uint8_t PNum = 0; PNum < PIPE_TOTAL_PIPES; PNum++)
{
Pipe_SelectPipe(PNum);
UPIENX = 0;
UPINTX = 0;
UPCFG1X = 0;
Pipe_DisablePipe();
}
}
bool Pipe_IsEndpointBound(const uint8_t EndpointAddress)
{
uint8_t PrevPipeNumber = Pipe_GetCurrentPipe();
for (uint8_t PNum = 0; PNum < PIPE_TOTAL_PIPES; PNum++)
{
Pipe_SelectPipe(PNum);
if (!(Pipe_IsConfigured()))
continue;
uint8_t PipeToken = Pipe_GetPipeToken();
bool PipeTokenCorrect = true;
if (PipeToken != PIPE_TOKEN_SETUP)
PipeTokenCorrect = (PipeToken == ((EndpointAddress & PIPE_EPDIR_MASK) ? PIPE_TOKEN_IN : PIPE_TOKEN_OUT));
if (PipeTokenCorrect && (Pipe_BoundEndpointNumber() == (EndpointAddress & PIPE_EPNUM_MASK)))
return true;
}
Pipe_SelectPipe(PrevPipeNumber);
return false;
}
uint8_t Pipe_WaitUntilReady(void)
{
#if (USB_STREAM_TIMEOUT_MS < 0xFF)
uint8_t TimeoutMSRem = USB_STREAM_TIMEOUT_MS;
#else
uint16_t TimeoutMSRem = USB_STREAM_TIMEOUT_MS;
#endif
uint16_t PreviousFrameNumber = USB_Host_GetFrameNumber();
for (;;)
{
if (Pipe_GetPipeToken() == PIPE_TOKEN_IN)
{
if (Pipe_IsINReceived())
return PIPE_READYWAIT_NoError;
}
else
{
if (Pipe_IsOUTReady())
return PIPE_READYWAIT_NoError;
}
if (Pipe_IsStalled())
return PIPE_READYWAIT_PipeStalled;
else if (USB_HostState == HOST_STATE_Unattached)
return PIPE_READYWAIT_DeviceDisconnected;
uint16_t CurrentFrameNumber = USB_Host_GetFrameNumber();
if (CurrentFrameNumber != PreviousFrameNumber)
{
PreviousFrameNumber = CurrentFrameNumber;
if (!(TimeoutMSRem--))
return PIPE_READYWAIT_Timeout;
}
}
}
#endif

View file

@ -0,0 +1,943 @@
/*
LUFA Library
Copyright (C) Dean Camera, 2011.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
Copyright 2011 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, 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
* \brief USB Pipe definitions for the AVR8 microcontrollers.
* \copydetails Group_PipeManagement_AVR8
*
* \note This file should not be included directly. It is automatically included as needed by the USB driver
* dispatch header located in LUFA/Drivers/USB/USB.h.
*/
/** \ingroup Group_PipeRW
* \defgroup Group_PipeRW_AVR8 Pipe Data Reading and Writing (AVR8)
* \brief Pipe data read/write definitions for the Atmel AVR8 architecture.
*
* Functions, macros, variables, enums and types related to data reading and writing from and to pipes.
*/
/** \ingroup Group_PipePrimitiveRW
* \defgroup Group_PipePrimitiveRW_AVR8 Read/Write of Primitive Data Types (AVR8)
* \brief Pipe primative data read/write definitions for the Atmel AVR8 architecture.
*
* Functions, macros, variables, enums and types related to data reading and writing of primitive data types
* from and to pipes.
*/
/** \ingroup Group_PipePacketManagement
* \defgroup Group_PipePacketManagement_AVR8 Pipe Packet Management (AVR8)
* \brief Pipe packet management definitions for the Atmel AVR8 architecture.
*
* Functions, macros, variables, enums and types related to packet management of pipes.
*/
/** \ingroup Group_PipeControlReq
* \defgroup Group_PipeControlReq_AVR8 Pipe Control Request Management (AVR8)
* \brief Pipe control request management definitions for the Atmel AVR8 architecture.
*
* Module for host mode request processing. This module allows for the transmission of standard, class and
* vendor control requests to the default control endpoint of an attached device while in host mode.
*
* \see Chapter 9 of the USB 2.0 specification.
*/
/** \ingroup Group_PipeManagement
* \defgroup Group_PipeManagement_AVR8 Pipe Management (AVR8)
* \brief Pipe management definitions for the Atmel AVR8 architecture.
*
* This module contains functions, macros and enums related to pipe management when in USB Host mode. This
* module contains the pipe management macros, as well as pipe interrupt and data send/receive functions
* for various data types.
*
* @{
*/
#ifndef __PIPE_AVR8_H__
#define __PIPE_AVR8_H__
/* Includes: */
#include "../../../../Common/Common.h"
#include "../USBTask.h"
/* Enable C linkage for C++ Compilers: */
#if defined(__cplusplus)
extern "C" {
#endif
/* Preprocessor Checks: */
#if !defined(__INCLUDE_FROM_USB_DRIVER)
#error Do not include this file directly. Include LUFA/Drivers/USB/USB.h instead.
#endif
/* Public Interface - May be used in end-application: */
/* Macros: */
/** \name Pipe Error Flag Masks */
//@{
/** Mask for \ref Pipe_GetErrorFlags(), indicating that an overflow error occurred in the pipe on the received data. */
#define PIPE_ERRORFLAG_OVERFLOW (1 << 6)
/** Mask for \ref Pipe_GetErrorFlags(), indicating that an underflow error occurred in the pipe on the received data. */
#define PIPE_ERRORFLAG_UNDERFLOW (1 << 5)
/** Mask for \ref Pipe_GetErrorFlags(), indicating that a CRC error occurred in the pipe on the received data. */
#define PIPE_ERRORFLAG_CRC16 (1 << 4)
/** Mask for \ref Pipe_GetErrorFlags(), indicating that a hardware timeout error occurred in the pipe. */
#define PIPE_ERRORFLAG_TIMEOUT (1 << 3)
/** Mask for \ref Pipe_GetErrorFlags(), indicating that a hardware PID error occurred in the pipe. */
#define PIPE_ERRORFLAG_PID (1 << 2)
/** Mask for \ref Pipe_GetErrorFlags(), indicating that a hardware data PID error occurred in the pipe. */
#define PIPE_ERRORFLAG_DATAPID (1 << 1)
/** Mask for \ref Pipe_GetErrorFlags(), indicating that a hardware data toggle error occurred in the pipe. */
#define PIPE_ERRORFLAG_DATATGL (1 << 0)
//@}
/** \name Pipe Token Masks */
//@{
/** Token mask for \ref Pipe_ConfigurePipe(). This sets the pipe as a SETUP token (for CONTROL type pipes),
* which will trigger a control request on the attached device when data is written to the pipe.
*/
#define PIPE_TOKEN_SETUP (0 << PTOKEN0)
/** Token mask for \ref Pipe_ConfigurePipe(). This sets the pipe as a IN token (for non-CONTROL type pipes),
* indicating that the pipe data will flow from device to host.
*/
#define PIPE_TOKEN_IN (1 << PTOKEN0)
/** Token mask for \ref Pipe_ConfigurePipe(). This sets the pipe as a OUT token (for non-CONTROL type pipes),
* indicating that the pipe data will flow from host to device.
*/
#define PIPE_TOKEN_OUT (2 << PTOKEN0)
//@}
/** \name Pipe Bank Mode Masks */
//@{
/** Mask for the bank mode selection for the \ref Pipe_ConfigurePipe() macro. This indicates that the pipe
* should have one single bank, which requires less USB FIFO memory but results in slower transfers as
* only one USB device (the AVR or the attached device) can access the pipe's bank at the one time.
*/
#define PIPE_BANK_SINGLE (0 << EPBK0)
/** Mask for the bank mode selection for the \ref Pipe_ConfigurePipe() macro. This indicates that the pipe
* should have two banks, which requires more USB FIFO memory but results in faster transfers as one
* USB device (the AVR or the attached device) can access one bank while the other accesses the second
* bank.
*/
#define PIPE_BANK_DOUBLE (1 << EPBK0)
//@}
/** Pipe address for the default control pipe, which always resides in address 0. This is
* defined for convenience to give more readable code when used with the pipe macros.
*/
#define PIPE_CONTROLPIPE 0
/** Default size of the default control pipe's bank, until altered by the Endpoint0Size value
* in the device descriptor of the attached device.
*/
#define PIPE_CONTROLPIPE_DEFAULT_SIZE 64
/** Pipe number mask, for masking against pipe addresses to retrieve the pipe's numerical address
* in the device.
*/
#define PIPE_PIPENUM_MASK 0x07
/** Total number of pipes (including the default control pipe at address 0) which may be used in
* the device. Different USB AVR models support different amounts of pipes, this value reflects
* the maximum number of pipes for the currently selected AVR model.
*/
#define PIPE_TOTAL_PIPES 7
/** Size in bytes of the largest pipe bank size possible in the device. Not all banks on each AVR
* model supports the largest bank size possible on the device; different pipe numbers support
* different maximum bank sizes. This value reflects the largest possible bank of any pipe on the
* currently selected USB AVR model.
*/
#define PIPE_MAX_SIZE 256
/** Endpoint number mask, for masking against endpoint addresses to retrieve the endpoint's
* numerical address in the attached device.
*/
#define PIPE_EPNUM_MASK 0x0F
/** Endpoint direction mask, for masking against endpoint addresses to retrieve the endpoint's
* direction for comparing with the \c ENDPOINT_DESCRIPTOR_DIR_* masks.
*/
#define PIPE_EPDIR_MASK 0x80
/* Enums: */
/** Enum for the possible error return codes of the \ref Pipe_WaitUntilReady() function.
*
* \ingroup Group_PipeRW_AVR8
*/
enum Pipe_WaitUntilReady_ErrorCodes_t
{
PIPE_READYWAIT_NoError = 0, /**< Pipe ready for next packet, no error. */
PIPE_READYWAIT_PipeStalled = 1, /**< The device stalled the pipe while waiting. */
PIPE_READYWAIT_DeviceDisconnected = 2, /**< Device was disconnected from the host while waiting. */
PIPE_READYWAIT_Timeout = 3, /**< The device failed to accept or send the next packet
* within the software timeout period set by the
* \ref USB_STREAM_TIMEOUT_MS macro.
*/
};
/* Inline Functions: */
/** Indicates the number of bytes currently stored in the current pipes's selected bank.
*
* \note The return width of this function may differ, depending on the maximum pipe bank size
* of the selected AVR model.
*
* \ingroup Group_PipeRW_AVR8
*
* \return Total number of bytes in the currently selected pipe's FIFO buffer.
*/
static inline uint16_t Pipe_BytesInPipe(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline uint16_t Pipe_BytesInPipe(void)
{
return UPBCX;
}
/** Returns the pipe address of the currently selected pipe. This is typically used to save the
* currently selected pipe number so that it can be restored after another pipe has been manipulated.
*
* \return Index of the currently selected pipe.
*/
static inline uint8_t Pipe_GetCurrentPipe(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline uint8_t Pipe_GetCurrentPipe(void)
{
return (UPNUM & PIPE_PIPENUM_MASK);
}
/** Selects the given pipe number. Any pipe operations which do not require the pipe number to be
* indicated will operate on the currently selected pipe.
*
* \param[in] PipeNumber Index of the pipe to select.
*/
static inline void Pipe_SelectPipe(const uint8_t PipeNumber) ATTR_ALWAYS_INLINE;
static inline void Pipe_SelectPipe(const uint8_t PipeNumber)
{
UPNUM = PipeNumber;
}
/** Resets the desired pipe, including the pipe banks and flags.
*
* \param[in] PipeNumber Index of the pipe to reset.
*/
static inline void Pipe_ResetPipe(const uint8_t PipeNumber) ATTR_ALWAYS_INLINE;
static inline void Pipe_ResetPipe(const uint8_t PipeNumber)
{
UPRST = (1 << PipeNumber);
UPRST = 0;
}
/** Enables the currently selected pipe so that data can be sent and received through it to and from
* an attached device.
*
* \pre The currently selected pipe must first be configured properly via \ref Pipe_ConfigurePipe().
*/
static inline void Pipe_EnablePipe(void) ATTR_ALWAYS_INLINE;
static inline void Pipe_EnablePipe(void)
{
UPCONX |= (1 << PEN);
}
/** Disables the currently selected pipe so that data cannot be sent and received through it to and
* from an attached device.
*/
static inline void Pipe_DisablePipe(void) ATTR_ALWAYS_INLINE;
static inline void Pipe_DisablePipe(void)
{
UPCONX &= ~(1 << PEN);
}
/** Determines if the currently selected pipe is enabled, but not necessarily configured.
*
* \return Boolean \c true if the currently selected pipe is enabled, \c false otherwise.
*/
static inline bool Pipe_IsEnabled(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline bool Pipe_IsEnabled(void)
{
return ((UPCONX & (1 << PEN)) ? true : false);
}
/** Gets the current pipe token, indicating the pipe's data direction and type.
*
* \return The current pipe token, as a \c PIPE_TOKEN_* mask.
*/
static inline uint8_t Pipe_GetPipeToken(void) ATTR_ALWAYS_INLINE;
static inline uint8_t Pipe_GetPipeToken(void)
{
return (UPCFG0X & (0x03 << PTOKEN0));
}
/** Sets the token for the currently selected pipe to one of the tokens specified by the \c PIPE_TOKEN_*
* masks. This can be used on CONTROL type pipes, to allow for bidirectional transfer of data during
* control requests, or on regular pipes to allow for half-duplex bidirectional data transfer to devices
* which have two endpoints of opposite direction sharing the same endpoint address within the device.
*
* \param[in] Token New pipe token to set the selected pipe to, as a \c PIPE_TOKEN_* mask.
*/
static inline void Pipe_SetPipeToken(const uint8_t Token) ATTR_ALWAYS_INLINE;
static inline void Pipe_SetPipeToken(const uint8_t Token)
{
UPCFG0X = ((UPCFG0X & ~(0x03 << PTOKEN0)) | Token);
}
/** Configures the currently selected pipe to allow for an unlimited number of IN requests. */
static inline void Pipe_SetInfiniteINRequests(void) ATTR_ALWAYS_INLINE;
static inline void Pipe_SetInfiniteINRequests(void)
{
UPCONX |= (1 << INMODE);
}
/** Configures the currently selected pipe to only allow the specified number of IN requests to be
* accepted by the pipe before it is automatically frozen.
*
* \param[in] TotalINRequests Total number of IN requests that the pipe may receive before freezing.
*/
static inline void Pipe_SetFiniteINRequests(const uint8_t TotalINRequests) ATTR_ALWAYS_INLINE;
static inline void Pipe_SetFiniteINRequests(const uint8_t TotalINRequests)
{
UPCONX &= ~(1 << INMODE);
UPINRQX = TotalINRequests;
}
/** Determines if the currently selected pipe is configured.
*
* \return Boolean \c true if the selected pipe is configured, \c false otherwise.
*/
static inline bool Pipe_IsConfigured(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline bool Pipe_IsConfigured(void)
{
return ((UPSTAX & (1 << CFGOK)) ? true : false);
}
/** Retrieves the endpoint number of the endpoint within the attached device that the currently selected
* pipe is bound to.
*
* \return Endpoint number the currently selected pipe is bound to.
*/
static inline uint8_t Pipe_BoundEndpointNumber(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline uint8_t Pipe_BoundEndpointNumber(void)
{
return ((UPCFG0X >> PEPNUM0) & PIPE_EPNUM_MASK);
}
/** Sets the period between interrupts for an INTERRUPT type pipe to a specified number of milliseconds.
*
* \param[in] Milliseconds Number of milliseconds between each pipe poll.
*/
static inline void Pipe_SetInterruptPeriod(const uint8_t Milliseconds) ATTR_ALWAYS_INLINE;
static inline void Pipe_SetInterruptPeriod(const uint8_t Milliseconds)
{
UPCFG2X = Milliseconds;
}
/** Returns a mask indicating which pipe's interrupt periods have elapsed, indicating that the pipe should
* be serviced.
*
* \return Mask whose bits indicate which pipes have interrupted.
*/
static inline uint8_t Pipe_GetPipeInterrupts(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline uint8_t Pipe_GetPipeInterrupts(void)
{
return UPINT;
}
/** Determines if the specified pipe number has interrupted (valid only for INTERRUPT type
* pipes).
*
* \param[in] PipeNumber Index of the pipe whose interrupt flag should be tested.
*
* \return Boolean \c true if the specified pipe has interrupted, \c false otherwise.
*/
static inline bool Pipe_HasPipeInterrupted(const uint8_t PipeNumber) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline bool Pipe_HasPipeInterrupted(const uint8_t PipeNumber)
{
return ((UPINT & (1 << PipeNumber)) ? true : false);
}
/** Unfreezes the selected pipe, allowing it to communicate with an attached device. */
static inline void Pipe_Unfreeze(void) ATTR_ALWAYS_INLINE;
static inline void Pipe_Unfreeze(void)
{
UPCONX &= ~(1 << PFREEZE);
}
/** Freezes the selected pipe, preventing it from communicating with an attached device. */
static inline void Pipe_Freeze(void) ATTR_ALWAYS_INLINE;
static inline void Pipe_Freeze(void)
{
UPCONX |= (1 << PFREEZE);
}
/** Determines if the currently selected pipe is frozen, and not able to accept data.
*
* \return Boolean \c true if the currently selected pipe is frozen, \c false otherwise.
*/
static inline bool Pipe_IsFrozen(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline bool Pipe_IsFrozen(void)
{
return ((UPCONX & (1 << PFREEZE)) ? true : false);
}
/** Clears the master pipe error flag. */
static inline void Pipe_ClearError(void) ATTR_ALWAYS_INLINE;
static inline void Pipe_ClearError(void)
{
UPINTX &= ~(1 << PERRI);
}
/** Determines if the master pipe error flag is set for the currently selected pipe, indicating that
* some sort of hardware error has occurred on the pipe.
*
* \see \ref Pipe_GetErrorFlags() macro for information on retrieving the exact error flag.
*
* \return Boolean \c true if an error has occurred on the selected pipe, \c false otherwise.
*/
static inline bool Pipe_IsError(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline bool Pipe_IsError(void)
{
return ((UPINTX & (1 << PERRI)) ? true : false);
}
/** Clears all the currently selected pipe's hardware error flags, but does not clear the master error
* flag for the pipe.
*/
static inline void Pipe_ClearErrorFlags(void) ATTR_ALWAYS_INLINE;
static inline void Pipe_ClearErrorFlags(void)
{
UPERRX = 0;
}
/** Gets a mask of the hardware error flags which have occurred on the currently selected pipe. This
* value can then be masked against the \c PIPE_ERRORFLAG_* masks to determine what error has occurred.
*
* \return Mask comprising of \c PIPE_ERRORFLAG_* bits indicating what error has occurred on the selected pipe.
*/
static inline uint8_t Pipe_GetErrorFlags(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline uint8_t Pipe_GetErrorFlags(void)
{
return ((UPERRX & (PIPE_ERRORFLAG_CRC16 | PIPE_ERRORFLAG_TIMEOUT |
PIPE_ERRORFLAG_PID | PIPE_ERRORFLAG_DATAPID |
PIPE_ERRORFLAG_DATATGL)) |
(UPSTAX & (PIPE_ERRORFLAG_OVERFLOW | PIPE_ERRORFLAG_UNDERFLOW)));
}
/** Retrieves the number of busy banks in the currently selected pipe, which have been queued for
* transmission via the \ref Pipe_ClearOUT() command, or are awaiting acknowledgement via the
* \ref Pipe_ClearIN() command.
*
* \ingroup Group_PipePacketManagement_AVR8
*
* \return Total number of busy banks in the selected pipe.
*/
static inline uint8_t Pipe_GetBusyBanks(void)
{
return (UPSTAX & (0x03 << NBUSYBK0));
}
/** Determines if the currently selected pipe may be read from (if data is waiting in the pipe
* bank and the pipe is an IN direction, or if the bank is not yet full if the pipe is an OUT
* direction). This function will return false if an error has occurred in the pipe, or if the pipe
* is an IN direction and no packet (or an empty packet) has been received, or if the pipe is an OUT
* direction and the pipe bank is full.
*
* \note This function is not valid on CONTROL type pipes.
*
* \ingroup Group_PipePacketManagement_AVR8
*
* \return Boolean \c true if the currently selected pipe may be read from or written to, depending
* on its direction.
*/
static inline bool Pipe_IsReadWriteAllowed(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline bool Pipe_IsReadWriteAllowed(void)
{
return ((UPINTX & (1 << RWAL)) ? true : false);
}
/** Determines if a packet has been received on the currently selected IN pipe from the attached device.
*
* \ingroup Group_PipePacketManagement_AVR8
*
* \return Boolean \c true if the current pipe has received an IN packet, \c false otherwise.
*/
static inline bool Pipe_IsINReceived(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline bool Pipe_IsINReceived(void)
{
return ((UPINTX & (1 << RXINI)) ? true : false);
}
/** Determines if the currently selected OUT pipe is ready to send an OUT packet to the attached device.
*
* \ingroup Group_PipePacketManagement_AVR8
*
* \return Boolean \c true if the current pipe is ready for an OUT packet, \c false otherwise.
*/
static inline bool Pipe_IsOUTReady(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline bool Pipe_IsOUTReady(void)
{
return ((UPINTX & (1 << TXOUTI)) ? true : false);
}
/** Determines if no SETUP request is currently being sent to the attached device on the selected
* CONTROL type pipe.
*
* \ingroup Group_PipePacketManagement_AVR8
*
* \return Boolean \c true if the current pipe is ready for a SETUP packet, \c false otherwise.
*/
static inline bool Pipe_IsSETUPSent(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline bool Pipe_IsSETUPSent(void)
{
return ((UPINTX & (1 << TXSTPI)) ? true : false);
}
/** Sends the currently selected CONTROL type pipe's contents to the device as a SETUP packet.
*
* \ingroup Group_PipePacketManagement_AVR8
*/
static inline void Pipe_ClearSETUP(void) ATTR_ALWAYS_INLINE;
static inline void Pipe_ClearSETUP(void)
{
UPINTX &= ~((1 << TXSTPI) | (1 << FIFOCON));
}
/** Acknowledges the reception of a setup IN request from the attached device on the currently selected
* pipe, freeing the bank ready for the next packet.
*
* \ingroup Group_PipePacketManagement_AVR8
*/
static inline void Pipe_ClearIN(void) ATTR_ALWAYS_INLINE;
static inline void Pipe_ClearIN(void)
{
UPINTX &= ~((1 << RXINI) | (1 << FIFOCON));
}
/** Sends the currently selected pipe's contents to the device as an OUT packet on the selected pipe, freeing
* the bank ready for the next packet.
*
* \ingroup Group_PipePacketManagement_AVR8
*/
static inline void Pipe_ClearOUT(void) ATTR_ALWAYS_INLINE;
static inline void Pipe_ClearOUT(void)
{
UPINTX &= ~((1 << TXOUTI) | (1 << FIFOCON));
}
/** Determines if the device sent a NAK (Negative Acknowledge) in response to the last sent packet on
* the currently selected pipe. This occurs when the host sends a packet to the device, but the device
* is not currently ready to handle the packet (i.e. its endpoint banks are full). Once a NAK has been
* received, it must be cleared using \ref Pipe_ClearNAKReceived() before the previous (or any other) packet
* can be re-sent.
*
* \ingroup Group_PipePacketManagement_AVR8
*
* \return Boolean \c true if an NAK has been received on the current pipe, \c false otherwise.
*/
static inline bool Pipe_IsNAKReceived(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline bool Pipe_IsNAKReceived(void)
{
return ((UPINTX & (1 << NAKEDI)) ? true : false);
}
/** Clears the NAK condition on the currently selected pipe.
*
* \ingroup Group_PipePacketManagement_AVR8
*
* \see \ref Pipe_IsNAKReceived() for more details.
*/
static inline void Pipe_ClearNAKReceived(void) ATTR_ALWAYS_INLINE;
static inline void Pipe_ClearNAKReceived(void)
{
UPINTX &= ~(1 << NAKEDI);
}
/** Determines if the currently selected pipe has had the STALL condition set by the attached device.
*
* \ingroup Group_PipePacketManagement_AVR8
*
* \return Boolean \c true if the current pipe has been stalled by the attached device, \c false otherwise.
*/
static inline bool Pipe_IsStalled(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline bool Pipe_IsStalled(void)
{
return ((UPINTX & (1 << RXSTALLI)) ? true : false);
}
/** Clears the STALL condition detection flag on the currently selected pipe, but does not clear the
* STALL condition itself (this must be done via a ClearFeature control request to the device).
*
* \ingroup Group_PipePacketManagement_AVR8
*/
static inline void Pipe_ClearStall(void) ATTR_ALWAYS_INLINE;
static inline void Pipe_ClearStall(void)
{
UPINTX &= ~(1 << RXSTALLI);
}
/** Reads one byte from the currently selected pipe's bank, for OUT direction pipes.
*
* \ingroup Group_PipePrimitiveRW_AVR8
*
* \return Next byte in the currently selected pipe's FIFO buffer.
*/
static inline uint8_t Pipe_Read_Byte(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline uint8_t Pipe_Read_Byte(void)
{
return UPDATX;
}
/** Writes one byte from the currently selected pipe's bank, for IN direction pipes.
*
* \ingroup Group_PipePrimitiveRW_AVR8
*
* \param[in] Byte Next byte to write into the the currently selected pipe's FIFO buffer.
*/
static inline void Pipe_Write_Byte(const uint8_t Byte) ATTR_ALWAYS_INLINE;
static inline void Pipe_Write_Byte(const uint8_t Byte)
{
UPDATX = Byte;
}
/** Discards one byte from the currently selected pipe's bank, for OUT direction pipes.
*
* \ingroup Group_PipePrimitiveRW_AVR8
*/
static inline void Pipe_Discard_Byte(void) ATTR_ALWAYS_INLINE;
static inline void Pipe_Discard_Byte(void)
{
uint8_t Dummy;
Dummy = UPDATX;
}
/** Reads two bytes from the currently selected pipe's bank in little endian format, for OUT
* direction pipes.
*
* \ingroup Group_PipePrimitiveRW_AVR8
*
* \return Next word in the currently selected pipe's FIFO buffer.
*/
static inline uint16_t Pipe_Read_Word_LE(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline uint16_t Pipe_Read_Word_LE(void)
{
union
{
uint16_t Word;
uint8_t Bytes[2];
} Data;
Data.Bytes[0] = UPDATX;
Data.Bytes[1] = UPDATX;
return Data.Word;
}
/** Reads two bytes from the currently selected pipe's bank in big endian format, for OUT
* direction pipes.
*
* \ingroup Group_PipePrimitiveRW_AVR8
*
* \return Next word in the currently selected pipe's FIFO buffer.
*/
static inline uint16_t Pipe_Read_Word_BE(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline uint16_t Pipe_Read_Word_BE(void)
{
union
{
uint16_t Word;
uint8_t Bytes[2];
} Data;
Data.Bytes[1] = UPDATX;
Data.Bytes[0] = UPDATX;
return Data.Word;
}
/** Writes two bytes to the currently selected pipe's bank in little endian format, for IN
* direction pipes.
*
* \ingroup Group_PipePrimitiveRW_AVR8
*
* \param[in] Word Next word to write to the currently selected pipe's FIFO buffer.
*/
static inline void Pipe_Write_Word_LE(const uint16_t Word) ATTR_ALWAYS_INLINE;
static inline void Pipe_Write_Word_LE(const uint16_t Word)
{
UPDATX = (Word & 0xFF);
UPDATX = (Word >> 8);
}
/** Writes two bytes to the currently selected pipe's bank in big endian format, for IN
* direction pipes.
*
* \ingroup Group_PipePrimitiveRW_AVR8
*
* \param[in] Word Next word to write to the currently selected pipe's FIFO buffer.
*/
static inline void Pipe_Write_Word_BE(const uint16_t Word) ATTR_ALWAYS_INLINE;
static inline void Pipe_Write_Word_BE(const uint16_t Word)
{
UPDATX = (Word >> 8);
UPDATX = (Word & 0xFF);
}
/** Discards two bytes from the currently selected pipe's bank, for OUT direction pipes.
*
* \ingroup Group_PipePrimitiveRW_AVR8
*/
static inline void Pipe_Discard_Word(void) ATTR_ALWAYS_INLINE;
static inline void Pipe_Discard_Word(void)
{
uint8_t Dummy;
Dummy = UPDATX;
Dummy = UPDATX;
}
/** Reads four bytes from the currently selected pipe's bank in little endian format, for OUT
* direction pipes.
*
* \ingroup Group_PipePrimitiveRW_AVR8
*
* \return Next double word in the currently selected pipe's FIFO buffer.
*/
static inline uint32_t Pipe_Read_DWord_LE(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline uint32_t Pipe_Read_DWord_LE(void)
{
union
{
uint32_t DWord;
uint8_t Bytes[4];
} Data;
Data.Bytes[0] = UPDATX;
Data.Bytes[1] = UPDATX;
Data.Bytes[2] = UPDATX;
Data.Bytes[3] = UPDATX;
return Data.DWord;
}
/** Reads four bytes from the currently selected pipe's bank in big endian format, for OUT
* direction pipes.
*
* \ingroup Group_PipePrimitiveRW_AVR8
*
* \return Next double word in the currently selected pipe's FIFO buffer.
*/
static inline uint32_t Pipe_Read_DWord_BE(void) ATTR_WARN_UNUSED_RESULT ATTR_ALWAYS_INLINE;
static inline uint32_t Pipe_Read_DWord_BE(void)
{
union
{
uint32_t DWord;
uint8_t Bytes[4];
} Data;
Data.Bytes[3] = UPDATX;
Data.Bytes[2] = UPDATX;
Data.Bytes[1] = UPDATX;
Data.Bytes[0] = UPDATX;
return Data.DWord;
}
/** Writes four bytes to the currently selected pipe's bank in little endian format, for IN
* direction pipes.
*
* \ingroup Group_PipePrimitiveRW_AVR8
*
* \param[in] DWord Next double word to write to the currently selected pipe's FIFO buffer.
*/
static inline void Pipe_Write_DWord_LE(const uint32_t DWord) ATTR_ALWAYS_INLINE;
static inline void Pipe_Write_DWord_LE(const uint32_t DWord)
{
UPDATX = (DWord & 0xFF);
UPDATX = (DWord >> 8);
UPDATX = (DWord >> 16);
UPDATX = (DWord >> 24);
}
/** Writes four bytes to the currently selected pipe's bank in big endian format, for IN
* direction pipes.
*
* \ingroup Group_PipePrimitiveRW_AVR8
*
* \param[in] DWord Next double word to write to the currently selected pipe's FIFO buffer.
*/
static inline void Pipe_Write_DWord_BE(const uint32_t DWord) ATTR_ALWAYS_INLINE;
static inline void Pipe_Write_DWord_BE(const uint32_t DWord)
{
UPDATX = (DWord >> 24);
UPDATX = (DWord >> 16);
UPDATX = (DWord >> 8);
UPDATX = (DWord & 0xFF);
}
/** Discards four bytes from the currently selected pipe's bank, for OUT direction pipes.
*
* \ingroup Group_PipePrimitiveRW_AVR8
*/
static inline void Pipe_Discard_DWord(void) ATTR_ALWAYS_INLINE;
static inline void Pipe_Discard_DWord(void)
{
uint8_t Dummy;
Dummy = UPDATX;
Dummy = UPDATX;
Dummy = UPDATX;
Dummy = UPDATX;
}
/* External Variables: */
/** Global indicating the maximum packet size of the default control pipe located at address
* 0 in the device. This value is set to the value indicated in the attached device's device
* descriptor once the USB interface is initialized into host mode and a device is attached
* to the USB bus.
*
* \note This variable should be treated as read-only in the user application, and never manually
* changed in value.
*/
extern uint8_t USB_ControlPipeSize;
/* Function Prototypes: */
/** Configures the specified pipe number with the given pipe type, token, target endpoint number in the
* attached device, bank size and banking mode.
*
* A newly configured pipe is frozen by default, and must be unfrozen before use via the \ref Pipe_Unfreeze()
* before being used. Pipes should be kept frozen unless waiting for data from a device while in IN mode, or
* sending data to the device in OUT mode. IN type pipes are also automatically configured to accept infinite
* numbers of IN requests without automatic freezing - this can be overridden by a call to
* \ref Pipe_SetFiniteINRequests().
*
* \param[in] Number Pipe number to configure. This must be more than 0 and less than \ref PIPE_TOTAL_PIPES.
*
* \param[in] Type Type of pipe to configure, an \c EP_TYPE_* mask. Not all pipe types are available on Low
* Speed USB devices - refer to the USB 2.0 specification.
*
* \param[in] Token Pipe data token, either \ref PIPE_TOKEN_SETUP, \ref PIPE_TOKEN_OUT or \ref PIPE_TOKEN_IN.
* All pipes (except Control type) are unidirectional - data may only be read from or
* written to the pipe bank based on its direction, not both.
*
* \param[in] EndpointNumber Endpoint index within the attached device that the pipe should interface to.
*
* \param[in] Size Size of the pipe's bank, where packets are stored before they are transmitted to
* the USB device, or after they have been received from the USB device (depending on
* the pipe's data direction). The bank size must indicate the maximum packet size that
* the pipe can handle.
*
* \param[in] Banks Number of banks to use for the pipe being configured, a \c PIPE_BANK_* mask. More banks
* uses more USB DPRAM, but offers better performance. Isochronous type pipes <b>must</b>
* have at least two banks.
*
* \note When the \c ORDERED_EP_CONFIG compile time option is used, Pipes <b>must</b> be configured in ascending order,
* or bank corruption will occur.
* \n\n
*
* \note Certain models of USB AVR's pipes may have different maximum packet sizes based on the pipe's
* index - refer to the chosen USB AVR's datasheet to determine the maximum bank size for each pipe.
* \n\n
*
* \note The default control pipe should not be manually configured by the user application, as it is
* automatically configured by the library internally.
* \n\n
*
* \note This routine will automatically select the specified pipe upon success. Upon failure, the pipe which
* failed to reconfigure correctly will be selected.
*
* \return Boolean \c true if the configuration succeeded, \c false otherwise.
*/
bool Pipe_ConfigurePipe(const uint8_t Number,
const uint8_t Type,
const uint8_t Token,
const uint8_t EndpointNumber,
const uint16_t Size,
const uint8_t Banks);
/** Spin-loops until the currently selected non-control pipe is ready for the next packed of data to be read
* or written to it, aborting in the case of an error condition (such as a timeout or device disconnect).
*
* \ingroup Group_PipeRW_AVR8
*
* \return A value from the \ref Pipe_WaitUntilReady_ErrorCodes_t enum.
*/
uint8_t Pipe_WaitUntilReady(void);
/** Determines if a pipe has been bound to the given device endpoint address. If a pipe which is bound to the given
* endpoint is found, it is automatically selected.
*
* \param[in] EndpointAddress Address and direction mask of the endpoint within the attached device to check.
*
* \return Boolean \c true if a pipe bound to the given endpoint address of the specified direction is found,
* \c false otherwise.
*/
bool Pipe_IsEndpointBound(const uint8_t EndpointAddress);
/* Private Interface - For use in library only: */
#if !defined(__DOXYGEN__)
/* Macros: */
#if !defined(ENDPOINT_CONTROLEP)
#define ENDPOINT_CONTROLEP 0
#endif
/* Inline Functions: */
static inline uint8_t Pipe_BytesToEPSizeMask(const uint16_t Bytes) ATTR_WARN_UNUSED_RESULT ATTR_CONST ATTR_ALWAYS_INLINE;
static inline uint8_t Pipe_BytesToEPSizeMask(const uint16_t Bytes)
{
uint8_t MaskVal = 0;
uint16_t CheckBytes = 8;
while ((CheckBytes < Bytes) && (CheckBytes < PIPE_MAX_SIZE))
{
MaskVal++;
CheckBytes <<= 1;
}
return (MaskVal << EPSIZE0);
}
/* Function Prototypes: */
void Pipe_ClearPipes(void);
#endif
/* Disable C linkage for C++ Compilers: */
#if defined(__cplusplus)
}
#endif
#endif
/** @} */

Some files were not shown because too many files have changed in this diff Show more