Main Page | Data Structures | Directories | File List | Data Fields | Globals

usbdrv.c

Go to the documentation of this file.
00001 /*********************************************************************
00002  *
00003  *                Microchip USB C18 Firmware Version 1.0
00004  *
00005  *********************************************************************
00006  * FileName:        usbdrv.c
00007  * Dependencies:    See INCLUDES section below
00008  * Processor:       PIC18
00009  * Compiler:        C18 2.30.01+
00010  * Company:         Microchip Technology, Inc.
00011  *
00012  * Software License Agreement
00013  *
00014  * The software supplied herewith by Microchip Technology Incorporated
00015  * (the “Company”) for its PICmicro® Microcontroller is intended and
00016  * supplied to you, the Company’s customer, for use solely and
00017  * exclusively on Microchip PICmicro Microcontroller products. The
00018  * software is owned by the Company and/or its supplier, and is
00019  * protected under applicable copyright laws. All rights are reserved.
00020  * Any use in violation of the foregoing restrictions may subject the
00021  * user to criminal sanctions under applicable laws, as well as to
00022  * civil liability for the breach of the terms and conditions of this
00023  * license.
00024  *
00025  * THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES,
00026  * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
00027  * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00028  * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
00029  * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
00030  * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
00031  *
00032  * Author               Date        Comment
00033  *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00034  * Rawin Rojvanit       11/19/04    Original.
00035  ********************************************************************/
00036 
00037 /** I N C L U D E S **********************************************************/
00038 #include <p18cxxx.h>
00039 #include "system\typedefs.h"
00040 #include "system\usb\usb.h"
00041 #include "io_cfg.h"             // Required for USBCheckBusStatus()
00042 
00043 /** V A R I A B L E S ********************************************************/
00044 #pragma udata
00045 
00046 /** P R I V A T E  P R O T O T Y P E S ***************************************/
00047 void USBModuleEnable(void);
00048 void USBModuleDisable(void);
00049 
00050 void USBSuspend(void);
00051 void USBWakeFromSuspend(void);
00052 
00053 void USBProtocolResetHandler(void);
00054 void USB_SOF_Handler(void);
00055 void USBStallHandler(void);
00056 void USBErrorHandler(void);
00057 
00058 /** D E C L A R A T I O N S **************************************************/
00059 #pragma code
00060 /******************************************************************************
00061  * Function:        void USBCheckBusStatus(void)
00062  *
00063  * PreCondition:    None
00064  *
00065  * Input:           None
00066  *
00067  * Output:          None
00068  *
00069  * Side Effects:    None
00070  *
00071  * Overview:        This routine enables/disables the USB module by monitoring
00072  *                  the USB power signal.
00073  *
00074  * Note:            None
00075  *****************************************************************************/
00076 void USBCheckBusStatus(void)
00077 {
00078     /**************************************************************************
00079      * Bus Attachment & Detachment Detection
00080      * usb_bus_sense is an i/o pin defined in io_cfg.h
00081      *************************************************************************/
00082     #define USB_BUS_ATTACHED    1
00083     #define USB_BUS_DETACHED    0
00084 
00085     if(usb_bus_sense == USB_BUS_ATTACHED)       // Is USB bus attached?
00086     {
00087         if(UCONbits.USBEN == 0)                 // Is the module off?
00088             USBModuleEnable();                  // Is off, enable it
00089     }
00090     else
00091     {
00092         if(UCONbits.USBEN == 1)                 // Is the module on?
00093             USBModuleDisable();                 // Is on, disable it
00094     }//end if(usb_bus_sense...)
00095     
00096     /*
00097      * After enabling the USB module, it takes some time for the voltage
00098      * on the D+ or D- line to rise high enough to get out of the SE0 condition.
00099      * The USB Reset interrupt should not be unmasked until the SE0 condition is
00100      * cleared. This helps preventing the firmware from misinterpreting this
00101      * unique event as a USB bus reset from the USB host.
00102      */
00103     if(usb_device_state == ATTACHED_STATE)
00104     {
00105         if(!UCONbits.SE0)
00106         {
00107             UIR = 0;                        // Clear all USB interrupts
00108             UIE = 0;                        // Mask all USB interrupts
00109             UIEbits.URSTIE = 1;             // Unmask RESET interrupt
00110             UIEbits.IDLEIE = 1;             // Unmask IDLE interrupt
00111             usb_device_state = POWERED_STATE;
00112         }//end if                           // else wait until SE0 is cleared
00113     }//end if(usb_device_state == ATTACHED_STATE)
00114 
00115 }//end USBCheckBusStatus
00116 
00117 /******************************************************************************
00118  * Function:        void USBModuleEnable(void)
00119  *
00120  * PreCondition:    None
00121  *
00122  * Input:           None
00123  *
00124  * Output:          None
00125  *
00126  * Side Effects:    None
00127  *
00128  * Overview:        This routine enables the USB module.
00129  *                  An end designer should never have to call this routine
00130  *                  manually. This routine should only be called from
00131  *                  USBCheckBusStatus().
00132  *
00133  * Note:            See USBCheckBusStatus() for more information.
00134  *****************************************************************************/
00135 void USBModuleEnable(void)
00136 {
00137     UCON = 0;
00138     UIE = 0;                                // Mask all USB interrupts
00139     UCONbits.USBEN = 1;                     // Enable module & attach to bus
00140     usb_device_state = ATTACHED_STATE;      // Defined in usbmmap.c & .h
00141 }//end USBModuleEnable
00142 
00143 /******************************************************************************
00144  * Function:        void USBModuleDisable(void)
00145  *
00146  * PreCondition:    None
00147  *
00148  * Input:           None
00149  *
00150  * Output:          None
00151  *
00152  * Side Effects:    None
00153  *
00154  * Overview:        This routine disables the USB module.
00155  *                  An end designer should never have to call this routine
00156  *                  manually. This routine should only be called from
00157  *                  USBCheckBusStatus().
00158  *
00159  * Note:            See USBCheckBusStatus() for more information.
00160  *****************************************************************************/
00161 void USBModuleDisable(void)
00162 {
00163     UCON = 0;                               // Disable module & detach from bus
00164     UIE = 0;                                // Mask all USB interrupts
00165     usb_device_state = DETACHED_STATE;      // Defined in usbmmap.c & .h
00166 }//end USBModuleDisable
00167 
00168 /******************************************************************************
00169  * Function:        void USBSoftDetach(void)
00170  *
00171  * PreCondition:    None
00172  *
00173  * Input:           None
00174  *
00175  * Output:          None
00176  *
00177  * Side Effects:    The device will have to be re-enumerated to function again.
00178  *
00179  * Overview:        USBSoftDetach electrically disconnects the device from
00180  *                  the bus. This is done by stop supplying Vusb voltage to
00181  *                  pull-up resistor. The pull-down resistors on the host
00182  *                  side will pull both differential signal lines low and
00183  *                  the host registers the event as a disconnect.
00184  *
00185  *                  Since the USB cable is not physically disconnected, the
00186  *                  power supply through the cable can still be sensed by
00187  *                  the device. The next time USBCheckBusStatus() function
00188  *                  is called, it will reconnect the device back to the bus.
00189  *
00190  * Note:            None
00191  *****************************************************************************/
00192 void USBSoftDetach(void)
00193 {
00194     USBModuleDisable();
00195 }//end USBSoftDetach
00196 
00197 /******************************************************************************
00198  * Function:        void USBDriverService(void)
00199  *
00200  * PreCondition:    None
00201  *
00202  * Input:           None
00203  *
00204  * Output:          None
00205  *
00206  * Side Effects:    None
00207  *
00208  * Overview:        This routine is the heart of this firmware. It manages
00209  *                  all USB interrupts.
00210  *
00211  * Note:            Device state transitions through the following stages:
00212  *                  DETACHED -> ATTACHED -> POWERED -> DEFAULT ->
00213  *                  ADDRESS_PENDING -> ADDRESSED -> CONFIGURED -> READY
00214  *****************************************************************************/
00215 void USBDriverService(void)
00216 {   
00217     /*
00218      * Pointless to continue servicing if USB cable is not even attached.
00219      */
00220     if(usb_device_state == DETACHED_STATE) return;
00221     
00222     /*
00223      * Task A: Service USB Activity Interrupt
00224      */
00225 
00226     if(UIRbits.ACTVIF && UIEbits.ACTVIE)    USBWakeFromSuspend();
00227 
00228     /*
00229      * Pointless to continue servicing if the device is in suspend mode.
00230      */    
00231     if(UCONbits.SUSPND==1) return;
00232             
00233     /*
00234      * Task B: Service USB Bus Reset Interrupt.
00235      * When bus reset is received during suspend, ACTVIF will be set first,
00236      * once the UCONbits.SUSPND is clear, then the URSTIF bit will be asserted.
00237      * This is why URSTIF is checked after ACTVIF.
00238      */
00239     if(UIRbits.URSTIF && UIEbits.URSTIE)    USBProtocolResetHandler();
00240     
00241     /*
00242      * Task C: Service other USB interrupts
00243      */
00244     if(UIRbits.IDLEIF && UIEbits.IDLEIE)    USBSuspend();
00245     if(UIRbits.SOFIF && UIEbits.SOFIE)      USB_SOF_Handler();
00246     if(UIRbits.STALLIF && UIEbits.STALLIE)  USBStallHandler();
00247     if(UIRbits.UERRIF && UIEbits.UERRIE)    USBErrorHandler();
00248 
00249     /*
00250      * Pointless to continue servicing if the host has not sent a bus reset.
00251      * Once bus reset is received, the device transitions into the DEFAULT
00252      * state and is ready for communication.
00253      */
00254     if(usb_device_state < DEFAULT_STATE) return;
00255 
00256     /*
00257      * Task D: Servicing USB Transaction Complete Interrupt
00258      */
00259     if(UIRbits.TRNIF && UIEbits.TRNIE)
00260     {
00261         /*
00262          * USBCtrlEPService only services transactions over EP0.
00263          * It ignores all other EP transactions.
00264          */
00265         USBCtrlEPService();
00266         
00267         /*
00268          * Other EP can be serviced later by responsible device class firmware.
00269          * Each device driver knows when an OUT or IN transaction is ready by
00270          * checking the buffer ownership bit.
00271          * An OUT EP should always be owned by SIE until the data is ready.
00272          * An IN EP should always be owned by CPU until the data is ready.
00273          *
00274          * Because of this logic, it is not necessary to save the USTAT value
00275          * of non-EP0 transactions.
00276          */
00277         UIRbits.TRNIF = 0;
00278     }//end if(UIRbits.TRNIF && UIEbits.TRNIE)
00279     
00280 }//end USBDriverService
00281 
00282 /******************************************************************************
00283  * Function:        void USBSuspend(void)
00284  *
00285  * PreCondition:    None
00286  *
00287  * Input:           None
00288  *
00289  * Output:          None
00290  *
00291  * Side Effects:    None
00292  *
00293  * Overview:        
00294  *
00295  * Note:            None
00296  *****************************************************************************/
00297 void USBSuspend(void)
00298 {
00299     /*
00300      * NOTE: Do not clear UIRbits.ACTVIF here!
00301      * Reason:
00302      * ACTVIF is only generated once an IDLEIF has been generated.
00303      * This is a 1:1 ratio interrupt generation.
00304      * For every IDLEIF, there will be only one ACTVIF regardless of
00305      * the number of subsequent bus transitions.
00306      *
00307      * If the ACTIF is cleared here, a problem could occur when:
00308      * [       IDLE       ][bus activity ->
00309      * <--- 3 ms ----->     ^
00310      *                ^     ACTVIF=1
00311      *                IDLEIF=1
00312      *  #           #           #           #   (#=Program polling flags)
00313      *                          ^
00314      *                          This polling loop will see both
00315      *                          IDLEIF=1 and ACTVIF=1.
00316      *                          However, the program services IDLEIF first
00317      *                          because ACTIVIE=0.
00318      *                          If this routine clears the only ACTIVIF,
00319      *                          then it can never get out of the suspend
00320      *                          mode.             
00321      */
00322     UIEbits.ACTVIE = 1;                     // Enable bus activity interrupt
00323     UIRbits.IDLEIF = 0;
00324     UCONbits.SUSPND = 1;                    // Put USB module in power conserve
00325                                             // mode, SIE clock inactive
00326     /*
00327      * At this point the PIC can go into sleep,idle, or
00328      * switch to a slower clock, etc.
00329      */
00330     
00331     /* Modifiable Section */
00332     PIR2bits.USBIF = 0;
00333     PIE2bits.USBIE = 1;                     // Set USB wakeup source
00334     Sleep();                                // Goto sleep
00335     PIE2bits.USBIE = 0;
00336     /* End Modifiable Section */
00337 
00338 }//end USBSuspend
00339 
00340 /******************************************************************************
00341  * Function:        void USBWakeFromSuspend(void)
00342  *
00343  * PreCondition:    None
00344  *
00345  * Input:           None
00346  *
00347  * Output:          None
00348  *
00349  * Side Effects:    None
00350  *
00351  * Overview:        
00352  *
00353  * Note:            None
00354  *****************************************************************************/
00355 void USBWakeFromSuspend(void)
00356 {
00357     /* 
00358      * If using clock switching, this is the place to restore the
00359      * original clock frequency.
00360      */
00361     UCONbits.SUSPND = 0;
00362     UIEbits.ACTVIE = 0;
00363     UIRbits.ACTVIF = 0;
00364 }//end USBWakeFromSuspend
00365 
00366 /******************************************************************************
00367  * Function:        void USBRemoteWakeup(void)
00368  *
00369  * PreCondition:    None
00370  *
00371  * Input:           None
00372  *
00373  * Output:          None
00374  *
00375  * Side Effects:    None
00376  *
00377  * Overview:        This function should be called by user when the device
00378  *                  is waken up by an external stimulus other than ACTIVIF.
00379  *                  Please read the note below to understand the limitations.
00380  *
00381  * Note:            The modifiable section in this routine should be changed
00382  *                  to meet the application needs. Current implementation
00383  *                  temporary blocks other functions from executing for a
00384  *                  period of 1-13 ms depending on the core frequency.
00385  *
00386  *                  According to USB 2.0 specification section 7.1.7.7,
00387  *                  "The remote wakeup device must hold the resume signaling
00388  *                  for at lest 1 ms but for no more than 15 ms."
00389  *                  The idea here is to use a delay counter loop, using a
00390  *                  common value that would work over a wide range of core
00391  *                  frequencies.
00392  *                  That value selected is 1800. See table below:
00393  *                  ==========================================================
00394  *                  Core Freq(MHz)      MIP         RESUME Signal Period (ms)
00395  *                  ==========================================================
00396  *                      48              12          1.05
00397  *                       4              1           12.6
00398  *                  ==========================================================
00399  *                  * These timing could be incorrect when using code
00400  *                    optimization or extended instruction mode,
00401  *                    or when having other interrupts enabled.
00402  *                    Make sure to verify using the MPLAB SIM's Stopwatch
00403  *****************************************************************************/
00404 void USBRemoteWakeup(void)
00405 {
00406     static word delay_count;
00407     
00408     if(usb_stat.RemoteWakeup == 1)          // Check if RemoteWakeup function
00409     {                                       // has been enabled by the host.
00410         USBWakeFromSuspend();               // Unsuspend USB modue
00411         UCONbits.RESUME = 1;                // Start RESUME signaling
00412 
00413         /* Modifiable Section */
00414         
00415         delay_count = 1800U;                // Set RESUME line for 1-13 ms
00416         do
00417         {
00418             delay_count--;
00419         }while(delay_count);        
00420         
00421         /* End Modifiable Section */
00422         
00423         UCONbits.RESUME = 0;
00424     }//endif 
00425 }//end USBRemoteWakeup
00426 
00427 /******************************************************************************
00428  * Function:        void USB_SOF_Handler(void)
00429  *
00430  * PreCondition:    None
00431  *
00432  * Input:           None
00433  *
00434  * Output:          None
00435  *
00436  * Side Effects:    None
00437  *
00438  * Overview:        The USB host sends out a SOF packet to full-speed devices
00439  *                  every 1 ms. This interrupt may be useful for isochronous
00440  *                  pipes. End designers should implement callback routine
00441  *                  as necessary.
00442  *
00443  * Note:            None
00444  *****************************************************************************/
00445 void USB_SOF_Handler(void)
00446 {
00447     /* Callback routine here */
00448     
00449     UIRbits.SOFIF = 0;
00450 }//end USB_SOF_Handler
00451 
00452 /******************************************************************************
00453  * Function:        void USBStallHandler(void)
00454  *
00455  * PreCondition:    A STALL packet is sent to the host by the SIE.
00456  *
00457  * Input:           None
00458  *
00459  * Output:          None
00460  *
00461  * Side Effects:    None
00462  *
00463  * Overview:        The STALLIF is set anytime the SIE sends out a STALL
00464  *                  packet regardless of which endpoint causes it.
00465  *                  A Setup transaction overrides the STALL function. A stalled
00466  *                  endpoint stops stalling once it receives a setup packet.
00467  *                  In this case, the SIE will accepts the Setup packet and
00468  *                  set the TRNIF flag to notify the firmware. STALL function
00469  *                  for that particular endpoint pipe will be automatically
00470  *                  disabled (direction specific).
00471  *
00472  *                  There are a few reasons for an endpoint to be stalled.
00473  *                  1. When a non-supported USB request is received.
00474  *                     Example: GET_DESCRIPTOR(DEVICE_QUALIFIER)
00475  *                  2. When an endpoint is currently halted.
00476  *                  3. When the device class specifies that an endpoint must
00477  *                     stall in response to a specific event.
00478  *                     Example: Mass Storage Device Class
00479  *                              If the CBW is not valid, the device shall
00480  *                              STALL the Bulk-In pipe.
00481  *                              See USB Mass Storage Class Bulk-only Transport
00482  *                              Specification for more details.
00483  *
00484  * Note:            UEPn.EPSTALL can be scanned to see which endpoint causes
00485  *                  the stall event.
00486  *                  If
00487  *****************************************************************************/
00488 void USBStallHandler(void)
00489 {
00490     /*
00491      * Does not really have to do anything here,
00492      * even for the control endpoint.
00493      * All BDs of Endpoint 0 are owned by SIE right now,
00494      * but once a Setup Transaction is received, the ownership
00495      * for EP0_OUT will be returned to CPU.
00496      * When the Setup Transaction is serviced, the ownership
00497      * for EP0_IN will then be forced back to CPU by firmware.
00498      */
00499     if(UEP0bits.EPSTALL == 1)
00500     {
00501         USBPrepareForNextSetupTrf();        // Firmware work-around
00502         UEP0bits.EPSTALL = 0;
00503     }
00504     UIRbits.STALLIF = 0;
00505 }//end USBStallHandler
00506 
00507 /******************************************************************************
00508  * Function:        void USBErrorHandler(void)
00509  *
00510  * PreCondition:    None
00511  *
00512  * Input:           None
00513  *
00514  * Output:          None
00515  *
00516  * Side Effects:    None
00517  *
00518  * Overview:        The purpose of this interrupt is mainly for debugging
00519  *                  during development. Check UEIR to see which error causes
00520  *                  the interrupt.
00521  *
00522  * Note:            None
00523  *****************************************************************************/
00524 void USBErrorHandler(void)
00525 {
00526     UIRbits.UERRIF = 0;
00527 }//end USBErrorHandler
00528 
00529 /******************************************************************************
00530  * Function:        void USBProtocolResetHandler(void)
00531  *
00532  * PreCondition:    A USB bus reset is received from the host.
00533  *
00534  * Input:           None
00535  *
00536  * Output:          None
00537  *
00538  * Side Effects:    Currently, this routine flushes any pending USB
00539  *                  transactions. It empties out the USTAT FIFO. This action
00540  *                  might not be desirable in some applications.
00541  *
00542  * Overview:        Once a USB bus reset is received from the host, this
00543  *                  routine should be called. It resets the device address to
00544  *                  zero, disables all non-EP0 endpoints, initializes EP0 to
00545  *                  be ready for default communication, clears all USB
00546  *                  interrupt flags, unmasks applicable USB interrupts, and
00547  *                  reinitializes internal state-machine variables.
00548  *
00549  * Note:            None
00550  *****************************************************************************/
00551 void USBProtocolResetHandler(void)
00552 {
00553     UEIR = 0;                       // Clear all USB error flags
00554     UIR = 0;                        // Clears all USB interrupts
00555     UEIE = 0b10011111;              // Unmask all USB error interrupts
00556     UIE = 0b01111011;               // Enable all interrupts except ACTVIE
00557     
00558     UADDR = 0x00;                   // Reset to default address
00559     mDisableEP1to15();              // Reset all non-EP0 UEPn registers
00560     UEP0 = EP_CTRL|HSHK_EN;         // Init EP0 as a Ctrl EP, see usbdrv.h
00561 
00562     while(UIRbits.TRNIF == 1)       // Flush any pending transactions
00563         UIRbits.TRNIF = 0;
00564 
00565     UCONbits.PKTDIS = 0;            // Make sure packet processing is enabled
00566     USBPrepareForNextSetupTrf();    // Declared in usbctrltrf.c
00567     
00568     usb_stat.RemoteWakeup = 0;      // Default status flag to disable
00569     usb_active_cfg = 0;             // Clear active configuration
00570     usb_device_state = DEFAULT_STATE;
00571 }//end USBProtocolResetHandler
00572 
00573 
00574 /* Auxiliary Function */
00575 void ClearArray(byte* startAdr,byte count)
00576 {
00577     *startAdr;
00578     while(count)
00579     {
00580         _asm
00581         clrf POSTINC0,0
00582         _endasm
00583         count--;
00584     }//end while
00585 }//end ClearArray
00586 
00587 /** EOF usbdrv.c *************************************************************/

Generated on Wed Jun 8 03:49:39 2005 for cdc by  doxygen 1.4.2