729 lines
28 KiB
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;
|
|
}
|
|
}
|
|
}
|
|
|