273 lines
12 KiB
C
273 lines
12 KiB
C
/*
|
|
* 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();
|
|
} |