/* * File: main.c * Author: justin * * Created on August 9, 2019, 6:14 PM */ #include "usb.h" #include "bootloader.h" unsigned int uint_delay_counter; /* Private prototypes */ void main(void); void BootMain(void); void InitializeSystem(void); const unsigned int FlashSignatureWord __at(APP_SIGNATURE_ADDRESS) = APP_SIGNATURE_VALUE; //const unsigned int FlashSignatureWord __at(APP_SIGNATURE_ADDRESS) = APP_SIGNATURE_VALUE; void main(void) { //BootMain(); /** * TODO: implement hardware IO-based method for forcing entry into bootloader */ // normal operation: verify the firmware signature is valid. if it isn't enter // bootloader (fw update) mode so valid firmware can be flashed DoFlashSignatureCheck: //Check if the application region flash signature is valid if(*(const unsigned int*)APP_SIGNATURE_ADDRESS == APP_SIGNATURE_VALUE) { //The flash signature was valid, implying the previous //erase/program/verify operation was a success. //Also make sure the first WORD of program memory in the app space //is not blank, meaning there is an application image programmed into the device. if(*(const unsigned int*)REMAPPED_APPLICATION_RESET_VECTOR != 0xFFFF) { //Go ahead and jump out of bootloader mode into the application run mode #asm goto REMAPPED_APPLICATION_RESET_VECTOR #endasm } } //else the application image is missing or corrupt. In this case, we //need to stay in the bootloader mode, so the user has the ability to //try (again) to re-program a valid application image into the device. BootMain(); } void BootMain(void) __at(0x30) { //Make sure interrupts are disabled for this code (could still be on, //if the application firmware jumped into the bootloader via software methods) INTCON = 0x00; //Clear the stack pointer, in case the user application jumped into //bootloader mode with excessive junk on the call stack STKPTR = 0x00; // End of the important parts of the C initializer. This bootloader firmware does not use // any C initialized user variables (idata memory sections). Therefore, the above is all // the initialization that is required. //Call other initialization code and (re)enable the USB module InitializeSystem(); //Execute main loop while(1) { //Need to call USBDeviceTasks() periodically. This function takes care of //processing non-USB application related USB packets (ex: "Chapter 9" //packets associated with USB enumeration) USBDeviceTasks(); ProcessIO(); //This is where all the actual bootloader related data transfer/self programming takes //place see ProcessIO() function in the BootPIC[xxxx].c file. }//end while } void InitializeSystem(void) { UserInit(); USBDeviceInit(); } // ****************************************************************************************************** // ************** 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. // // 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 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: Before returning from this function, make sure that the * oscillator settings are fully compatible with USB module * operation. * If using the two-speed startup feature, wakeup and execution * will occur before the main oscillator + PLL has had a chance * to start. Device will run from INTOSC (no PLL). However, the * USB module cannot be clocked and receive correct USB data when * it is not clocked with the correct frequency clock source. * Therefore, when using two-speed startup, should execute software * delay to prevent any other code from executing until the main * oscillator is ready. * The host will allow at least 10ms for USB "resume recovery", during * which it will not try to communicate with the device. *****************************************************************************/ void USBCBWakeFromSuspend(void) { //This code delays ~5ms @ 8MHz to execute (using C18 3.21 with full //optimizations enabled), but takes much less time at 48MHz. This delay //is to make sure the PLL is enabled and locked, in case two speed startup //was enabled DelayRoutine(0x300); //Device will switch clocks (if using two-speed startup) while executing this delay function //Primary oscillator and PLL should be running by now. //Do not return from this function until the oscillator is correctly configured and //running in a USB compatible mode/frequency. //Additional code for re-enabling I/O pins and increasing power draw from VBUS //may be placed here (up to the maximum of 100mA [when unconfigured] or the //amount specified in the configuration descriptor (when configured). } /****************************************************************************** * 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) { Sleep(); // Go to sleep, wake up when a USB activity event occurs //If using the WDT, should go back to sleep if awoke by WDT instead of USBIF while((USBIF_FLAG == 0) && (RCONbits.TO == 0)) //If using the WDT, should go back to sleep if awoke by WDT instead of USBIF { Sleep(); //Entry into sleep clears WDT count, much like executing ClrWdt() instruction } //After the USB suspend event ends, you should re-configure your I/O pins //for normal operation mode (which is allowed to consume more current). //However, it is recommended to put this code in the USBCBWakeFromSuspend() //function instead of here (so that this function will work with either //sleeping or clock switching to a lower frequency). } /******************************************************************* * Function: void USBCBInitEP(uint8_t ConfigurationIndex) * * 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 request. This * callback function should initialize the endpoints * for the device's usage according to the current * configuration. * * Note: If the host ever "unconfigures" the device, it will * set the configuration to '0'. In this case, this * callback gets called with ConfigurationIndex == 0, where * the firmware should disable all non-EP0 endpoints (until * the next non-zero SET_CONFIGURATION request is received, * which will cause this callback to execute again). *******************************************************************/ void USBCBInitEP(uint8_t ConfigurationIndex) { //Check what configuration "index" the host has requested us to select. //Configuration index 0 is special and represents that the device should be //un-configured. However, when the host sets the configuration (with index //matching the valid/implemented configuration from the configuration descriptor), //the firmware should enable the application endpoints associated with that //configuration, and (re)initialize all application state variables associated //with the USB application endpoints operation. if(ConfigurationIndex == 1) //This application only implements one configuration, with index == 1. { //The host sent us a non-zero set configuration index. In this //case we should prepare the application endpoints to be ready //to use, and to (re-)initialize any application variables associated //with the endpoints. HIDInitEP(); //(Re-)Initialize the application variables associated with the USB interface UserInit(); // See BootPIC[xxxx].c. Initializes the bootloader firmware state machine variables. } //else the host set the configuration back to 0 (indicating unconfigured), or //to some higher (non-implemented value). In either case, we don't need to //do anything specifically, unless the application requires some kind of //"safe shutdown" code to execute after the host has deconfigured the device. } /******************************************************************* * Function: void USBCBCheckOtherReq(void) * * PreCondition: None * * Input: None * * Output: None * * Side Effects: None * * Overview: This function is called when the USB stack receives a * new control transfer SETUP packet from the host. The * USB stack handles normal USB "Chapter 9" requests internally, * but some control transfer requests are class specific. In * order to handle these class specific requests, you must call * the class handler's firmware control transfer handler function. * If implementing a composite device with multiple classes * implemented, call each of the handlers in the below callback. * * Note: None *******************************************************************/ void USBCBCheckOtherReq(void) { USBCheckHIDRequest(); }