firmware/usbdrv.c
author root@rika
Thu, 23 Apr 2009 19:10:12 +0200
changeset 30 7fd00015f62f
parent 2 2f55e5dd591d
permissions -rw-r--r--
several changes..
     1 /*********************************************************************
     2  *
     3  *                Microchip USB C18 Firmware Version 1.0
     4  *
     5  *********************************************************************
     6  * FileName:        usbdrv.c
     7  * Dependencies:    See INCLUDES section below
     8  * Processor:       PIC18
     9  * Compiler:        C18 2.30.01+
    10  * Company:         Microchip Technology, Inc.
    11  *
    12  * Software License Agreement
    13  *
    14  * The software supplied herewith by Microchip Technology Incorporated
    15  * (the “Company”) for its PICmicro® Microcontroller is intended and
    16  * supplied to you, the Company’s customer, for use solely and
    17  * exclusively on Microchip PICmicro Microcontroller products. The
    18  * software is owned by the Company and/or its supplier, and is
    19  * protected under applicable copyright laws. All rights are reserved.
    20  * Any use in violation of the foregoing restrictions may subject the
    21  * user to criminal sanctions under applicable laws, as well as to
    22  * civil liability for the breach of the terms and conditions of this
    23  * license.
    24  *
    25  * THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES,
    26  * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
    27  * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
    28  * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
    29  * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
    30  * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
    31  *
    32  * Author               Date        Comment
    33  *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    34  * Rawin Rojvanit       11/19/04    Original.
    35  ********************************************************************/
    36 
    37 /** I N C L U D E S **********************************************************/
    38 #include <p18cxxx.h>
    39 #include "typedefs.h"
    40 #include "usb.h"
    41 #include "io_cfg.h"             // Required for USBCheckBusStatus()
    42 
    43 /** V A R I A B L E S ********************************************************/
    44 #pragma udata
    45 
    46 /** P R I V A T E  P R O T O T Y P E S ***************************************/
    47 void USBModuleEnable(void);
    48 void USBModuleDisable(void);
    49 
    50 void USBSuspend(void);
    51 void USBWakeFromSuspend(void);
    52 
    53 void USBProtocolResetHandler(void);
    54 void USB_SOF_Handler(void);
    55 void USBStallHandler(void);
    56 void USBErrorHandler(void);
    57 
    58 /** D E C L A R A T I O N S **************************************************/
    59 #pragma code
    60 /******************************************************************************
    61  * Function:        void USBCheckBusStatus(void)
    62  *
    63  * PreCondition:    None
    64  *
    65  * Input:           None
    66  *
    67  * Output:          None
    68  *
    69  * Side Effects:    None
    70  *
    71  * Overview:        This routine enables/disables the USB module by monitoring
    72  *                  the USB power signal.
    73  *
    74  * Note:            None
    75  *****************************************************************************/
    76 void USBCheckBusStatus(void)
    77 {
    78     /**************************************************************************
    79      * Bus Attachment & Detachment Detection
    80      * usb_bus_sense is an i/o pin defined in io_cfg.h
    81      *************************************************************************/
    82     #define USB_BUS_ATTACHED    1
    83     #define USB_BUS_DETACHED    0
    84 
    85     if(usb_bus_sense == USB_BUS_ATTACHED)       // Is USB bus attached?
    86     {
    87         if(UCONbits.USBEN == 0)                 // Is the module off?
    88             USBModuleEnable();                  // Is off, enable it
    89     }
    90     else
    91     {
    92         if(UCONbits.USBEN == 1)                 // Is the module on?
    93             USBModuleDisable();                 // Is on, disable it
    94     }//end if(usb_bus_sense...)
    95     
    96     /*
    97      * After enabling the USB module, it takes some time for the voltage
    98      * on the D+ or D- line to rise high enough to get out of the SE0 condition.
    99      * The USB Reset interrupt should not be unmasked until the SE0 condition is
   100      * cleared. This helps preventing the firmware from misinterpreting this
   101      * unique event as a USB bus reset from the USB host.
   102      */
   103     if(usb_device_state == ATTACHED_STATE)
   104     {
   105         if(!UCONbits.SE0)
   106         {
   107             UIR = 0;                        // Clear all USB interrupts
   108             UIE = 0;                        // Mask all USB interrupts
   109             UIEbits.URSTIE = 1;             // Unmask RESET interrupt
   110             UIEbits.IDLEIE = 1;             // Unmask IDLE interrupt
   111             usb_device_state = POWERED_STATE;
   112         }//end if                           // else wait until SE0 is cleared
   113     }//end if(usb_device_state == ATTACHED_STATE)
   114 
   115 }//end USBCheckBusStatus
   116 
   117 /******************************************************************************
   118  * Function:        void USBModuleEnable(void)
   119  *
   120  * PreCondition:    None
   121  *
   122  * Input:           None
   123  *
   124  * Output:          None
   125  *
   126  * Side Effects:    None
   127  *
   128  * Overview:        This routine enables the USB module.
   129  *                  An end designer should never have to call this routine
   130  *                  manually. This routine should only be called from
   131  *                  USBCheckBusStatus().
   132  *
   133  * Note:            See USBCheckBusStatus() for more information.
   134  *****************************************************************************/
   135 void USBModuleEnable(void)
   136 {
   137     UCON = 0;
   138     UIE = 0;                                // Mask all USB interrupts
   139     UCONbits.USBEN = 1;                     // Enable module & attach to bus
   140     usb_device_state = ATTACHED_STATE;      // Defined in usbmmap.c & .h
   141 }//end USBModuleEnable
   142 
   143 /******************************************************************************
   144  * Function:        void USBModuleDisable(void)
   145  *
   146  * PreCondition:    None
   147  *
   148  * Input:           None
   149  *
   150  * Output:          None
   151  *
   152  * Side Effects:    None
   153  *
   154  * Overview:        This routine disables the USB module.
   155  *                  An end designer should never have to call this routine
   156  *                  manually. This routine should only be called from
   157  *                  USBCheckBusStatus().
   158  *
   159  * Note:            See USBCheckBusStatus() for more information.
   160  *****************************************************************************/
   161 void USBModuleDisable(void)
   162 {
   163     UCON = 0;                               // Disable module & detach from bus
   164     UIE = 0;                                // Mask all USB interrupts
   165     usb_device_state = DETACHED_STATE;      // Defined in usbmmap.c & .h
   166 }//end USBModuleDisable
   167 
   168 /******************************************************************************
   169  * Function:        void USBSoftDetach(void)
   170  *
   171  * PreCondition:    None
   172  *
   173  * Input:           None
   174  *
   175  * Output:          None
   176  *
   177  * Side Effects:    The device will have to be re-enumerated to function again.
   178  *
   179  * Overview:        USBSoftDetach electrically disconnects the device from
   180  *                  the bus. This is done by stop supplying Vusb voltage to
   181  *                  pull-up resistor. The pull-down resistors on the host
   182  *                  side will pull both differential signal lines low and
   183  *                  the host registers the event as a disconnect.
   184  *
   185  *                  Since the USB cable is not physically disconnected, the
   186  *                  power supply through the cable can still be sensed by
   187  *                  the device. The next time USBCheckBusStatus() function
   188  *                  is called, it will reconnect the device back to the bus.
   189  *
   190  * Note:            None
   191  *****************************************************************************/
   192 void USBSoftDetach(void)
   193 {
   194     USBModuleDisable();
   195 }//end USBSoftDetach
   196 
   197 /******************************************************************************
   198  * Function:        void USBDriverService(void)
   199  *
   200  * PreCondition:    None
   201  *
   202  * Input:           None
   203  *
   204  * Output:          None
   205  *
   206  * Side Effects:    None
   207  *
   208  * Overview:        This routine is the heart of this firmware. It manages
   209  *                  all USB interrupts.
   210  *
   211  * Note:            Device state transitions through the following stages:
   212  *                  DETACHED -> ATTACHED -> POWERED -> DEFAULT ->
   213  *                  ADDRESS_PENDING -> ADDRESSED -> CONFIGURED -> READY
   214  *****************************************************************************/
   215 void USBDriverService(void)
   216 {   
   217     /*
   218      * Pointless to continue servicing if USB cable is not even attached.
   219      */
   220     if(usb_device_state == DETACHED_STATE) return;
   221     
   222     /*
   223      * Task A: Service USB Activity Interrupt
   224      */
   225 
   226     if(UIRbits.ACTVIF && UIEbits.ACTVIE)    USBWakeFromSuspend();
   227 
   228     /*
   229      * Pointless to continue servicing if the device is in suspend mode.
   230      */    
   231     if(UCONbits.SUSPND==1) return;
   232             
   233     /*
   234      * Task B: Service USB Bus Reset Interrupt.
   235      * When bus reset is received during suspend, ACTVIF will be set first,
   236      * once the UCONbits.SUSPND is clear, then the URSTIF bit will be asserted.
   237      * This is why URSTIF is checked after ACTVIF.
   238      */
   239     if(UIRbits.URSTIF && UIEbits.URSTIE)    USBProtocolResetHandler();
   240     
   241     /*
   242      * Task C: Service other USB interrupts
   243      */
   244     if(UIRbits.IDLEIF && UIEbits.IDLEIE)    USBSuspend();
   245     if(UIRbits.SOFIF && UIEbits.SOFIE)      USB_SOF_Handler();
   246     if(UIRbits.STALLIF && UIEbits.STALLIE)  USBStallHandler();
   247     if(UIRbits.UERRIF && UIEbits.UERRIE)    USBErrorHandler();
   248 
   249     /*
   250      * Pointless to continue servicing if the host has not sent a bus reset.
   251      * Once bus reset is received, the device transitions into the DEFAULT
   252      * state and is ready for communication.
   253      */
   254     if(usb_device_state < DEFAULT_STATE) return;
   255 
   256     /*
   257      * Task D: Servicing USB Transaction Complete Interrupt
   258      */
   259     if(UIRbits.TRNIF && UIEbits.TRNIE)
   260     {
   261         /*
   262          * USBCtrlEPService only services transactions over EP0.
   263          * It ignores all other EP transactions.
   264          */
   265         USBCtrlEPService();
   266         
   267         /*
   268          * Other EP can be serviced later by responsible device class firmware.
   269          * Each device driver knows when an OUT or IN transaction is ready by
   270          * checking the buffer ownership bit.
   271          * An OUT EP should always be owned by SIE until the data is ready.
   272          * An IN EP should always be owned by CPU until the data is ready.
   273          *
   274          * Because of this logic, it is not necessary to save the USTAT value
   275          * of non-EP0 transactions.
   276          */
   277         UIRbits.TRNIF = 0;
   278     }//end if(UIRbits.TRNIF && UIEbits.TRNIE)
   279     
   280 }//end USBDriverService
   281 
   282 /******************************************************************************
   283  * Function:        void USBSuspend(void)
   284  *
   285  * PreCondition:    None
   286  *
   287  * Input:           None
   288  *
   289  * Output:          None
   290  *
   291  * Side Effects:    None
   292  *
   293  * Overview:        
   294  *
   295  * Note:            None
   296  *****************************************************************************/
   297 void USBSuspend(void)
   298 {
   299     /*
   300      * NOTE: Do not clear UIRbits.ACTVIF here!
   301      * Reason:
   302      * ACTVIF is only generated once an IDLEIF has been generated.
   303      * This is a 1:1 ratio interrupt generation.
   304      * For every IDLEIF, there will be only one ACTVIF regardless of
   305      * the number of subsequent bus transitions.
   306      *
   307      * If the ACTIF is cleared here, a problem could occur when:
   308      * [       IDLE       ][bus activity ->
   309      * <--- 3 ms ----->     ^
   310      *                ^     ACTVIF=1
   311      *                IDLEIF=1
   312      *  #           #           #           #   (#=Program polling flags)
   313      *                          ^
   314      *                          This polling loop will see both
   315      *                          IDLEIF=1 and ACTVIF=1.
   316      *                          However, the program services IDLEIF first
   317      *                          because ACTIVIE=0.
   318      *                          If this routine clears the only ACTIVIF,
   319      *                          then it can never get out of the suspend
   320      *                          mode.             
   321      */
   322     UIEbits.ACTVIE = 1;                     // Enable bus activity interrupt
   323     UIRbits.IDLEIF = 0;
   324     UCONbits.SUSPND = 1;                    // Put USB module in power conserve
   325                                             // mode, SIE clock inactive
   326     /*
   327      * At this point the PIC can go into sleep,idle, or
   328      * switch to a slower clock, etc.
   329      */
   330     
   331     /* Modifiable Section */
   332     PIR2bits.USBIF = 0;
   333     PIE2bits.USBIE = 1;                     // Set USB wakeup source
   334     Sleep();                                // Goto sleep
   335     PIE2bits.USBIE = 0;
   336     /* End Modifiable Section */
   337 
   338 }//end USBSuspend
   339 
   340 /******************************************************************************
   341  * Function:        void USBWakeFromSuspend(void)
   342  *
   343  * PreCondition:    None
   344  *
   345  * Input:           None
   346  *
   347  * Output:          None
   348  *
   349  * Side Effects:    None
   350  *
   351  * Overview:        
   352  *
   353  * Note:            None
   354  *****************************************************************************/
   355 void USBWakeFromSuspend(void)
   356 {
   357     /* 
   358      * If using clock switching, this is the place to restore the
   359      * original clock frequency.
   360      */
   361     UCONbits.SUSPND = 0;
   362     UIEbits.ACTVIE = 0;
   363     UIRbits.ACTVIF = 0;
   364 }//end USBWakeFromSuspend
   365 
   366 /******************************************************************************
   367  * Function:        void USBRemoteWakeup(void)
   368  *
   369  * PreCondition:    None
   370  *
   371  * Input:           None
   372  *
   373  * Output:          None
   374  *
   375  * Side Effects:    None
   376  *
   377  * Overview:        This function should be called by user when the device
   378  *                  is waken up by an external stimulus other than ACTIVIF.
   379  *                  Please read the note below to understand the limitations.
   380  *
   381  * Note:            The modifiable section in this routine should be changed
   382  *                  to meet the application needs. Current implementation
   383  *                  temporary blocks other functions from executing for a
   384  *                  period of 1-13 ms depending on the core frequency.
   385  *
   386  *                  According to USB 2.0 specification section 7.1.7.7,
   387  *                  "The remote wakeup device must hold the resume signaling
   388  *                  for at lest 1 ms but for no more than 15 ms."
   389  *                  The idea here is to use a delay counter loop, using a
   390  *                  common value that would work over a wide range of core
   391  *                  frequencies.
   392  *                  That value selected is 1800. See table below:
   393  *                  ==========================================================
   394  *                  Core Freq(MHz)      MIP         RESUME Signal Period (ms)
   395  *                  ==========================================================
   396  *                      48              12          1.05
   397  *                       4              1           12.6
   398  *                  ==========================================================
   399  *                  * These timing could be incorrect when using code
   400  *                    optimization or extended instruction mode,
   401  *                    or when having other interrupts enabled.
   402  *                    Make sure to verify using the MPLAB SIM's Stopwatch
   403  *****************************************************************************/
   404 void USBRemoteWakeup(void)
   405 {
   406     static word delay_count;
   407     
   408     if(usb_stat.RemoteWakeup == 1)          // Check if RemoteWakeup function
   409     {                                       // has been enabled by the host.
   410         USBWakeFromSuspend();               // Unsuspend USB modue
   411         UCONbits.RESUME = 1;                // Start RESUME signaling
   412 
   413         /* Modifiable Section */
   414         
   415         delay_count = 1800U;                // Set RESUME line for 1-13 ms
   416         do
   417         {
   418             delay_count--;
   419         }while(delay_count);        
   420         
   421         /* End Modifiable Section */
   422         
   423         UCONbits.RESUME = 0;
   424     }//endif 
   425 }//end USBRemoteWakeup
   426 
   427 /******************************************************************************
   428  * Function:        void USB_SOF_Handler(void)
   429  *
   430  * PreCondition:    None
   431  *
   432  * Input:           None
   433  *
   434  * Output:          None
   435  *
   436  * Side Effects:    None
   437  *
   438  * Overview:        The USB host sends out a SOF packet to full-speed devices
   439  *                  every 1 ms. This interrupt may be useful for isochronous
   440  *                  pipes. End designers should implement callback routine
   441  *                  as necessary.
   442  *
   443  * Note:            None
   444  *****************************************************************************/
   445 void USB_SOF_Handler(void)
   446 {
   447     /* Callback routine here */
   448     
   449     UIRbits.SOFIF = 0;
   450 }//end USB_SOF_Handler
   451 
   452 /******************************************************************************
   453  * Function:        void USBStallHandler(void)
   454  *
   455  * PreCondition:    A STALL packet is sent to the host by the SIE.
   456  *
   457  * Input:           None
   458  *
   459  * Output:          None
   460  *
   461  * Side Effects:    None
   462  *
   463  * Overview:        The STALLIF is set anytime the SIE sends out a STALL
   464  *                  packet regardless of which endpoint causes it.
   465  *                  A Setup transaction overrides the STALL function. A stalled
   466  *                  endpoint stops stalling once it receives a setup packet.
   467  *                  In this case, the SIE will accepts the Setup packet and
   468  *                  set the TRNIF flag to notify the firmware. STALL function
   469  *                  for that particular endpoint pipe will be automatically
   470  *                  disabled (direction specific).
   471  *
   472  *                  There are a few reasons for an endpoint to be stalled.
   473  *                  1. When a non-supported USB request is received.
   474  *                     Example: GET_DESCRIPTOR(DEVICE_QUALIFIER)
   475  *                  2. When an endpoint is currently halted.
   476  *                  3. When the device class specifies that an endpoint must
   477  *                     stall in response to a specific event.
   478  *                     Example: Mass Storage Device Class
   479  *                              If the CBW is not valid, the device shall
   480  *                              STALL the Bulk-In pipe.
   481  *                              See USB Mass Storage Class Bulk-only Transport
   482  *                              Specification for more details.
   483  *
   484  * Note:            UEPn.EPSTALL can be scanned to see which endpoint causes
   485  *                  the stall event.
   486  *                  If
   487  *****************************************************************************/
   488 void USBStallHandler(void)
   489 {
   490     /*
   491      * Does not really have to do anything here,
   492      * even for the control endpoint.
   493      * All BDs of Endpoint 0 are owned by SIE right now,
   494      * but once a Setup Transaction is received, the ownership
   495      * for EP0_OUT will be returned to CPU.
   496      * When the Setup Transaction is serviced, the ownership
   497      * for EP0_IN will then be forced back to CPU by firmware.
   498      */
   499     if(UEP0bits.EPSTALL == 1)
   500     {
   501         USBPrepareForNextSetupTrf();        // Firmware work-around
   502         UEP0bits.EPSTALL = 0;
   503     }
   504     UIRbits.STALLIF = 0;
   505 }//end USBStallHandler
   506 
   507 /******************************************************************************
   508  * Function:        void USBErrorHandler(void)
   509  *
   510  * PreCondition:    None
   511  *
   512  * Input:           None
   513  *
   514  * Output:          None
   515  *
   516  * Side Effects:    None
   517  *
   518  * Overview:        The purpose of this interrupt is mainly for debugging
   519  *                  during development. Check UEIR to see which error causes
   520  *                  the interrupt.
   521  *
   522  * Note:            None
   523  *****************************************************************************/
   524 void USBErrorHandler(void)
   525 {
   526     UIRbits.UERRIF = 0;
   527 }//end USBErrorHandler
   528 
   529 /******************************************************************************
   530  * Function:        void USBProtocolResetHandler(void)
   531  *
   532  * PreCondition:    A USB bus reset is received from the host.
   533  *
   534  * Input:           None
   535  *
   536  * Output:          None
   537  *
   538  * Side Effects:    Currently, this routine flushes any pending USB
   539  *                  transactions. It empties out the USTAT FIFO. This action
   540  *                  might not be desirable in some applications.
   541  *
   542  * Overview:        Once a USB bus reset is received from the host, this
   543  *                  routine should be called. It resets the device address to
   544  *                  zero, disables all non-EP0 endpoints, initializes EP0 to
   545  *                  be ready for default communication, clears all USB
   546  *                  interrupt flags, unmasks applicable USB interrupts, and
   547  *                  reinitializes internal state-machine variables.
   548  *
   549  * Note:            None
   550  *****************************************************************************/
   551 void USBProtocolResetHandler(void)
   552 {
   553     UEIR = 0;                       // Clear all USB error flags
   554     UIR = 0;                        // Clears all USB interrupts
   555     UEIE = 0b10011111;              // Unmask all USB error interrupts
   556     UIE = 0b01111011;               // Enable all interrupts except ACTVIE
   557     
   558     UADDR = 0x00;                   // Reset to default address
   559     mDisableEP1to15();              // Reset all non-EP0 UEPn registers
   560     UEP0 = EP_CTRL|HSHK_EN;         // Init EP0 as a Ctrl EP, see usbdrv.h
   561 
   562     while(UIRbits.TRNIF == 1)       // Flush any pending transactions
   563         UIRbits.TRNIF = 0;
   564 
   565     UCONbits.PKTDIS = 0;            // Make sure packet processing is enabled
   566     USBPrepareForNextSetupTrf();    // Declared in usbctrltrf.c
   567     
   568     usb_stat.RemoteWakeup = 0;      // Default status flag to disable
   569     usb_active_cfg = 0;             // Clear active configuration
   570     usb_device_state = DEFAULT_STATE;
   571 }//end USBProtocolResetHandler
   572 
   573 
   574 /* Auxiliary Function */
   575 void ClearArray(byte* startAdr,byte count)
   576 {
   577     *startAdr;
   578     while(count)
   579     {
   580         _asm
   581         clrf POSTINC0,0
   582         _endasm
   583         count--;
   584     }//end while
   585 }//end ClearArray
   586 
   587 /** EOF usbdrv.c *************************************************************/