You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
834 lines
33 KiB
834 lines
33 KiB
/********************************************************************
|
|
FileName: main.c
|
|
Dependencies: See INCLUDES section
|
|
Processor: PIC18, PIC24, dsPIC, and PIC32 USB Microcontrollers
|
|
Hardware: This demo is natively intended to be used on Microchip USB demo
|
|
boards supported by the MCHPFSUSB stack. See release notes for
|
|
support matrix. This demo can be modified for use on other
|
|
hardware platforms.
|
|
Complier: Microchip C18 (for PIC18), XC16 (for PIC24/dsPIC), XC32 (for PIC32)
|
|
Company: Microchip Technology, Inc.
|
|
|
|
Software License Agreement:
|
|
|
|
The software supplied herewith by Microchip Technology Incorporated
|
|
(the "Company") for its PIC(R) Microcontroller is intended and
|
|
supplied to you, the Company's customer, for use solely and
|
|
exclusively on Microchip PIC Microcontroller products. The
|
|
software is owned by the Company and/or its supplier, and is
|
|
protected under applicable copyright laws. All rights are reserved.
|
|
Any use in violation of the foregoing restrictions may subject the
|
|
user to criminal sanctions under applicable laws, as well as to
|
|
civil liability for the breach of the terms and conditions of this
|
|
license.
|
|
|
|
THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES,
|
|
WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
|
|
TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
|
|
IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
|
|
CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
|
|
|
|
********************************************************************
|
|
File Description:
|
|
|
|
Change History:
|
|
Rev Description
|
|
---- -----------------------------------------
|
|
1.0 Initial release
|
|
2.1 Updated for simplicity and to use common
|
|
coding style
|
|
2.7b Improvements to USBCBSendResume(), to make it easier to use.
|
|
2.9f Adding new part support
|
|
2.9j Updates to support new bootloader features (ex: app version
|
|
fetching).
|
|
********************************************************************/
|
|
|
|
#ifndef MAIN_C
|
|
#define MAIN_C
|
|
|
|
/** INCLUDES *******************************************************/
|
|
#include "../mcu.h"
|
|
#include "../typedefs.h"
|
|
#include "usb.h"
|
|
#include "usb_function_hid.h"
|
|
|
|
/** VARIABLES ******************************************************/
|
|
#if defined(__18CXX)
|
|
#pragma udata
|
|
|
|
//The ReceivedDataBuffer[] and ToSendDataBuffer[] arrays are used as
|
|
//USB packet buffers in this firmware. Therefore, they must be located in
|
|
//a USB module accessible portion of microcontroller RAM.
|
|
#if defined(__18F14K50) || defined(__18F13K50) || defined(__18LF14K50) || defined(__18LF13K50)
|
|
#pragma udata USB_VARIABLES=0x260
|
|
#elif defined(__18F2455) || defined(__18F2550) || defined(__18F4455) || defined(__18F4550)\
|
|
|| defined(__18F2458) || defined(__18F2553) || defined(__18F4458) || defined(__18F4553)\
|
|
|| defined(__18LF24K50) || defined(__18F24K50) || defined(__18LF25K50)\
|
|
|| defined(__18F25K50) || defined(__18LF45K50) || defined(__18F45K50)
|
|
#pragma udata USB_VARIABLES=0x500
|
|
#elif defined(__18F4450) || defined(__18F2450)
|
|
#pragma udata USB_VARIABLES=0x480
|
|
#else
|
|
#pragma udata
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(__XC8)
|
|
#if defined(_18F14K50) || defined(_18F13K50) || defined(_18LF14K50) || defined(_18LF13K50)
|
|
#define RX_DATA_BUFFER_ADDRESS @0x260
|
|
#define TX_DATA_BUFFER_ADDRESS @0x2A0
|
|
#elif defined(_18F2455) || defined(_18F2550) || defined(_18F4455) || defined(_18F4550)\
|
|
|| defined(_18F2458) || defined(_18F2453) || defined(_18F4558) || defined(_18F4553)\
|
|
|| defined(_18LF24K50) || defined(_18F24K50) || defined(_18LF25K50)\
|
|
|| defined(_18F25K50) || defined(_18LF45K50) || defined(_18F45K50)
|
|
#define RX_DATA_BUFFER_ADDRESS @0x500
|
|
#define TX_DATA_BUFFER_ADDRESS @0x540
|
|
#elif defined(_18F4450) || defined(_18F2450)
|
|
#define RX_DATA_BUFFER_ADDRESS @0x480
|
|
#define TX_DATA_BUFFER_ADDRESS @0x4C0
|
|
#elif defined(_16F1459)
|
|
#define RX_DATA_BUFFER_ADDRESS @0x2050
|
|
#define TX_DATA_BUFFER_ADDRESS @0x20A0
|
|
#else
|
|
#define RX_DATA_BUFFER_ADDRESS
|
|
#define RX_DATA_BUFFER_ADDRESS
|
|
#endif
|
|
#else
|
|
#define RX_DATA_BUFFER_ADDRESS
|
|
#define TX_DATA_BUFFER_ADDRESS
|
|
#endif
|
|
|
|
unsigned char USBRxBuffer[64] RX_DATA_BUFFER_ADDRESS;
|
|
unsigned char USBTxBuffer[64] TX_DATA_BUFFER_ADDRESS;
|
|
|
|
#if defined(__18CXX)
|
|
#pragma udata
|
|
#endif
|
|
|
|
USB_HANDLE USBOutHandle = 0; //USB handle. Must be initialized to 0 at startup.
|
|
USB_HANDLE USBInHandle = 0; //USB handle. Must be initialized to 0 at startup.
|
|
|
|
void USBCBSendResume(void);
|
|
|
|
/** VECTOR REMAPPING ***********************************************/
|
|
#if defined(__18CXX)
|
|
//On PIC18 devices, addresses 0x00, 0x08, and 0x18 are used for
|
|
//the reset, high priority interrupt, and low priority interrupt
|
|
//vectors. However, the Microchip HID bootloader occupies the
|
|
//0x00-0xFFF program memory region. Therefore, the bootloader code remaps
|
|
//these vectors to new locations as indicated below. This remapping is
|
|
//only necessary if you wish to be able to (optionally) program the hex file
|
|
//generated from this project with the USB bootloader.
|
|
#define REMAPPED_RESET_VECTOR_ADDRESS 0x1000
|
|
#define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS 0x1008
|
|
#define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS 0x1018
|
|
#define APP_VERSION_ADDRESS 0x1016 //Fixed location, so the App FW image version can be read by the bootloader.
|
|
#define APP_SIGNATURE_ADDRESS 0x1006 //Signature location that must be kept at blaknk value (0xFFFF) in this project (has special purpose for bootloader).
|
|
|
|
//--------------------------------------------------------------------------
|
|
//Application firmware image version values, as reported to the bootloader
|
|
//firmware. These are useful so the bootloader can potentially know if the
|
|
//user is trying to program an older firmware image onto a device that
|
|
//has already been programmed with a with a newer firmware image.
|
|
//Format is APP_FIRMWARE_VERSION_MAJOR.APP_FIRMWARE_VERSION_MINOR.
|
|
//The valid minor version is from 00 to 99. Example:
|
|
//if APP_FIRMWARE_VERSION_MAJOR == 1, APP_FIRMWARE_VERSION_MINOR == 1,
|
|
//then the version is "1.01"
|
|
#define APP_FIRMWARE_VERSION_MAJOR 1 //valid values 0-255
|
|
#define APP_FIRMWARE_VERSION_MINOR 0 //valid values 0-99
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma romdata AppVersionAndSignatureSection = APP_VERSION_ADDRESS
|
|
ROM unsigned char AppVersion[2] = {APP_FIRMWARE_VERSION_MINOR, APP_FIRMWARE_VERSION_MAJOR};
|
|
#pragma romdata AppSignatureSection = APP_SIGNATURE_ADDRESS
|
|
ROM unsigned short int SignaturePlaceholder = 0xFFFF;
|
|
|
|
#pragma code HIGH_INTERRUPT_VECTOR = 0x08
|
|
void High_ISR (void)
|
|
{
|
|
_asm goto REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS _endasm
|
|
}
|
|
#pragma code LOW_INTERRUPT_VECTOR = 0x18
|
|
void Low_ISR (void)
|
|
{
|
|
_asm goto REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS _endasm
|
|
}
|
|
extern void _startup (void); // See c018i.c in your C18 compiler dir
|
|
#pragma code REMAPPED_RESET_VECTOR = REMAPPED_RESET_VECTOR_ADDRESS
|
|
void _reset (void)
|
|
{
|
|
_asm goto _startup _endasm
|
|
}
|
|
#pragma code REMAPPED_HIGH_INTERRUPT_VECTOR = REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS
|
|
void Remapped_High_ISR (void)
|
|
{
|
|
_asm goto YourHighPriorityISRCode _endasm
|
|
}
|
|
#pragma code REMAPPED_LOW_INTERRUPT_VECTOR = REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS
|
|
void Remapped_Low_ISR (void)
|
|
{
|
|
_asm goto YourLowPriorityISRCode _endasm
|
|
}
|
|
#pragma code
|
|
|
|
|
|
//These are your actual interrupt handling routines.
|
|
#pragma interrupt YourHighPriorityISRCode
|
|
void YourHighPriorityISRCode()
|
|
{
|
|
//Check which interrupt flag caused the interrupt.
|
|
//Service the interrupt
|
|
//Clear the interrupt flag
|
|
//Etc.
|
|
#if defined(USB_INTERRUPT)
|
|
USBDeviceTasks();
|
|
#endif
|
|
|
|
} //This return will be a "retfie fast", since this is in a #pragma interrupt section
|
|
#pragma interruptlow YourLowPriorityISRCode
|
|
void YourLowPriorityISRCode()
|
|
{
|
|
//Check which interrupt flag caused the interrupt.
|
|
//Service the interrupt
|
|
//Clear the interrupt flag
|
|
//Etc.
|
|
|
|
} //This return will be a "retfie", since this is in a #pragma interruptlow section
|
|
#elif defined(_PIC14E)
|
|
//These are your actual interrupt handling routines.
|
|
void interrupt ISRCode()
|
|
{
|
|
//Check which interrupt flag caused the interrupt.
|
|
//Service the interrupt
|
|
//Clear the interrupt flag
|
|
//Etc.
|
|
#if defined(USB_INTERRUPT)
|
|
|
|
USBDeviceTasks();
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
|
|
/** DECLARATIONS ***************************************************/
|
|
#if defined(__18CXX)
|
|
#pragma code
|
|
#endif
|
|
|
|
/********************************************************************
|
|
* Function: void main(void)
|
|
*
|
|
* PreCondition: None
|
|
*
|
|
* Input: None
|
|
*
|
|
* Output: None
|
|
*
|
|
* Side Effects: None
|
|
*
|
|
* Overview: Main program entry point.
|
|
*
|
|
* Note: None
|
|
*******************************************************************/
|
|
/*#if defined(__18CXX)
|
|
void main(void)
|
|
#else
|
|
int main(void)
|
|
#endif
|
|
{
|
|
InitializeSystem();
|
|
|
|
#if defined(USB_INTERRUPT)
|
|
USBDeviceAttach();
|
|
#endif
|
|
|
|
while(1)
|
|
{
|
|
#if defined(USB_POLLING)
|
|
// Check bus status and service USB interrupts.
|
|
USBDeviceTasks(); // Interrupt or polling method. If using polling, must call
|
|
// this function periodically. This function will take care
|
|
// of processing and responding to SETUP transactions
|
|
// (such as during the enumeration process when you first
|
|
// plug in). USB hosts require that USB devices should accept
|
|
// and process SETUP packets in a timely fashion. Therefore,
|
|
// when using polling, this function should be called
|
|
// regularly (such as once every 1.8ms or faster** [see
|
|
// inline code comments in usb_device.c for explanation when
|
|
// "or faster" applies]) In most cases, the USBDeviceTasks()
|
|
// function does not take very long to execute (ex: <100
|
|
// instruction cycles) before it returns.
|
|
#endif
|
|
|
|
|
|
// Application-specific tasks.
|
|
// Application related code may be added here, or in the ProcessIO() function.
|
|
ProcessIO();
|
|
}//end while
|
|
}//end main*/
|
|
|
|
|
|
/********************************************************************
|
|
* Function: static void InitializeSystem(void)
|
|
*
|
|
* PreCondition: None
|
|
*
|
|
* Input: None
|
|
*
|
|
* Output: None
|
|
*
|
|
* Side Effects: None
|
|
*
|
|
* Overview: InitializeSystem is a centralize initialization
|
|
* routine. All required USB initialization routines
|
|
* are called from here.
|
|
*
|
|
* User application initialization routine should
|
|
* also be called from here.
|
|
*
|
|
* Note: None
|
|
*******************************************************************/
|
|
void USBDriverInit(void)
|
|
{
|
|
|
|
USBOutHandle = 0;
|
|
USBInHandle = 0;
|
|
USBDeviceInit(); //usb_device.c. Initializes USB module SFRs and firmware
|
|
//variables to known states.
|
|
}//end InitializeSystem
|
|
|
|
|
|
/********************************************************************
|
|
* Function: void ProcessIO(void)
|
|
*
|
|
* PreCondition: None
|
|
*
|
|
* Input: None
|
|
*
|
|
* Output: None
|
|
*
|
|
* Side Effects: None
|
|
*
|
|
* Overview: This function is a place holder for other user
|
|
* routines. It is a mixture of both USB and
|
|
* non-USB tasks.
|
|
*
|
|
* Note: None
|
|
*******************************************************************/
|
|
/*void ProcessIO(void)
|
|
{
|
|
//Blink the LEDs according to the USB device status
|
|
|
|
// User Application USB tasks
|
|
if((USBDeviceState < CONFIGURED_STATE)||(USBSuspendControl==1)) return;
|
|
|
|
//Check if we have received an OUT data packet from the host
|
|
if(!HIDRxHandleBusy(USBOutHandle))
|
|
{
|
|
//We just received a packet of data from the USB host.
|
|
//Check the first byte of the packet to see what command the host
|
|
//application software wants us to fulfill.
|
|
switch(ReceivedDataBuffer[0]) //Look at the data the host sent, to see what kind of application specific command it sent.
|
|
{
|
|
case 0x80: //Toggle LEDs command
|
|
case 0x81: //Get push button state
|
|
//Check to make sure the endpoint/buffer is free before we modify the contents
|
|
if(!HIDTxHandleBusy(USBInHandle))
|
|
{
|
|
ToSendDataBuffer[0] = 0x81; //Echo back to the host PC the command we are fulfilling in the first byte. In this case, the Get Pushbutton State command.
|
|
USBInHandle = HIDTxPacket(HID_EP,(BYTE*)&ToSendDataBuffer[0],64);
|
|
}
|
|
break;
|
|
|
|
case 0x37: //Read POT command. Uses ADC to measure an analog voltage on one of the ANxx I/O pins, and returns the result to the host
|
|
{
|
|
WORD_VAL w;
|
|
|
|
//Check to make sure the endpoint/buffer is free before we modify the contents
|
|
if(!HIDTxHandleBusy(USBInHandle))
|
|
{
|
|
//Some demo boards, like the PIC18F87J50 FS USB Plug-In Module board, do not have a potentiometer (when used stand alone).
|
|
//This function call will still measure the analog voltage on the I/O pin however. To make the demo more interesting, it
|
|
//is suggested that an external adjustable analog voltage should be applied to this pin.
|
|
ToSendDataBuffer[0] = 0x37; //Echo back to the host the command we are fulfilling in the first byte. In this case, the Read POT (analog voltage) command.
|
|
ToSendDataBuffer[1] = w.v[0]; //Measured analog voltage LSB
|
|
ToSendDataBuffer[2] = w.v[1]; //Measured analog voltage MSB
|
|
|
|
//Prepare the USB module to send the data packet to the host
|
|
USBInHandle = HIDTxPacket(HID_EP,(BYTE*)&ToSendDataBuffer[0],64);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
//Re-arm the OUT endpoint, so we can receive the next OUT data packet
|
|
//that the host may try to send us.
|
|
USBOutHandle = HIDRxPacket(HID_EP, (BYTE*)&ReceivedDataBuffer, 64);
|
|
}
|
|
|
|
|
|
}//end ProcessIO */
|
|
|
|
|
|
// ******************************************************************************************************
|
|
// ************** USB Callback Functions ****************************************************************
|
|
// ******************************************************************************************************
|
|
// The USB firmware stack will call the callback functions USBCBxxx() in response to certain USB related
|
|
// events. For example, if the host PC is powering down, it will stop sending out Start of Frame (SOF)
|
|
// packets to your device. In response to this, all USB devices are supposed to decrease their power
|
|
// consumption from the USB Vbus to <2.5mA* each. The USB module detects this condition (which according
|
|
// to the USB specifications is 3+ms of no bus activity/SOF packets) and then calls the USBCBSuspend()
|
|
// function. You should modify these callback functions to take appropriate actions for each of these
|
|
// conditions. For example, in the USBCBSuspend(), you may wish to add code that will decrease power
|
|
// consumption from Vbus to <2.5mA (such as by clock switching, turning off LEDs, putting the
|
|
// microcontroller to sleep, etc.). Then, in the USBCBWakeFromSuspend() function, you may then wish to
|
|
// add code that undoes the power saving things done in the USBCBSuspend() function.
|
|
|
|
// The USBCBSendResume() function is special, in that the USB stack will not automatically call this
|
|
// function. This function is meant to be called from the application firmware instead. See the
|
|
// additional comments near the function.
|
|
|
|
// Note *: The "usb_20.pdf" specs indicate 500uA or 2.5mA, depending upon device classification. However,
|
|
// the USB-IF has officially issued an ECN (engineering change notice) changing this to 2.5mA for all
|
|
// devices. Make sure to re-download the latest specifications to get all of the newest ECNs.
|
|
|
|
/******************************************************************************
|
|
* Function: void USBCBSuspend(void)
|
|
*
|
|
* PreCondition: None
|
|
*
|
|
* Input: None
|
|
*
|
|
* Output: None
|
|
*
|
|
* Side Effects: None
|
|
*
|
|
* Overview: Call back that is invoked when a USB suspend is detected
|
|
*
|
|
* Note: None
|
|
*****************************************************************************/
|
|
//void USBCBSuspend(void)
|
|
//{
|
|
//Example power saving code. Insert appropriate code here for the desired
|
|
//application behavior. If the microcontroller will be put to sleep, a
|
|
//process similar to that shown below may be used:
|
|
|
|
//ConfigureIOPinsForLowPower();
|
|
//SaveStateOfAllInterruptEnableBits();
|
|
//DisableAllInterruptEnableBits();
|
|
//EnableOnlyTheInterruptsWhichWillBeUsedToWakeTheMicro(); //should enable at least USBActivityIF as a wake source
|
|
//Sleep();
|
|
//RestoreStateOfAllPreviouslySavedInterruptEnableBits(); //Preferrably, this should be done in the USBCBWakeFromSuspend() function instead.
|
|
//RestoreIOPinsToNormal(); //Preferrably, this should be done in the USBCBWakeFromSuspend() function instead.
|
|
|
|
//IMPORTANT NOTE: Do not clear the USBActivityIF (ACTVIF) bit here. This bit is
|
|
//cleared inside the usb_device.c file. Clearing USBActivityIF here will cause
|
|
//things to not work as intended.
|
|
|
|
|
|
// #if defined(__C30__) || defined __XC16__
|
|
//This function requires that the _IPL level be something other than 0.
|
|
// We can set it here to something other than
|
|
// #ifndef DSPIC33E_USB_STARTER_KIT
|
|
// _IPL = 1;
|
|
// USBSleepOnSuspend();
|
|
// #endif
|
|
// #endif
|
|
//}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
* Function: void USBCBWakeFromSuspend(void)
|
|
*
|
|
* PreCondition: None
|
|
*
|
|
* Input: None
|
|
*
|
|
* Output: None
|
|
*
|
|
* Side Effects: None
|
|
*
|
|
* Overview: The host may put USB peripheral devices in low power
|
|
* suspend mode (by "sending" 3+ms of idle). Once in suspend
|
|
* mode, the host may wake the device back up by sending non-
|
|
* idle state signalling.
|
|
*
|
|
* This call back is invoked when a wakeup from USB suspend
|
|
* is detected.
|
|
*
|
|
* Note: None
|
|
*****************************************************************************/
|
|
//void USBCBWakeFromSuspend(void)
|
|
//{
|
|
// If clock switching or other power savings measures were taken when
|
|
// executing the USBCBSuspend() function, now would be a good time to
|
|
// switch back to normal full power run mode conditions. The host allows
|
|
// 10+ milliseconds of wakeup time, after which the device must be
|
|
// fully back to normal, and capable of receiving and processing USB
|
|
// packets. In order to do this, the USB module must receive proper
|
|
// clocking (IE: 48MHz clock must be available to SIE for full speed USB
|
|
// operation).
|
|
// Make sure the selected oscillator settings are consistent with USB
|
|
// operation before returning from this function.
|
|
//}
|
|
|
|
/********************************************************************
|
|
* Function: void USBCB_SOF_Handler(void)
|
|
*
|
|
* PreCondition: None
|
|
*
|
|
* Input: None
|
|
*
|
|
* Output: None
|
|
*
|
|
* Side Effects: None
|
|
*
|
|
* Overview: The USB host sends out a SOF packet to full-speed
|
|
* devices every 1 ms. This interrupt may be useful
|
|
* for isochronous pipes. End designers should
|
|
* implement callback routine as necessary.
|
|
*
|
|
* Note: None
|
|
*******************************************************************/
|
|
//void USBCB_SOF_Handler(void)
|
|
//{
|
|
// No need to clear UIRbits.SOFIF to 0 here.
|
|
// Callback caller is already doing that.
|
|
//}
|
|
|
|
/*******************************************************************
|
|
* Function: void USBCBErrorHandler(void)
|
|
*
|
|
* PreCondition: None
|
|
*
|
|
* Input: None
|
|
*
|
|
* Output: None
|
|
*
|
|
* Side Effects: None
|
|
*
|
|
* Overview: The purpose of this callback is mainly for
|
|
* debugging during development. Check UEIR to see
|
|
* which error causes the interrupt.
|
|
*
|
|
* Note: None
|
|
*******************************************************************/
|
|
//void USBCBErrorHandler(void)
|
|
//{
|
|
// No need to clear UEIR to 0 here.
|
|
// Callback caller is already doing that.
|
|
|
|
// Typically, user firmware does not need to do anything special
|
|
// if a USB error occurs. For example, if the host sends an OUT
|
|
// packet to your device, but the packet gets corrupted (ex:
|
|
// because of a bad connection, or the user unplugs the
|
|
// USB cable during the transmission) this will typically set
|
|
// one or more USB error interrupt flags. Nothing specific
|
|
// needs to be done however, since the SIE will automatically
|
|
// send a "NAK" packet to the host. In response to this, the
|
|
// host will normally retry to send the packet again, and no
|
|
// data loss occurs. The system will typically recover
|
|
// automatically, without the need for application firmware
|
|
// intervention.
|
|
|
|
// Nevertheless, this callback function is provided, such as
|
|
// for debugging purposes.
|
|
//}
|
|
|
|
|
|
/*******************************************************************
|
|
* Function: void USBCBCheckOtherReq(void)
|
|
*
|
|
* PreCondition: None
|
|
*
|
|
* Input: None
|
|
*
|
|
* Output: None
|
|
*
|
|
* Side Effects: None
|
|
*
|
|
* Overview: When SETUP packets arrive from the host, some
|
|
* firmware must process the request and respond
|
|
* appropriately to fulfill the request. Some of
|
|
* the SETUP packets will be for standard
|
|
* USB "chapter 9" (as in, fulfilling chapter 9 of
|
|
* the official USB specifications) requests, while
|
|
* others may be specific to the USB device class
|
|
* that is being implemented. For example, a HID
|
|
* class device needs to be able to respond to
|
|
* "GET REPORT" type of requests. This
|
|
* is not a standard USB chapter 9 request, and
|
|
* therefore not handled by usb_device.c. Instead
|
|
* this request should be handled by class specific
|
|
* firmware, such as that contained in usb_function_hid.c.
|
|
*
|
|
* Note: None
|
|
*******************************************************************/
|
|
void USBCBCheckOtherReq(void)
|
|
{
|
|
USBCheckHIDRequest();
|
|
}//end
|
|
|
|
|
|
/*******************************************************************
|
|
* Function: void USBCBStdSetDscHandler(void)
|
|
*
|
|
* PreCondition: None
|
|
*
|
|
* Input: None
|
|
*
|
|
* Output: None
|
|
*
|
|
* Side Effects: None
|
|
*
|
|
* Overview: The USBCBStdSetDscHandler() callback function is
|
|
* called when a SETUP, bRequest: SET_DESCRIPTOR request
|
|
* arrives. Typically SET_DESCRIPTOR requests are
|
|
* not used in most applications, and it is
|
|
* optional to support this type of request.
|
|
*
|
|
* Note: None
|
|
*******************************************************************/
|
|
//void USBCBStdSetDscHandler(void)
|
|
//{
|
|
// Must claim session ownership if supporting this request
|
|
//}//end
|
|
|
|
|
|
/*******************************************************************
|
|
* Function: void USBCBInitEP(void)
|
|
*
|
|
* PreCondition: None
|
|
*
|
|
* Input: None
|
|
*
|
|
* Output: None
|
|
*
|
|
* Side Effects: None
|
|
*
|
|
* Overview: This function is called when the device becomes
|
|
* initialized, which occurs after the host sends a
|
|
* SET_CONFIGURATION (wValue not = 0) request. This
|
|
* callback function should initialize the endpoints
|
|
* for the device's usage according to the current
|
|
* configuration.
|
|
*
|
|
* Note: None
|
|
*******************************************************************/
|
|
void USBCBInitEP(void)
|
|
{
|
|
//enable the HID endpoint
|
|
USBEnableEndpoint(HID_EP,USB_IN_ENABLED|USB_OUT_ENABLED|USB_HANDSHAKE_ENABLED|USB_DISALLOW_SETUP);
|
|
//Re-arm the OUT endpoint for the next packet
|
|
USBOutHandle = HIDRxPacket(HID_EP,(BYTE*)&USBRxBuffer,64);
|
|
}
|
|
|
|
/********************************************************************
|
|
* Function: void USBCBSendResume(void)
|
|
*
|
|
* PreCondition: None
|
|
*
|
|
* Input: None
|
|
*
|
|
* Output: None
|
|
*
|
|
* Side Effects: None
|
|
*
|
|
* Overview: The USB specifications allow some types of USB
|
|
* peripheral devices to wake up a host PC (such
|
|
* as if it is in a low power suspend to RAM state).
|
|
* This can be a very useful feature in some
|
|
* USB applications, such as an Infrared remote
|
|
* control receiver. If a user presses the "power"
|
|
* button on a remote control, it is nice that the
|
|
* IR receiver can detect this signalling, and then
|
|
* send a USB "command" to the PC to wake up.
|
|
*
|
|
* The USBCBSendResume() "callback" function is used
|
|
* to send this special USB signalling which wakes
|
|
* up the PC. This function may be called by
|
|
* application firmware to wake up the PC. This
|
|
* function will only be able to wake up the host if
|
|
* all of the below are true:
|
|
*
|
|
* 1. The USB driver used on the host PC supports
|
|
* the remote wakeup capability.
|
|
* 2. The USB configuration descriptor indicates
|
|
* the device is remote wakeup capable in the
|
|
* bmAttributes field.
|
|
* 3. The USB host PC is currently sleeping,
|
|
* and has previously sent your device a SET
|
|
* FEATURE setup packet which "armed" the
|
|
* remote wakeup capability.
|
|
*
|
|
* If the host has not armed the device to perform remote wakeup,
|
|
* then this function will return without actually performing a
|
|
* remote wakeup sequence. This is the required behavior,
|
|
* as a USB device that has not been armed to perform remote
|
|
* wakeup must not drive remote wakeup signalling onto the bus;
|
|
* doing so will cause USB compliance testing failure.
|
|
*
|
|
* This callback should send a RESUME signal that
|
|
* has the period of 1-15ms.
|
|
*
|
|
* Note: This function does nothing and returns quickly, if the USB
|
|
* bus and host are not in a suspended condition, or are
|
|
* otherwise not in a remote wakeup ready state. Therefore, it
|
|
* is safe to optionally call this function regularly, ex:
|
|
* anytime application stimulus occurs, as the function will
|
|
* have no effect, until the bus really is in a state ready
|
|
* to accept remote wakeup.
|
|
*
|
|
* When this function executes, it may perform clock switching,
|
|
* depending upon the application specific code in
|
|
* USBCBWakeFromSuspend(). This is needed, since the USB
|
|
* bus will no longer be suspended by the time this function
|
|
* returns. Therefore, the USB module will need to be ready
|
|
* to receive traffic from the host.
|
|
*
|
|
* The modifiable section in this routine may be changed
|
|
* to meet the application needs. Current implementation
|
|
* temporary blocks other functions from executing for a
|
|
* period of ~3-15 ms depending on the core frequency.
|
|
*
|
|
* According to USB 2.0 specification section 7.1.7.7,
|
|
* "The remote wakeup device must hold the resume signaling
|
|
* for at least 1 ms but for no more than 15 ms."
|
|
* The idea here is to use a delay counter loop, using a
|
|
* common value that would work over a wide range of core
|
|
* frequencies.
|
|
* That value selected is 1800. See table below:
|
|
* ==========================================================
|
|
* Core Freq(MHz) MIP RESUME Signal Period (ms)
|
|
* ==========================================================
|
|
* 48 12 1.05
|
|
* 4 1 12.6
|
|
* ==========================================================
|
|
* * These timing could be incorrect when using code
|
|
* optimization or extended instruction mode,
|
|
* or when having other interrupts enabled.
|
|
* Make sure to verify using the MPLAB SIM's Stopwatch
|
|
* and verify the actual signal on an oscilloscope.
|
|
*******************************************************************/
|
|
void USBCBSendResume(void)
|
|
{
|
|
static WORD delay_count;
|
|
|
|
//First verify that the host has armed us to perform remote wakeup.
|
|
//It does this by sending a SET_FEATURE request to enable remote wakeup,
|
|
//usually just before the host goes to standby mode (note: it will only
|
|
//send this SET_FEATURE request if the configuration descriptor declares
|
|
//the device as remote wakeup capable, AND, if the feature is enabled
|
|
//on the host (ex: on Windows based hosts, in the device manager
|
|
//properties page for the USB device, power management tab, the
|
|
//"Allow this device to bring the computer out of standby." checkbox
|
|
//should be checked).
|
|
if(USBGetRemoteWakeupStatus() == TRUE)
|
|
{
|
|
//Verify that the USB bus is in fact suspended, before we send
|
|
//remote wakeup signalling.
|
|
if(USBIsBusSuspended() == TRUE)
|
|
{
|
|
USBMaskInterrupts();
|
|
|
|
//Clock switch to settings consistent with normal USB operation.
|
|
// USBCBWakeFromSuspend();
|
|
USBSuspendControl = 0;
|
|
USBBusIsSuspended = FALSE; //So we don't execute this code again,
|
|
//until a new suspend condition is detected.
|
|
|
|
//Section 7.1.7.7 of the USB 2.0 specifications indicates a USB
|
|
//device must continuously see 5ms+ of idle on the bus, before it sends
|
|
//remote wakeup signalling. One way to be certain that this parameter
|
|
//gets met, is to add a 2ms+ blocking delay here (2ms plus at
|
|
//least 3ms from bus idle to USBIsBusSuspended() == TRUE, yeilds
|
|
//5ms+ total delay since start of idle).
|
|
delay_count = 3600U;
|
|
do
|
|
{
|
|
delay_count--;
|
|
}while(delay_count);
|
|
|
|
//Now drive the resume K-state signalling onto the USB bus.
|
|
USBResumeControl = 1; // Start RESUME signaling
|
|
delay_count = 1800U; // Set RESUME line for 1-13 ms
|
|
do
|
|
{
|
|
delay_count--;
|
|
}while(delay_count);
|
|
USBResumeControl = 0; //Finished driving resume signalling
|
|
|
|
USBUnmaskInterrupts();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
* Function: BOOL USER_USB_CALLBACK_EVENT_HANDLER(
|
|
* USB_EVENT event, void *pdata, WORD size)
|
|
*
|
|
* PreCondition: None
|
|
*
|
|
* Input: USB_EVENT event - the type of event
|
|
* void *pdata - pointer to the event data
|
|
* WORD size - size of the event data
|
|
*
|
|
* Output: None
|
|
*
|
|
* Side Effects: None
|
|
*
|
|
* Overview: This function is called from the USB stack to
|
|
* notify a user application that a USB event
|
|
* occured. This callback is in interrupt context
|
|
* when the USB_INTERRUPT option is selected.
|
|
*
|
|
* Note: None
|
|
*******************************************************************/
|
|
BOOL USER_USB_CALLBACK_EVENT_HANDLER(int event, void *pdata, WORD size)
|
|
{
|
|
switch(event)
|
|
{
|
|
// case EVENT_TRANSFER:
|
|
//Add application specific callback task or callback function here if desired.
|
|
// break;
|
|
// case EVENT_SOF:
|
|
// USBCB_SOF_Handler();
|
|
// break;
|
|
// case EVENT_SUSPEND:
|
|
// USBCBSuspend();
|
|
// break;
|
|
// case EVENT_RESUME:
|
|
// USBCBWakeFromSuspend();
|
|
// break;
|
|
case EVENT_CONFIGURED:
|
|
USBCBInitEP();
|
|
break;
|
|
// case EVENT_SET_DESCRIPTOR:
|
|
// USBCBStdSetDscHandler();
|
|
// break;
|
|
case EVENT_EP0_REQUEST:
|
|
USBCBCheckOtherReq();
|
|
break;
|
|
// case EVENT_BUS_ERROR:
|
|
// USBCBErrorHandler();
|
|
// break;
|
|
// case EVENT_TRANSFER_TERMINATED:
|
|
//Add application specific callback task or callback function here if desired.
|
|
//The EVENT_TRANSFER_TERMINATED event occurs when the host performs a CLEAR
|
|
//FEATURE (endpoint halt) request on an application endpoint which was
|
|
//previously armed (UOWN was = 1). Here would be a good place to:
|
|
//1. Determine which endpoint the transaction that just got terminated was
|
|
// on, by checking the handle value in the *pdata.
|
|
//2. Re-arm the endpoint if desired (typically would be the case for OUT
|
|
// endpoints).
|
|
// break;
|
|
default:
|
|
break;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/** EOF main.c *************************************************/
|
|
#endif
|