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 *************************************************************/