at91work/usb-device-cdc-serial-project/main.c

729 lines
28 KiB
C

/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support
* ----------------------------------------------------------------------------
* Copyright (c) 2008, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/
//-----------------------------------------------------------------------------
/// \dir "USB CDC serial converter"
///
/// !!!Purpose
///
/// The USB CDC Serial Project will help you to get familiar with the
/// USB Device Port(UDP) and USART interface on AT91SAM microcontrollers. Also
/// it can help you to be familiar with the USB Framework that is used for
/// rapid development of USB-compliant class drivers such as USB Communication
/// Device class (CDC).
///
/// You can find following information depends on your needs:
/// - Sample usage of USB CDC driver and USART driver.
/// - USB CDC driver development based on the AT91 USB Framework.
/// - USB enumerate sequence, the standard and class-specific descriptors and
/// requests handling.
/// - The initialize sequence and usage of UDP interface.
/// - The initialize sequence and usage of USART interface with PDC.
///
/// !See
/// - usart: USART interface driver
/// - tc: TIMER/COUNTER interface driver
/// - usb: USB Framework, USB CDC driver and UDP interface driver
/// - "AT91 USB device framework"
/// - "USBD API"
/// - "cdc-serial"
/// - "USB CDC Serial Device"
/// - "USB CDC Serial Host Driver"
///
/// !!!Requirements
///
/// This package can be used with all Atmel evaluation kits that have both
/// UDP and USART interface.
///
/// The current supported board list:
/// - at91sam7s-ek (exclude at91sam7s32)
/// - at91sam7x-ek
/// - at91sam7xc-ek
/// - at91sam7a3-ek
/// - at91sam7se-ek
/// - at91sam9260-ek
/// - at91sam9263-ek
///
/// !!!Description
///
/// When an EK running this program connected to a host (PC for example), with
/// USB cable, the EK appears as a Seriao COM port for the host, after driver
/// installation with the offered 6119.inf. Then the host can send or receive
/// data through the port with host software. The data stream from the host is
/// then sent to the EK, and forward to USART port of AT91SAM chips. The USART
/// port of the EK is monitored by the timer and the incoming data will be sent
/// to the host.
///
/// !!!Usage
///
/// -# Build the program and download it inside the evaluation board. Please
/// refer to the
/// <a href="http://www.atmel.com/dyn/resources/prod_documents/doc6224.pdf">
/// SAM-BA User Guide</a>, the
/// <a href="http://www.atmel.com/dyn/resources/prod_documents/doc6310.pdf">
/// GNU-Based Software Development</a> application note or to the
/// <a href="ftp://ftp.iar.se/WWWfiles/arm/Guides/EWARM_UserGuide.ENU.pdf">
/// IAR EWARM User Guide</a>, depending on your chosen solution.
/// -# On the computer, open and configure a terminal application
/// (e.g. HyperTerminal on Microsoft Windows) with these settings:
/// - 115200 bauds
/// - 8 bits of data
/// - No parity
/// - 1 stop bit
/// - No flow control
/// -# Start the application.
/// -# In the terminal window, the following text should appear:
/// \code
/// -- USB Device CDC Serial Project xxx --
/// -- AT91xxxxxx-xx
/// -- Compiled: xxx xx xxxx xx:xx:xx --
/// \endcode
/// -# When connecting USB cable to windows, the LED blinks, and the host
/// reports a new USB %device attachment (if it's the first time you connect
/// an %audio speaker demo board to your host). You can use the inf file
/// at91lib\\usb\\device\\cdc-serial\\drv\\6119.inf to install the serial
/// port. Then new "AT91 USB to Serial Converter (COMx)" appears in the
/// hardware %device list.
/// -# You can run hyperterminal to send data to the port. And it can be seen
/// at the other hyperterminal connected to the USART port of the EK.
///
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/// \unit
///
/// !Purpose
///
/// This file contains all the specific code for the
/// usb-device-cdc-serial-project
///
/// !Contents
///
/// The code can be roughly broken down as follows:
/// - Configuration functions
/// - VBus_Configure
/// - PIO & Timer configurations in start of main
/// - Interrupt handlers
/// - ISR_Vbus
/// - ISR_Timer0
/// - ISR_Usart0
/// - Callback functions
/// - UsbDataReceived
/// - The main function, which implements the program behavior
///
/// Please refer to the list of functions in the #Overview# tab of this unit
/// for more detailed information.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Headers
//------------------------------------------------------------------------------
#include <board.h>
#include <pio/pio.h>
#include <pio/pio_it.h>
#include <aic/aic.h>
#include <tc/tc.h>
#include <usart/usart.h>
#include <utility/trace.h>
#include <utility/led.h>
#include <usb/device/cdc-serial/CDCDSerialDriver.h>
#include <usb/device/cdc-serial/CDCDSerialDriverDescriptors.h>
#include <pmc/pmc.h>
//------------------------------------------------------------------------------
// Definitions
//------------------------------------------------------------------------------
#ifndef AT91C_ID_TC0
#define AT91C_ID_TC0 AT91C_ID_TC
#endif
/// Size in bytes of the buffer used for reading data from the USB & USART
#define DATABUFFERSIZE \
BOARD_USB_ENDPOINTS_MAXPACKETSIZE(CDCDSerialDriverDescriptors_DATAIN)
/// Use for power management
#define STATE_IDLE 0
/// The USB device is in suspend state
#define STATE_SUSPEND 4
/// The USB device is in resume state
#define STATE_RESUME 5
//------------------------------------------------------------------------------
// Internal variables
//------------------------------------------------------------------------------
/// State of USB, for suspend and resume
unsigned char USBState = STATE_IDLE;
/// List of pins that must be configured for use by the application.
static const Pin pins[] = {PIN_USART0_TXD, PIN_USART0_RXD};
/// Double-buffer for storing incoming USART data.
static unsigned char usartBuffers[2][DATABUFFERSIZE];
/// Current USART buffer index.
static unsigned char usartCurrentBuffer = 0;
/// Buffer for storing incoming USB data.
static unsigned char usbBuffer[DATABUFFERSIZE];
//------------------------------------------------------------------------------
// VBus monitoring (optional)
//------------------------------------------------------------------------------
#if defined(PIN_USB_VBUS)
#define VBUS_CONFIGURE() VBus_Configure()
/// VBus pin instance.
static const Pin pinVbus = PIN_USB_VBUS;
//------------------------------------------------------------------------------
/// Handles interrupts coming from PIO controllers.
//------------------------------------------------------------------------------
static void ISR_Vbus(const Pin *pPin)
{
// Check current level on VBus
if (PIO_Get(&pinVbus)) {
TRACE_INFO("VBUS conn\n\r");
USBD_Connect();
}
else {
TRACE_INFO("VBUS discon\n\r");
USBD_Disconnect();
}
}
//------------------------------------------------------------------------------
/// Configures the VBus pin to trigger an interrupt when the level on that pin
/// changes.
//------------------------------------------------------------------------------
static void VBus_Configure( void )
{
TRACE_INFO("VBus configuration\n\r");
// Configure PIO
PIO_Configure(&pinVbus, 1);
PIO_ConfigureIt(&pinVbus, ISR_Vbus);
PIO_EnableIt(&pinVbus);
// Check current level on VBus
if (PIO_Get(&pinVbus)) {
// if VBUS present, force the connect
TRACE_INFO("VBUS conn\n\r");
USBD_Connect();
}
else {
USBD_Disconnect();
}
}
#else
#define VBUS_CONFIGURE() USBD_Connect()
#endif //#if defined(PIN_USB_VBUS)
#if defined (CP15_PRESENT)
//------------------------------------------------------------------------------
/// Put the CPU in 32kHz, disable PLL, main oscillator
/// Put voltage regulator in standby mode
//------------------------------------------------------------------------------
void LowPowerMode(void)
{
PMC_CPUInIdleMode();
}
//------------------------------------------------------------------------------
/// Put voltage regulator in normal mode
/// Return the CPU to normal speed 48MHz, enable PLL, main oscillator
//------------------------------------------------------------------------------
void NormalPowerMode(void)
{
}
#elif defined(at91sam7a3)
//------------------------------------------------------------------------------
/// Put the CPU in 32kHz, disable PLL, main oscillator
//------------------------------------------------------------------------------
void LowPowerMode(void)
{
// MCK=48MHz to MCK=32kHz
// MCK = SLCK/2 : change source first from 48 000 000 to 18. / 2 = 9M
AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_PRES_CLK_2;
while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
// MCK=SLCK : then change prescaler
AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_CSS_SLOW_CLK;
while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
// disable PLL
AT91C_BASE_PMC->PMC_PLLR = 0;
// Disable Main Oscillator
AT91C_BASE_PMC->PMC_MOR = 0;
PMC_DisableProcessorClock();
}
//------------------------------------------------------------------------------
/// Return the CPU to normal speed 48MHz, enable PLL, main oscillator
//------------------------------------------------------------------------------
void NormalPowerMode(void)
{
// MCK=32kHz to MCK=48MHz
// enable Main Oscillator
AT91C_BASE_PMC->PMC_MOR = (( (AT91C_CKGR_OSCOUNT & (0x06 <<8)) | AT91C_CKGR_MOSCEN ));
while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MOSCS ) );
// enable PLL@96MHz
AT91C_BASE_PMC->PMC_PLLR = ((AT91C_CKGR_DIV & 0x0E) |
(AT91C_CKGR_PLLCOUNT & (28<<8)) |
(AT91C_CKGR_MUL & (0x48<<16)));
while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCK ) );
while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1 ;
// MCK=SLCK/2 : change prescaler first
AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_PRES_CLK_2;
while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
// MCK=PLLCK/2 : then change source
AT91C_BASE_PMC->PMC_MCKR |= AT91C_PMC_CSS_PLL_CLK ;
while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
}
#elif defined (at91sam7se)
//------------------------------------------------------------------------------
/// Put the CPU in 32kHz, disable PLL, main oscillator
/// Put voltage regulator in standby mode
//------------------------------------------------------------------------------
void LowPowerMode(void)
{
// MCK=48MHz to MCK=32kHz
// MCK = SLCK/2 : change source first from 48 000 000 to 18. / 2 = 9M
AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_PRES_CLK_2;
while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
// MCK=SLCK : then change prescaler
AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_CSS_SLOW_CLK;
while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
// disable PLL
AT91C_BASE_PMC->PMC_PLLR = 0;
// Disable Main Oscillator
AT91C_BASE_PMC->PMC_MOR = 0;
// Voltage regulator in standby mode : Enable VREG Low Power Mode
AT91C_BASE_VREG->VREG_MR |= AT91C_VREG_PSTDBY;
PMC_DisableProcessorClock();
}
//------------------------------------------------------------------------------
/// Put voltage regulator in normal mode
/// Return the CPU to normal speed 48MHz, enable PLL, main oscillator
//------------------------------------------------------------------------------
void NormalPowerMode(void)
{
// Voltage regulator in normal mode : Disable VREG Low Power Mode
AT91C_BASE_VREG->VREG_MR &= ~AT91C_VREG_PSTDBY;
// MCK=32kHz to MCK=48MHz
// enable Main Oscillator
AT91C_BASE_PMC->PMC_MOR = (( (AT91C_CKGR_OSCOUNT & (0x06 <<8)) | AT91C_CKGR_MOSCEN ));
while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MOSCS ) );
// enable PLL@96MHz
AT91C_BASE_PMC->PMC_PLLR = ((AT91C_CKGR_DIV & 0x0E) |
(AT91C_CKGR_PLLCOUNT & (28<<8)) |
(AT91C_CKGR_MUL & (0x48<<16)));
while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCK ) );
while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1 ;
// MCK=SLCK/2 : change prescaler first
AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_PRES_CLK_2;
while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
// MCK=PLLCK/2 : then change source
AT91C_BASE_PMC->PMC_MCKR |= AT91C_PMC_CSS_PLL_CLK ;
while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
}
#elif defined (at91sam7s)
//------------------------------------------------------------------------------
/// Put the CPU in 32kHz, disable PLL, main oscillator
/// Put voltage regulator in standby mode
//------------------------------------------------------------------------------
void LowPowerMode(void)
{
// MCK=48MHz to MCK=32kHz
// MCK = SLCK/2 : change source first from 48 000 000 to 18. / 2 = 9M
AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_PRES_CLK_2;
while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
// MCK=SLCK : then change prescaler
AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_CSS_SLOW_CLK;
while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
// disable PLL
AT91C_BASE_PMC->PMC_PLLR = 0;
// Disable Main Oscillator
AT91C_BASE_PMC->PMC_MOR = 0;
// Voltage regulator in standby mode : Enable VREG Low Power Mode
AT91C_BASE_VREG->VREG_MR |= AT91C_VREG_PSTDBY;
PMC_DisableProcessorClock();
}
//------------------------------------------------------------------------------
/// Put voltage regulator in normal mode
/// Return the CPU to normal speed 48MHz, enable PLL, main oscillator
//------------------------------------------------------------------------------
void NormalPowerMode(void)
{
// Voltage regulator in normal mode : Disable VREG Low Power Mode
AT91C_BASE_VREG->VREG_MR &= ~AT91C_VREG_PSTDBY;
// MCK=32kHz to MCK=48MHz
// enable Main Oscillator
AT91C_BASE_PMC->PMC_MOR = (( (AT91C_CKGR_OSCOUNT & (0x06 <<8)) | AT91C_CKGR_MOSCEN ));
while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MOSCS ) );
// enable PLL@96MHz
AT91C_BASE_PMC->PMC_PLLR = ((AT91C_CKGR_DIV & 0x0E) |
(AT91C_CKGR_PLLCOUNT & (28<<8)) |
(AT91C_CKGR_MUL & (0x48<<16)));
while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCK ) );
while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1 ;
// MCK=SLCK/2 : change prescaler first
AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_PRES_CLK_2;
while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
// MCK=PLLCK/2 : then change source
AT91C_BASE_PMC->PMC_MCKR |= AT91C_PMC_CSS_PLL_CLK ;
while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
}
#elif defined (at91sam7x) || defined (at91sam7xc)
//------------------------------------------------------------------------------
/// Put the CPU in 32kHz, disable PLL, main oscillator
/// Put voltage regulator in standby mode
//------------------------------------------------------------------------------
void LowPowerMode(void)
{
// MCK=48MHz to MCK=32kHz
// MCK = SLCK/2 : change source first from 48 000 000 to 18. / 2 = 9M
AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_PRES_CLK_2;
while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
// MCK=SLCK : then change prescaler
AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_CSS_SLOW_CLK;
while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
// disable PLL
AT91C_BASE_PMC->PMC_PLLR = 0;
// Disable Main Oscillator
AT91C_BASE_PMC->PMC_MOR = 0;
// Voltage regulator in standby mode : Enable VREG Low Power Mode
AT91C_BASE_VREG->VREG_MR |= AT91C_VREG_PSTDBY;
PMC_DisableProcessorClock();
}
//------------------------------------------------------------------------------
/// Put voltage regulator in normal mode
/// Return the CPU to normal speed 48MHz, enable PLL, main oscillator
//------------------------------------------------------------------------------
void NormalPowerMode(void)
{
// Voltage regulator in normal mode : Disable VREG Low Power Mode
AT91C_BASE_VREG->VREG_MR &= ~AT91C_VREG_PSTDBY;
// MCK=32kHz to MCK=48MHz
// enable Main Oscillator
AT91C_BASE_PMC->PMC_MOR = (( (AT91C_CKGR_OSCOUNT & (0x06 <<8)) | AT91C_CKGR_MOSCEN ));
while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MOSCS ) );
// enable PLL@96MHz
AT91C_BASE_PMC->PMC_PLLR = ((AT91C_CKGR_DIV & 0x0E) |
(AT91C_CKGR_PLLCOUNT & (28<<8)) |
(AT91C_CKGR_MUL & (0x48<<16)));
while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCK ) );
while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1 ;
// MCK=SLCK/2 : change prescaler first
AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_PRES_CLK_2;
while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
// MCK=PLLCK/2 : then change source
AT91C_BASE_PMC->PMC_MCKR |= AT91C_PMC_CSS_PLL_CLK ;
while( !( AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY ) );
}
#endif
//------------------------------------------------------------------------------
// Internal functions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/// Handles interrupts coming from Timer #0.
//------------------------------------------------------------------------------
static void ISR_Timer0()
{
unsigned char size;
unsigned int status = AT91C_BASE_TC0->TC_SR;
if ((status & AT91C_TC_CPCS) != 0) {
// Flush PDC buffer
size = DATABUFFERSIZE - AT91C_BASE_US0->US_RCR;
if (size == 0) {
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
return;
}
AT91C_BASE_US0->US_RCR = 0;
// Send current buffer through the USB
while (CDCDSerialDriver_Write(usartBuffers[usartCurrentBuffer],
size, 0, 0) != USBD_STATUS_SUCCESS);
// Restart read on buffer
USART_ReadBuffer(AT91C_BASE_US0,
usartBuffers[usartCurrentBuffer],
DATABUFFERSIZE);
usartCurrentBuffer = 1 - usartCurrentBuffer;
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
}
}
//------------------------------------------------------------------------------
// Callbacks re-implementation
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/// Invoked when the USB device leaves the Suspended state. By default,
/// configures the LEDs.
//------------------------------------------------------------------------------
void USBDCallbacks_Resumed(void)
{
// Initialize LEDs
LED_Configure(USBD_LEDPOWER);
LED_Set(USBD_LEDPOWER);
LED_Configure(USBD_LEDUSB);
LED_Clear(USBD_LEDUSB);
USBState = STATE_RESUME;
}
//------------------------------------------------------------------------------
/// Invoked when the USB device gets suspended. By default, turns off all LEDs.
//------------------------------------------------------------------------------
void USBDCallbacks_Suspended(void)
{
// Turn off LEDs
LED_Clear(USBD_LEDPOWER);
LED_Clear(USBD_LEDUSB);
USBState = STATE_SUSPEND;
}
//------------------------------------------------------------------------------
/// Callback invoked when data has been received on the USB.
//------------------------------------------------------------------------------
static void UsbDataReceived(unsigned int unused,
unsigned char status,
unsigned int received,
unsigned int remaining)
{
// Check that data has been received successfully
if (status == USBD_STATUS_SUCCESS) {
// Send data through USART
while (!USART_WriteBuffer(AT91C_BASE_US0, usbBuffer, received));
AT91C_BASE_US0->US_IER = AT91C_US_TXBUFE;
// Check if bytes have been discarded
if ((received == DATABUFFERSIZE) && (remaining > 0)) {
TRACE_WARNING(
"UsbDataReceived: %u bytes discarded\n\r",
remaining);
}
}
else {
TRACE_WARNING( "UsbDataReceived: Transfer error\n\r");
}
}
//------------------------------------------------------------------------------
/// Handles interrupts coming from USART #0.
//------------------------------------------------------------------------------
static void ISR_Usart0()
{
unsigned int status = AT91C_BASE_US0->US_CSR;
unsigned short serialState;
// If USB device is not configured, do nothing
if (USBD_GetState() != USBD_STATE_CONFIGURED) {
AT91C_BASE_US0->US_IDR = 0xFFFFFFFF;
return;
}
// Buffer has been read successfully
if ((status & AT91C_US_ENDRX) != 0) {
// Disable timer
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
// Send buffer through the USB
while (CDCDSerialDriver_Write(usartBuffers[usartCurrentBuffer],
DATABUFFERSIZE, 0, 0) != USBD_STATUS_SUCCESS);
// Restart read on buffer
USART_ReadBuffer(AT91C_BASE_US0,
usartBuffers[usartCurrentBuffer],
DATABUFFERSIZE);
usartCurrentBuffer = 1 - usartCurrentBuffer;
// Restart timer
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
}
// Buffer has been sent
if ((status & AT91C_US_TXBUFE) != 0) {
// Restart USB read
CDCDSerialDriver_Read(usbBuffer,
DATABUFFERSIZE,
(TransferCallback) UsbDataReceived,
0);
AT91C_BASE_US0->US_IDR = AT91C_US_TXBUFE;
}
// Errors
serialState = CDCDSerialDriver_GetSerialState();
// Overrun
if ((status & AT91C_US_OVER) != 0) {
TRACE_WARNING( "ISR_Usart0: Overrun\n\r");
serialState |= CDCDSerialDriver_STATE_OVERRUN;
}
// Framing error
if ((status & AT91C_US_FRAME) != 0) {
TRACE_WARNING( "ISR_Usart0: Framing error\n\r");
serialState |= CDCDSerialDriver_STATE_FRAMING;
}
CDCDSerialDriver_SetSerialState(serialState);
}
//------------------------------------------------------------------------------
// Main
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/// Initializes drivers and start the USB <-> Serial bridge.
//------------------------------------------------------------------------------
int main()
{
TRACE_CONFIGURE(DBGU_STANDARD, 115200, BOARD_MCK);
printf("-- USB Device CDC Serial Project %s --\n\r", SOFTPACK_VERSION);
printf("-- %s\n\r", BOARD_NAME);
printf("-- Compiled: %s %s --\n\r", __DATE__, __TIME__);
// If they are present, configure Vbus & Wake-up pins
PIO_InitializeInterrupts(0);
// Configure USART
PIO_Configure(pins, PIO_LISTSIZE(pins));
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_US0;
AT91C_BASE_US0->US_IDR = 0xFFFFFFFF;
USART_Configure(AT91C_BASE_US0,
USART_MODE_ASYNCHRONOUS,
115200,
BOARD_MCK);
USART_SetTransmitterEnabled(AT91C_BASE_US0, 1);
USART_SetReceiverEnabled(AT91C_BASE_US0, 1);
AIC_ConfigureIT(AT91C_ID_US0, 0, ISR_Usart0);
AIC_EnableIT(AT91C_ID_US0);
// Configure timer 0
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0);
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
AT91C_BASE_TC0->TC_IDR = 0xFFFFFFFF;
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV5_CLOCK
| AT91C_TC_CPCSTOP
| AT91C_TC_CPCDIS
| AT91C_TC_WAVESEL_UP_AUTO
| AT91C_TC_WAVE;
AT91C_BASE_TC0->TC_RC = 0x00FF;
AT91C_BASE_TC0->TC_IER = AT91C_TC_CPCS;
AIC_ConfigureIT(AT91C_ID_TC0, 0, ISR_Timer0);
AIC_EnableIT(AT91C_ID_TC0);
// BOT driver initialization
CDCDSerialDriver_Initialize();
// connect if needed
VBUS_CONFIGURE();
// Driver loop
while (1) {
// Device is not configured
if (USBD_GetState() < USBD_STATE_CONFIGURED) {
// Connect pull-up, wait for configuration
USBD_Connect();
while (USBD_GetState() < USBD_STATE_CONFIGURED);
// Start receiving data on the USART
usartCurrentBuffer = 0;
USART_ReadBuffer(AT91C_BASE_US0, usartBuffers[0], DATABUFFERSIZE);
USART_ReadBuffer(AT91C_BASE_US0, usartBuffers[1], DATABUFFERSIZE);
AT91C_BASE_US0->US_IER = AT91C_US_ENDRX
| AT91C_US_FRAME
| AT91C_US_OVER;
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
// Start receiving data on the USB
CDCDSerialDriver_Read(usbBuffer,
DATABUFFERSIZE,
(TransferCallback) UsbDataReceived,
0);
}
if( USBState == STATE_SUSPEND ) {
TRACE_DEBUG("suspend !\n\r");
LowPowerMode();
USBState = STATE_IDLE;
}
if( USBState == STATE_RESUME ) {
// Return in normal MODE
TRACE_DEBUG("resume !\n\r");
NormalPowerMode();
USBState = STATE_IDLE;
}
}
}