started porting over the actual bootloader code from the MLA demo
This commit is contained in:
793
bootloader/src/bootloader.c
Normal file
793
bootloader/src/bootloader.c
Normal file
@@ -0,0 +1,793 @@
|
|||||||
|
#include "bootloader.h"
|
||||||
|
#include "typedefs.h"
|
||||||
|
#include "usb.h"
|
||||||
|
#include "usb_device_hid.h"
|
||||||
|
|
||||||
|
|
||||||
|
//The bootloader version, which the bootloader PC application can do extended query to get.
|
||||||
|
//Value provided is expected to be in the format of BOOTLOADER_VERSION_MAJOR.BOOTLOADER_VERSION_MINOR
|
||||||
|
//Ex: 1.01 would be BOOTLOADER_VERSION_MAJOR == 1, and BOOTLOADER_VERSION_MINOR == 1
|
||||||
|
#define BOOTLOADER_VERSION_MAJOR 1 //Legal value 0-255
|
||||||
|
#define BOOTLOADER_VERSION_MINOR 2 //Legal value 0-99. (1 = X.01)
|
||||||
|
|
||||||
|
//Section defining the address range to erase for the erase device command, along with the valid programming range to be reported by the QUERY_DEVICE command.
|
||||||
|
#define PROGRAM_MEM_START_ADDRESS REMAPPED_APPLICATION_RESET_VECTOR //Beginning of application program memory (not occupied by bootloader). **THIS VALUE MUST BE ALIGNED WITH 64 BYTE BLOCK BOUNDRY** Also, in order to work correctly, make sure the StartPageToErase is set to erase this section.
|
||||||
|
|
||||||
|
#define MAX_PAGE_TO_ERASE 511 //Last 64 byte page of flash on the PIC18F4550
|
||||||
|
#define PROGRAM_MEM_STOP_ADDRESS 0x008000 //**MUST BE WORD ALIGNED (EVEN) ADDRESS. This address does not get updated, but the one just below it does: IE: If PROGRAM_MEM_STOP_ADDRESS = 0x200, 0x1FF is the last programmed address (0x200 not programmed)**
|
||||||
|
#define CONFIG_WORDS_START_ADDRESS 0x300000 //0x300000 is start of CONFIG space for these devices
|
||||||
|
#define CONFIG_WORDS_SECTION_LENGTH 14 //14 bytes worth of Configuration words on these devices
|
||||||
|
#define USER_ID_ADDRESS 0x200000 //User ID is 8 bytes starting at 0x200000
|
||||||
|
#define USER_ID_SIZE 8
|
||||||
|
#define DEVICE_WITH_EEPROM //Comment this out, if you never want the bootloader to reprogram the EEPROM space
|
||||||
|
#define EEPROM_SIZE 0x100 //256 bytes of EEPROM on this device
|
||||||
|
#define EEPROM_EFFECTIVE_ADDRESS 0xF00000 //Location in the .hex file where the EEPROM contents are stored
|
||||||
|
#define WRITE_BLOCK_SIZE 0x20 //32 byte programming block size on the PIC18F4550/PIC18F4553 family devices
|
||||||
|
#define ERASE_PAGE_SIZE 64
|
||||||
|
|
||||||
|
//Derived microcontroller address/page constants
|
||||||
|
#define START_PAGE_TO_ERASE (PROGRAM_MEM_START_ADDRESS/ERASE_PAGE_SIZE) //The first flash page number to erase, which is the start of the application program space
|
||||||
|
#define ERASE_PAGE_ADDRESS_MASK (uint24_t)(0x1000000 - ERASE_PAGE_SIZE) //AND mask to move an address pointer to the start of an erase page
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Bootloader Command From Host - Switch() State Variable Choices
|
||||||
|
#define QUERY_DEVICE 0x02 //Command that the host uses to learn about the device (what regions can be programmed, and what type of memory is the region)
|
||||||
|
#define UNLOCK_CONFIG 0x03 //Note, this command is used for both locking and unlocking the config bits (see the "//Unlock Configs Command Definitions" below)
|
||||||
|
#define ERASE_DEVICE 0x04 //Host sends this command to start an erase operation. Firmware controls which pages should be erased.
|
||||||
|
#define PROGRAM_DEVICE 0x05 //If host is going to send a full RequestDataBlockSize to be programmed, it uses this command.
|
||||||
|
#define PROGRAM_COMPLETE 0x06 //If host send less than a RequestDataBlockSize to be programmed, or if it wished to program whatever was left in the buffer, it uses this command.
|
||||||
|
#define GET_DATA 0x07 //The host sends this command in order to read out memory from the device. Used during verify (and read/export hex operations)
|
||||||
|
#define RESET_DEVICE 0x08 //Resets the microcontroller, so it can update the config bits (if they were programmed, and so as to leave the bootloader (and potentially go back into the main application)
|
||||||
|
#define SIGN_FLASH 0x09 //The host PC application should send this command after the verify operation has completed successfully. If checksums are used instead of a true verify (due to ALLOW_GET_DATA_COMMAND being commented), then the host PC application should send SIGN_FLASH command after is has verified the checksums are as exected. The firmware will then program the SIGNATURE_WORD into flash at the SIGNATURE_ADDRESS.
|
||||||
|
#define QUERY_EXTENDED_INFO 0x0C //Used by host PC app to get additional info about the device, beyond the basic NVM layout provided by the query device command
|
||||||
|
|
||||||
|
//Unlock Configs Command Definitions
|
||||||
|
#define UNLOCKCONFIG 0x00 //Sub-command for the ERASE_DEVICE command
|
||||||
|
#define LOCKCONFIG 0x01 //Sub-command for the ERASE_DEVICE command
|
||||||
|
|
||||||
|
//Query Device Response "Types"
|
||||||
|
#define MEMORY_REGION_PROGRAM_MEM 0x01 //When the host sends a QUERY_DEVICE command, need to respond by populating a list of valid memory regions that exist in the device (and should be programmed)
|
||||||
|
#define MEMORY_REGION_EEDATA 0x02
|
||||||
|
#define MEMORY_REGION_CONFIG 0x03
|
||||||
|
#define MEMORY_REGION_USERID 0x04
|
||||||
|
#define MEMORY_REGION_END 0xFF //Sort of serves as a "null terminator" like number, which denotes the end of the memory region list has been reached.
|
||||||
|
#define BOOTLOADER_V1_01_OR_NEWER_FLAG 0xA5 //Tacked on in the VersionFlag byte, to indicate when using newer version of bootloader with extended query info available
|
||||||
|
|
||||||
|
|
||||||
|
//BootState Variable States
|
||||||
|
#define IDLE 0x00
|
||||||
|
#define NOT_IDLE 0x01
|
||||||
|
|
||||||
|
//OtherConstants
|
||||||
|
#define INVALID_ADDRESS 0xFFFFFFFF
|
||||||
|
#define CORRECT_UNLOCK_KEY 0xB5
|
||||||
|
|
||||||
|
//Application and Microcontroller constants
|
||||||
|
#define BYTES_PER_ADDRESS_PIC18 0x01 //One byte per address. PIC24 uses 2 bytes for each address in the hex file.
|
||||||
|
#define USB_PACKET_SIZE 0x40
|
||||||
|
#define WORDSIZE 0x02 //PIC18 uses 2 byte words, PIC24 uses 3 byte words.
|
||||||
|
#define REQUEST_DATA_BLOCK_SIZE 0x3A //Number of data bytes in a standard request to the PC. Must be an even number from 2-58 (0x02-0x3A). Larger numbers make better use of USB bandwidth and
|
||||||
|
//yeild shorter program/verify times, but require more micrcontroller RAM for buffer space.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** USB Packet Request/Response Formatting Structure **********************************************************/
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
unsigned char Contents[USB_PACKET_SIZE];
|
||||||
|
|
||||||
|
//General command (with data in it) packet structure used by PROGRAM_DEVICE and GET_DATA commands
|
||||||
|
struct{
|
||||||
|
unsigned char Command;
|
||||||
|
unsigned long Address;
|
||||||
|
unsigned char Size;
|
||||||
|
//unsigned char PadBytes[58-REQUEST_DATA_BLOCK_SIZE]; //Uncomment this if using a smaller than 0x3A RequestDataBlockSize. Compiler doesn't like 0 byte array when using 58 byte data block size.
|
||||||
|
unsigned char Data[REQUEST_DATA_BLOCK_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
//This struct used for responding to QUERY_DEVICE command (on a device with four programmable sections)
|
||||||
|
struct{
|
||||||
|
unsigned char Command;
|
||||||
|
unsigned char PacketDataFieldSize;
|
||||||
|
unsigned char BytesPerAddress;
|
||||||
|
unsigned char Type1;
|
||||||
|
unsigned long Address1;
|
||||||
|
unsigned long Length1;
|
||||||
|
unsigned char Type2;
|
||||||
|
unsigned long Address2;
|
||||||
|
unsigned long Length2;
|
||||||
|
unsigned char Type3;
|
||||||
|
unsigned long Address3;
|
||||||
|
unsigned long Length3;
|
||||||
|
unsigned char Type4;
|
||||||
|
unsigned long Address4;
|
||||||
|
unsigned long Length4;
|
||||||
|
unsigned char Type5;
|
||||||
|
unsigned long Address5;
|
||||||
|
unsigned long Length5;
|
||||||
|
unsigned char Type6;
|
||||||
|
unsigned long Address6;
|
||||||
|
unsigned long Length6;
|
||||||
|
unsigned char VersionFlag; //Used by host software to identify if device is new enough to support QUERY_EXTENDED_INFO command
|
||||||
|
unsigned char ExtraPadBytes[7];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct{ //For UNLOCK_CONFIG command
|
||||||
|
unsigned char Command;
|
||||||
|
unsigned char LockValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Structure for the QUERY_EXTENDED_INFO command (and response)
|
||||||
|
struct{
|
||||||
|
unsigned char Command;
|
||||||
|
unsigned int BootloaderVersion;
|
||||||
|
unsigned int ApplicationVersion;
|
||||||
|
unsigned long SignatureAddress;
|
||||||
|
unsigned int SignatureValue;
|
||||||
|
unsigned long ErasePageSize;
|
||||||
|
unsigned char Config1LMask;
|
||||||
|
unsigned char Config1HMask;
|
||||||
|
unsigned char Config2LMask;
|
||||||
|
unsigned char Config2HMask;
|
||||||
|
unsigned char Config3LMask;
|
||||||
|
unsigned char Config3HMask;
|
||||||
|
unsigned char Config4LMask;
|
||||||
|
unsigned char Config4HMask;
|
||||||
|
unsigned char Config5LMask;
|
||||||
|
unsigned char Config5HMask;
|
||||||
|
unsigned char Config6LMask;
|
||||||
|
unsigned char Config6HMask;
|
||||||
|
unsigned char Config7LMask;
|
||||||
|
unsigned char Config7HMask;
|
||||||
|
};
|
||||||
|
} PacketToFromPC;
|
||||||
|
|
||||||
|
PacketToFromPC PacketFromPC;
|
||||||
|
PacketToFromPC PacketToPC;
|
||||||
|
unsigned char ProgrammingBuffer[ERASE_PAGE_SIZE];
|
||||||
|
unsigned char BootState;
|
||||||
|
unsigned int ErasePageTracker;
|
||||||
|
unsigned char BufferedDataIndex;
|
||||||
|
uint24_t ProgrammedPointer;
|
||||||
|
unsigned char ConfigsLockValue;
|
||||||
|
|
||||||
|
USB_VOLATILE USB_HANDLE txHandle = 0;
|
||||||
|
USB_VOLATILE USB_HANDLE rxHandle = 0;
|
||||||
|
|
||||||
|
void WriteFlashBlock(void);
|
||||||
|
void WriteConfigBits(void);
|
||||||
|
void WriteEEPROM(void);
|
||||||
|
void UnlockAndActivate(unsigned char UnlockKey);
|
||||||
|
void ResetDeviceCleanly(void);
|
||||||
|
void TableReadPostIncrement(void);
|
||||||
|
void SignFlash(void);
|
||||||
|
void LowVoltageCheck(void);
|
||||||
|
|
||||||
|
void UserInit(void)
|
||||||
|
{
|
||||||
|
//Initialize bootloader state variables
|
||||||
|
BootState = IDLE;
|
||||||
|
ProgrammedPointer = INVALID_ADDRESS;
|
||||||
|
BufferedDataIndex = 0;
|
||||||
|
ConfigsLockValue = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* Function: void ProcessIO(void)
|
||||||
|
*
|
||||||
|
* PreCondition: None
|
||||||
|
*
|
||||||
|
* Input: None
|
||||||
|
*
|
||||||
|
* Output: None
|
||||||
|
*
|
||||||
|
* Side Effects: None
|
||||||
|
*
|
||||||
|
* Overview: This function receives/sends USB packets to/from the USB
|
||||||
|
* host. It also processes any received OUT packets and
|
||||||
|
* is reponsible for generating USB IN packet data.
|
||||||
|
*
|
||||||
|
* Note: None
|
||||||
|
*****************************************************************************/
|
||||||
|
void ProcessIO(void)
|
||||||
|
{
|
||||||
|
static unsigned char i;
|
||||||
|
static ROM uint8_t* pROM;
|
||||||
|
|
||||||
|
//Checks for and processes application related USB packets (assuming the
|
||||||
|
//USB bus is in the CONFIGURED_STATE, which is the only state where
|
||||||
|
//the host is allowed to send application related USB packets to the device.
|
||||||
|
if((USBGetDeviceState() != CONFIGURED_STATE) || (USBIsDeviceSuspended() == 1))
|
||||||
|
{
|
||||||
|
//No point to trying to run the application code until the device has
|
||||||
|
//been configured (finished with enumeration) and is not currently suspended.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check the current bootloader state (if we are currently waiting from a new
|
||||||
|
//command to process from the host, or if we are still processing a previous
|
||||||
|
//command.
|
||||||
|
if(BootState == IDLE)
|
||||||
|
{
|
||||||
|
//We are currently in the IDLE state waiting for a command from the
|
||||||
|
//PC software on the USB host.
|
||||||
|
if(!HIDRxHandleBusy(rxHandle)) //Did we receive a command?
|
||||||
|
{
|
||||||
|
//We received a new command from the host. Copy the OUT packet from
|
||||||
|
//the host into a local buffer for processing.
|
||||||
|
rxHandle = HIDRxPacket(HID_IN_EP, (char *)&PacketFromPC, USB_PACKET_SIZE); //Also re-arms the OUT endpoint to be able to receive the next packet
|
||||||
|
//HIDRxReport((char *)&PacketFromPC, USB_PACKET_SIZE); //Also re-arms the OUT endpoint to be able to receive the next packet
|
||||||
|
BootState = NOT_IDLE; //Set flag letting state machine know it has a command that needs processing.
|
||||||
|
|
||||||
|
//Pre-initialize a response packet buffer (only used for some commands)
|
||||||
|
for(i = 0; i < USB_PACKET_SIZE; i++) //Prepare the next packet we will send to the host, by initializing the entire packet to 0x00.
|
||||||
|
PacketToPC.Contents[i] = 0; //This saves code space, since we don't have to do it independently in the QUERY_DEVICE and GET_DATA cases.
|
||||||
|
}
|
||||||
|
}//if(BootState == IDLE)
|
||||||
|
else //(BootState must be NOT_IDLE)
|
||||||
|
{
|
||||||
|
//Check the latest command we received from the PC app, to determine what
|
||||||
|
//we should be doing.
|
||||||
|
switch(PacketFromPC.Command)
|
||||||
|
{
|
||||||
|
case QUERY_DEVICE:
|
||||||
|
//Make sure the USB IN endpoint buffer is available, then load
|
||||||
|
//up a query response packet to send to the host.
|
||||||
|
if(!HIDTxHandleBusy(txHandle))
|
||||||
|
{
|
||||||
|
//Prepare a response packet, which lets the PC software know about the memory ranges of this device.
|
||||||
|
PacketToPC.Command = QUERY_DEVICE;
|
||||||
|
PacketToPC.PacketDataFieldSize = REQUEST_DATA_BLOCK_SIZE;
|
||||||
|
PacketToPC.BytesPerAddress = BYTES_PER_ADDRESS_PIC18;
|
||||||
|
PacketToPC.Type1 = MEMORY_REGION_PROGRAM_MEM;
|
||||||
|
PacketToPC.Address1 = (unsigned long)PROGRAM_MEM_START_ADDRESS;
|
||||||
|
PacketToPC.Length1 = (unsigned long)(PROGRAM_MEM_STOP_ADDRESS - PROGRAM_MEM_START_ADDRESS); //Size of program memory area
|
||||||
|
PacketToPC.Type2 = MEMORY_REGION_CONFIG;
|
||||||
|
PacketToPC.Address2 = (unsigned long)CONFIG_WORDS_START_ADDRESS;
|
||||||
|
PacketToPC.Length2 = (unsigned long)CONFIG_WORDS_SECTION_LENGTH;
|
||||||
|
PacketToPC.Type3 = MEMORY_REGION_USERID; //Not really program memory (User ID), but may be treated as it it was as far as the host is concerned
|
||||||
|
PacketToPC.Address3 = (unsigned long)USER_ID_ADDRESS;
|
||||||
|
PacketToPC.Length3 = (unsigned long)(USER_ID_SIZE);
|
||||||
|
PacketToPC.Type4 = MEMORY_REGION_END;
|
||||||
|
#if defined(DEVICE_WITH_EEPROM)
|
||||||
|
PacketToPC.Type4 = MEMORY_REGION_EEDATA;
|
||||||
|
PacketToPC.Address4 = (unsigned long)EEPROM_EFFECTIVE_ADDRESS;
|
||||||
|
PacketToPC.Length4 = (unsigned long)EEPROM_SIZE;
|
||||||
|
PacketToPC.Type5 = MEMORY_REGION_END;
|
||||||
|
#endif
|
||||||
|
PacketToPC.VersionFlag = BOOTLOADER_V1_01_OR_NEWER_FLAG;
|
||||||
|
//Init pad bytes to 0x00... Already done after we received the QUERY_DEVICE command (just after calling HIDRxReport()).
|
||||||
|
|
||||||
|
//Now send the packet to the USB host software, assuming the USB endpoint is available/ready to accept new data.
|
||||||
|
txHandle = HIDTxPacket(HID_OUT_EP, (char *)&PacketToPC, USB_PACKET_SIZE);
|
||||||
|
BootState = IDLE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case UNLOCK_CONFIG:
|
||||||
|
ConfigsLockValue = TRUE;
|
||||||
|
if(PacketFromPC.LockValue == UNLOCKCONFIG)
|
||||||
|
{
|
||||||
|
ConfigsLockValue = FALSE;
|
||||||
|
}
|
||||||
|
BootState = IDLE;
|
||||||
|
break;
|
||||||
|
case ERASE_DEVICE:
|
||||||
|
//First erase main program flash memory
|
||||||
|
for(ErasePageTracker = START_PAGE_TO_ERASE; ErasePageTracker < (unsigned int)(MAX_PAGE_TO_ERASE + 1); ErasePageTracker++)
|
||||||
|
{
|
||||||
|
ClearWatchdog();
|
||||||
|
#ifdef __XC8__
|
||||||
|
TBLPTRU = 0x00;
|
||||||
|
TBLPTRH = (uint8_t)((uint24_t)ErasePageTracker >> 2);
|
||||||
|
TBLPTRL = (uint8_t)((uint24_t)ErasePageTracker << 6);
|
||||||
|
#else
|
||||||
|
TBLPTR = ErasePageTracker << 6;
|
||||||
|
#endif
|
||||||
|
EECON1 = 0b10010100; //Prepare for erasing flash memory
|
||||||
|
UnlockAndActivate(CORRECT_UNLOCK_KEY);
|
||||||
|
USBDeviceTasks(); //Call USBDeviceTasks() periodically to prevent falling off the bus if any SETUP packets should happen to arrive.
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(DEVICE_WITH_EEPROM)
|
||||||
|
//Now erase EEPROM (if any is present on the device)
|
||||||
|
i = EEPROM_EFFECTIVE_ADDRESS & (EEPROM_SIZE-1);
|
||||||
|
do{
|
||||||
|
EEADR = i;
|
||||||
|
EEDATA = 0xFF;
|
||||||
|
EECON1 = 0b00000100; //EEPROM Write mode
|
||||||
|
USBDeviceTasks(); //Call USBDeviceTasks() periodically to prevent falling off the bus if any SETUP packets should happen to arrive.
|
||||||
|
UnlockAndActivate(CORRECT_UNLOCK_KEY);
|
||||||
|
}while(i++<((EEPROM_SIZE-1)+(EEPROM_EFFECTIVE_ADDRESS & (EEPROM_SIZE-1))));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//Now erase the User ID space (0x200000 to 0x200007)
|
||||||
|
//TBLPTR = USER_ID_ADDRESS;
|
||||||
|
TBLPTRU = 0x20;
|
||||||
|
TBLPTRH = 0x00;
|
||||||
|
TBLPTRL = (uint8_t)USER_ID_ADDRESS;
|
||||||
|
EECON1 = 0b10010100; //Prepare for erasing flash memory
|
||||||
|
UnlockAndActivate(CORRECT_UNLOCK_KEY);
|
||||||
|
|
||||||
|
BootState = IDLE;
|
||||||
|
break;
|
||||||
|
case PROGRAM_DEVICE:
|
||||||
|
//Check if host is trying to program the config bits
|
||||||
|
if(PacketFromPC.Contents[3] == 0x30) // //PacketFromPC.Contents[3] is bits 23:16 of the address.
|
||||||
|
{ //0x30 implies config bits
|
||||||
|
if(ConfigsLockValue == FALSE)
|
||||||
|
{
|
||||||
|
WriteConfigBits(); //Doesn't get reprogrammed if the UNLOCK_CONFIG (LockValue = UNLOCKCONFIG) command hasn't previously been sent
|
||||||
|
}
|
||||||
|
BootState = IDLE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(DEVICE_WITH_EEPROM)
|
||||||
|
//Check if host is trying to program the EEPROM
|
||||||
|
if(PacketFromPC.Contents[3] == 0xF0) //PacketFromPC.Contents[3] is bits 23:16 of the address.
|
||||||
|
{ //0xF0 implies EEPROM
|
||||||
|
WriteEEPROM();
|
||||||
|
BootState = IDLE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(ProgrammedPointer == (uint24_t)INVALID_ADDRESS)
|
||||||
|
ProgrammedPointer = PacketFromPC.Address;
|
||||||
|
|
||||||
|
if(ProgrammedPointer == (uint24_t)PacketFromPC.Address)
|
||||||
|
{
|
||||||
|
for(i = 0; i < PacketFromPC.Size; i++)
|
||||||
|
{
|
||||||
|
ProgrammingBuffer[BufferedDataIndex] = PacketFromPC.Data[i+(REQUEST_DATA_BLOCK_SIZE-PacketFromPC.Size)]; //Data field is right justified. Need to put it in the buffer left justified.
|
||||||
|
BufferedDataIndex++;
|
||||||
|
ProgrammedPointer++;
|
||||||
|
if(BufferedDataIndex == WRITE_BLOCK_SIZE)
|
||||||
|
{
|
||||||
|
WriteFlashBlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//else host sent us a non-contiguous packet address... to make
|
||||||
|
//this firmware simpler, host should not do this without sending
|
||||||
|
//a PROGRAM_COMPLETE command in between program sections.
|
||||||
|
BootState = IDLE;
|
||||||
|
break;
|
||||||
|
case PROGRAM_COMPLETE:
|
||||||
|
WriteFlashBlock();
|
||||||
|
ProgrammedPointer = INVALID_ADDRESS; //Reinitialize pointer to an invalid range, so we know the next PROGRAM_DEVICE will be the start address of a contiguous section.
|
||||||
|
BootState = IDLE;
|
||||||
|
break;
|
||||||
|
case GET_DATA:
|
||||||
|
//Init pad bytes to 0x00... Already done after we received the QUERY_DEVICE command (just after calling HIDRxReport()).
|
||||||
|
PacketToPC.Command = GET_DATA;
|
||||||
|
PacketToPC.Address = PacketFromPC.Address;
|
||||||
|
PacketToPC.Size = PacketFromPC.Size;
|
||||||
|
|
||||||
|
pROM = (ROM uint8_t*)PacketFromPC.Address;
|
||||||
|
for(i = 0; i < PacketFromPC.Size; i++)
|
||||||
|
{
|
||||||
|
if(PacketFromPC.Contents[3] == 0xF0) //PacketFromPC.Contents[3] is bits 23:16 of the address.
|
||||||
|
{ //0xF0 implies EEPROM, which doesn't use the table pointer to read from
|
||||||
|
#if defined(DEVICE_WITH_EEPROM)
|
||||||
|
EEADR = (((unsigned char)PacketFromPC.Address) + i); //The bits 7:0 are 1:1 mapped to the EEPROM address space values
|
||||||
|
EECON1 = 0b00000000; //EEPROM read mode
|
||||||
|
EECON1bits.RD = 1;
|
||||||
|
PacketToPC.Data[i+((USB_PACKET_SIZE - 6) - PacketFromPC.Size)] = EEDATA;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else //else must have been a normal program memory region, or one that can be read from with the table pointer
|
||||||
|
{
|
||||||
|
PacketToPC.Data[i+((USB_PACKET_SIZE - 6) - PacketFromPC.Size)] = *pROM++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Assuming the USB IN (to host) buffer is available/ready, copy the
|
||||||
|
//data over so it can get sent to the USB host software.
|
||||||
|
if(!HIDTxHandleBusy(txHandle))
|
||||||
|
{
|
||||||
|
HIDTxPacket(HID_OUT_EP, (char *)&PacketToPC, USB_PACKET_SIZE);
|
||||||
|
BootState = IDLE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SIGN_FLASH:
|
||||||
|
SignFlash();
|
||||||
|
BootState = IDLE;
|
||||||
|
break;
|
||||||
|
case QUERY_EXTENDED_INFO:
|
||||||
|
//Prepare a response packet with the QUERY_EXTENDED_INFO response info in it.
|
||||||
|
//This command is only supported in bootloader firmware verison 1.01 or later.
|
||||||
|
//Make sure the regular QUERY_DEVIER reponse packet value "PacketToPC.Type6" is = BOOTLOADER_V1_01_OR_NEWER_FLAG;
|
||||||
|
//to let the host PC software know that the QUERY_EXTENDED_INFO command is implemented
|
||||||
|
//in this firmware and is available for requesting by the host software.
|
||||||
|
PacketToPC.Command = QUERY_EXTENDED_INFO; //Echo the command byte
|
||||||
|
PacketToPC.BootloaderVersion = ((unsigned int)BOOTLOADER_VERSION_MAJOR << 8)| BOOTLOADER_VERSION_MINOR;
|
||||||
|
PacketToPC.ApplicationVersion = *(ROM unsigned int*)APP_VERSION_ADDRESS;
|
||||||
|
PacketToPC.SignatureAddress = APP_SIGNATURE_ADDRESS;
|
||||||
|
PacketToPC.SignatureValue = APP_SIGNATURE_VALUE;
|
||||||
|
PacketToPC.ErasePageSize = ERASE_PAGE_SIZE;
|
||||||
|
PacketToPC.Config1LMask = 0xFF;
|
||||||
|
PacketToPC.Config1HMask = 0xFF;
|
||||||
|
PacketToPC.Config2LMask = 0xFF;
|
||||||
|
PacketToPC.Config2HMask = 0xFF;
|
||||||
|
PacketToPC.Config3LMask = 0x00;
|
||||||
|
PacketToPC.Config3HMask = 0xFF;
|
||||||
|
PacketToPC.Config4LMask = 0xFF;
|
||||||
|
PacketToPC.Config4HMask = 0x00;
|
||||||
|
PacketToPC.Config5LMask = 0xFF;
|
||||||
|
PacketToPC.Config5HMask = 0xFF;
|
||||||
|
PacketToPC.Config6LMask = 0xFF;
|
||||||
|
PacketToPC.Config6HMask = 0xFF;
|
||||||
|
PacketToPC.Config7LMask = 0xFF;
|
||||||
|
PacketToPC.Config7HMask = 0xFF;
|
||||||
|
|
||||||
|
//Now actually command USB to send the packet to the host
|
||||||
|
if(!HIDTxHandleBusy(txHandle))
|
||||||
|
{
|
||||||
|
HIDTxPacket(HID_OUT_EP, (char *)&PacketToPC, USB_PACKET_SIZE);
|
||||||
|
BootState = IDLE; //Packet will be sent, go back to idle state ready for next command from host
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RESET_DEVICE:
|
||||||
|
ResetDeviceCleanly();
|
||||||
|
//break; //no need, commented to save space
|
||||||
|
default:
|
||||||
|
//Should never hit the default
|
||||||
|
BootState = IDLE;
|
||||||
|
}//End switch
|
||||||
|
}//End of else of if(BootState == IDLE)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//Should be called once, only after the regular erase/program/verify sequence
|
||||||
|
//has completed successfully. This function will program the magic
|
||||||
|
//APP_SIGNATURE_VALUE into the magic APP_SIGNATURE_ADDRESS in the application
|
||||||
|
//flash memory space. This is used on the next bootup to know that the the
|
||||||
|
//flash memory image of the application is intact, and can be executed.
|
||||||
|
//This is useful for recovery purposes, in the event that an unexpected
|
||||||
|
//failure occurs during the erase/program sequence (ex: power loss or user
|
||||||
|
//unplugging the USB cable).
|
||||||
|
void SignFlash(void)
|
||||||
|
{
|
||||||
|
static unsigned char i;
|
||||||
|
static ROM uint8_t* pROM;
|
||||||
|
|
||||||
|
//First read in the erase page contents of the page with the signature WORD
|
||||||
|
//in it, and temporarily store it in a RAM buffer.
|
||||||
|
pROM = (ROM uint8_t*)(APP_SIGNATURE_ADDRESS & ERASE_PAGE_ADDRESS_MASK);
|
||||||
|
for(i = 0; i < ERASE_PAGE_SIZE; i++)
|
||||||
|
{
|
||||||
|
ProgrammingBuffer[i] = *pROM++;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Now change the signature WORD value at the correct address in the RAM buffer
|
||||||
|
ProgrammingBuffer[(APP_SIGNATURE_ADDRESS & ~ERASE_PAGE_ADDRESS_MASK)] = (unsigned char)APP_SIGNATURE_VALUE;
|
||||||
|
ProgrammingBuffer[(APP_SIGNATURE_ADDRESS & ~ERASE_PAGE_ADDRESS_MASK) + 1] = (unsigned char)(APP_SIGNATURE_VALUE >> 8);
|
||||||
|
|
||||||
|
//Now erase the flash memory block with the signature WORD in it
|
||||||
|
//TBLPTR = APP_SIGNATURE_ADDRESS & ERASE_PAGE_ADDRESS_MASK;
|
||||||
|
TBLPTRU = (uint8_t)((APP_SIGNATURE_ADDRESS & ERASE_PAGE_ADDRESS_MASK) >> 16);
|
||||||
|
TBLPTRH = (uint8_t)((APP_SIGNATURE_ADDRESS & ERASE_PAGE_ADDRESS_MASK) >> 8);
|
||||||
|
TBLPTRL = (uint8_t)(APP_SIGNATURE_ADDRESS & ERASE_PAGE_ADDRESS_MASK);
|
||||||
|
|
||||||
|
EECON1 = 0x94; //Prepare for flash erase operation
|
||||||
|
UnlockAndActivate(CORRECT_UNLOCK_KEY);
|
||||||
|
|
||||||
|
//Now re-program the values from the RAM buffer into the flash memory. Use
|
||||||
|
//reverse order, so we program the larger addresses first. This way, the
|
||||||
|
//write page with the flash signature word is the last page that gets
|
||||||
|
//programmed (assuming the flash signature resides on the lowest address
|
||||||
|
//write page, which is recommended, so that it becomes the first page
|
||||||
|
//erased, and the last page programmed).
|
||||||
|
pROM = (ROM uint8_t*)((APP_SIGNATURE_ADDRESS & ERASE_PAGE_ADDRESS_MASK) + ERASE_PAGE_SIZE - 1); //Point to last byte on the erase page
|
||||||
|
//TBLPTR = (APP_SIGNATURE_ADDRESS & ERASE_PAGE_ADDRESS_MASK) + ERASE_PAGE_SIZE - 1; //Point to last byte on the erase page
|
||||||
|
i = ERASE_PAGE_SIZE - 1;
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
#ifdef __XC8__
|
||||||
|
TBLPTRU = (uint32_t)pROM >> 16;
|
||||||
|
TBLPTRH = (uint16_t)pROM >> 8;
|
||||||
|
TBLPTRL = (uint8_t)pROM;
|
||||||
|
#else
|
||||||
|
TBLPTR = (uint24_t)pROM;
|
||||||
|
#endif
|
||||||
|
TABLAT = ProgrammingBuffer[i];
|
||||||
|
|
||||||
|
#ifdef __XC8__
|
||||||
|
#asm
|
||||||
|
tblwt
|
||||||
|
#endasm
|
||||||
|
#else //must be C18 instead
|
||||||
|
_asm tblwt _endasm
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//Check if we are at a program write block size boundary
|
||||||
|
if((i % WRITE_BLOCK_SIZE) == 0)
|
||||||
|
{
|
||||||
|
//The write latches are full, time to program the block.
|
||||||
|
ClearWatchdog();
|
||||||
|
EECON1 = 0xA4; //Write to flash on next WR = 1 operation
|
||||||
|
UnlockAndActivate(CORRECT_UNLOCK_KEY);
|
||||||
|
}
|
||||||
|
//Move ROM pointer back to next location
|
||||||
|
pROM--;
|
||||||
|
#ifdef __XC8__
|
||||||
|
#asm
|
||||||
|
tblrdpostdec
|
||||||
|
#endasm
|
||||||
|
#else //must be C18 instead
|
||||||
|
_asm tblrdpostdec _endasm
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//Check if we are done writing all blocks
|
||||||
|
if(i == 0)
|
||||||
|
{
|
||||||
|
break; //Exit while loop
|
||||||
|
}
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Before resetting the microcontroller, we should shut down the USB module
|
||||||
|
//gracefully, to make sure the host correctly recognizes that we detached
|
||||||
|
//from the bus. Some USB hosts malfunction/fail to re-enumerate the device
|
||||||
|
//correctly if the USB device does not stay detached for a minimum amount of
|
||||||
|
//time before re-attaching to the USB bus. For reliable operation, the USB
|
||||||
|
//device should stay detached for as long as a human would require to unplug and
|
||||||
|
//reattach a USB device (ex: 100ms+), to ensure the USB host software has a
|
||||||
|
//chance to process the detach event and configure itself for a state ready for
|
||||||
|
//a new attachment event.
|
||||||
|
void ResetDeviceCleanly(void)
|
||||||
|
{
|
||||||
|
//USBDisableWithLongDelay();
|
||||||
|
Reset();
|
||||||
|
Nop();
|
||||||
|
Nop();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Routine used to write data to the flash memory from the ProgrammingBuffer[].
|
||||||
|
void WriteFlashBlock(void) //Use to write blocks of data to flash.
|
||||||
|
{
|
||||||
|
static unsigned char i;
|
||||||
|
static unsigned char BytesTakenFromBuffer;
|
||||||
|
static unsigned char CorrectionFactor;
|
||||||
|
|
||||||
|
#ifdef __XC8__
|
||||||
|
static ROM uint8_t* pROM;
|
||||||
|
|
||||||
|
pROM = (ROM uint8_t*)(ProgrammedPointer - BufferedDataIndex);
|
||||||
|
TBLPTRU = 0x00;
|
||||||
|
TBLPTRH = (uint8_t)((uint16_t)pROM >> 8);
|
||||||
|
TBLPTRL = (uint8_t)pROM;
|
||||||
|
#else
|
||||||
|
TBLPTR = (ProgrammedPointer - BufferedDataIndex);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BytesTakenFromBuffer = 0;
|
||||||
|
|
||||||
|
//Check the lower 5 bits of the TBLPTR to verify it is pointing to a 32 byte aligned block (5 LSb = 00000).
|
||||||
|
//If it isn't, need to somehow make it so before doing the actual loading of the programming latches.
|
||||||
|
//In order to maximize programming speed, the PC application meant to be used with this firmware will not send
|
||||||
|
//large blocks of 0xFF bytes. If the PC application
|
||||||
|
//detects a large block of unprogrammed space in the hex file (effectively = 0xFF), it will skip over that
|
||||||
|
//section and will not send it to the firmware. This works, because the firmware will have already done an
|
||||||
|
//erase on that section of memory when it received the ERASE_DEVICE command from the PC. Therefore, the section
|
||||||
|
//can be left unprogrammed (after an erase the flash ends up = 0xFF).
|
||||||
|
//This can result in a problem however, in that the next genuine non-0xFF section in the hex file may not start
|
||||||
|
//on a 32 byte aligned block boundary. This needs to be handled with care since the microcontroller can only
|
||||||
|
//program 32 byte blocks that are aligned with 32 byte boundaries.
|
||||||
|
//So, use the below code to avoid this potential issue.
|
||||||
|
|
||||||
|
#if(WRITE_BLOCK_SIZE == 0x20)
|
||||||
|
CorrectionFactor = (TBLPTRL & 0b00011111); //Correctionfactor = number of bytes tblptr must go back to find the immediate preceeding 32 byte boundary
|
||||||
|
TBLPTRL &= 0b11100000; //Move the table pointer back to the immediately preceeding 32 byte boundary
|
||||||
|
#elif(WRITE_BLOCK_SIZE == 0x10)
|
||||||
|
CorrectionFactor = (TBLPTRL & 0b00001111); //Correctionfactor = number of bytes tblptr must go back to find the immediate preceeding 16 byte boundary
|
||||||
|
TBLPTRL &= 0b11110000; //Move the table pointer back to the immediately preceeding 16 byte boundary
|
||||||
|
#elif(WRITE_BLOCK_SIZE == 0x8)
|
||||||
|
CorrectionFactor = (TBLPTRL & 0b00000111); //Correctionfactor = number of bytes tblptr must go back to find the immediate preceeding 16 byte boundary
|
||||||
|
TBLPTRL &= 0b11111000; //Move the table pointer back to the immediately preceeding 16 byte boundary
|
||||||
|
#else
|
||||||
|
#warning "Double click this error message and fix this section for your microcontroller type."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for(i = 0; i < WRITE_BLOCK_SIZE; i++) //Load the programming latches
|
||||||
|
{
|
||||||
|
if(CorrectionFactor == 0)
|
||||||
|
{
|
||||||
|
if(BufferedDataIndex != 0) //If the buffer isn't empty
|
||||||
|
{
|
||||||
|
TABLAT = ProgrammingBuffer[BytesTakenFromBuffer];
|
||||||
|
#ifdef __XC8__
|
||||||
|
#asm
|
||||||
|
tblwtpostinc
|
||||||
|
#endasm
|
||||||
|
#else //must be C18 instead
|
||||||
|
_asm tblwtpostinc _endasm
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BytesTakenFromBuffer++;
|
||||||
|
BufferedDataIndex--; //Used up a byte from the buffer.
|
||||||
|
}
|
||||||
|
else //No more data in buffer, need to write 0xFF to fill the rest of the programming latch locations
|
||||||
|
{
|
||||||
|
TABLAT = 0xFF;
|
||||||
|
#ifdef __XC8__
|
||||||
|
#asm
|
||||||
|
tblwtpostinc
|
||||||
|
#endasm
|
||||||
|
#else //must be C18 instead
|
||||||
|
_asm tblwtpostinc _endasm
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TABLAT = 0xFF;
|
||||||
|
#ifdef __XC8__
|
||||||
|
#asm
|
||||||
|
tblwtpostinc
|
||||||
|
#endasm
|
||||||
|
#else //must be C18 instead
|
||||||
|
_asm tblwtpostinc _endasm
|
||||||
|
#endif
|
||||||
|
CorrectionFactor--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TBLPTR--; //Need to make table pointer point to the region which will be programmed before initiating the programming operation
|
||||||
|
#ifdef __XC8__
|
||||||
|
#asm
|
||||||
|
tblrdpostdec
|
||||||
|
#endasm
|
||||||
|
#else //must be C18 instead
|
||||||
|
_asm tblrdpostdec _endasm //Do this instead of TBLPTR--; since it takes less code space.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
EECON1 = 0b10100100; //flash programming mode
|
||||||
|
UnlockAndActivate(CORRECT_UNLOCK_KEY);
|
||||||
|
|
||||||
|
//Now need to fix the ProgrammingBuffer[]. We may not have taken a full 32 bytes out of the buffer. In this case,
|
||||||
|
//the data is no longer justified correctly.
|
||||||
|
for(i = 0; i < BufferedDataIndex; i++) //Need to rejustify the remaining data to the "left" of the buffer (if there is any left)
|
||||||
|
{
|
||||||
|
ProgrammingBuffer[i] = ProgrammingBuffer[BytesTakenFromBuffer+i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void WriteConfigBits(void) //Also used to write the Device ID
|
||||||
|
{
|
||||||
|
static unsigned char i;
|
||||||
|
|
||||||
|
#ifdef __XC8__
|
||||||
|
TBLPTRU = 0x30;
|
||||||
|
TBLPTRH = (uint8_t)((uint16_t)PacketFromPC.Address >> 8);
|
||||||
|
TBLPTRH = (uint8_t)(PacketFromPC.Address);
|
||||||
|
#else
|
||||||
|
TBLPTR = (uint24_t)PacketFromPC.Address;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for(i = 0; i < PacketFromPC.Size; i++)
|
||||||
|
{
|
||||||
|
TABLAT = PacketFromPC.Data[i+(REQUEST_DATA_BLOCK_SIZE-PacketFromPC.Size)];
|
||||||
|
#ifdef __XC8__
|
||||||
|
#asm
|
||||||
|
tblwt
|
||||||
|
#endasm
|
||||||
|
#else //must be C18 instead
|
||||||
|
_asm tblwt _endasm
|
||||||
|
#endif
|
||||||
|
|
||||||
|
EECON1 = 0b11000100; //Config bits programming mode
|
||||||
|
UnlockAndActivate(CORRECT_UNLOCK_KEY);
|
||||||
|
|
||||||
|
#ifdef __XC8__
|
||||||
|
#asm
|
||||||
|
tblrdpostinc
|
||||||
|
#endasm
|
||||||
|
#else //must be C18 instead
|
||||||
|
_asm tblrdpostinc _endasm
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(DEVICE_WITH_EEPROM)
|
||||||
|
void WriteEEPROM(void)
|
||||||
|
{
|
||||||
|
static unsigned char i;
|
||||||
|
|
||||||
|
for(i = 0; i < PacketFromPC.Size; i++)
|
||||||
|
{
|
||||||
|
EEADR = (((unsigned char)PacketFromPC.Address) + i);
|
||||||
|
EEDATA = PacketFromPC.Data[i+(REQUEST_DATA_BLOCK_SIZE-PacketFromPC.Size)];
|
||||||
|
|
||||||
|
EECON1 = 0b00000100; //EEPROM Write mode
|
||||||
|
UnlockAndActivate(CORRECT_UNLOCK_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//It is preferrable to only place this sequence in only one place in the flash memory.
|
||||||
|
//This reduces the probabilty of the code getting executed inadvertently by
|
||||||
|
//errant code. It is also recommended to enable BOR (in hardware) and/or add
|
||||||
|
//software checks to avoid microcontroller "overclocking". Always make sure
|
||||||
|
//to obey the voltage versus frequency graph in the datasheet, even during
|
||||||
|
//momentary events (such as the power up and power down ramp of the microcontroller).
|
||||||
|
void UnlockAndActivate(unsigned char UnlockKey)
|
||||||
|
{
|
||||||
|
INTCONbits.GIE = 0; //Make certain interrupts disabled for unlock process.
|
||||||
|
|
||||||
|
//Check to make sure the caller really was trying to call this function.
|
||||||
|
//If they were, they should always pass us the CORRECT_UNLOCK_KEY.
|
||||||
|
if(UnlockKey != CORRECT_UNLOCK_KEY)
|
||||||
|
{
|
||||||
|
//Warning! Errant code execution detected. Somehow this
|
||||||
|
//UnlockAndActivate() function got called by someone that wasn't trying
|
||||||
|
//to actually perform an NVM erase or write. This could happen due to
|
||||||
|
//microcontroller overclocking (or undervolting for an otherwise allowed
|
||||||
|
//CPU frequency), or due to buggy code (ex: incorrect use of function
|
||||||
|
//pointers, etc.). In either case, we should execute some fail safe
|
||||||
|
//code here to prevent corruption of the NVM contents.
|
||||||
|
OSCCON = 0x03; //Switch to INTOSC at low frequency
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
Sleep();
|
||||||
|
}
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __XC8__
|
||||||
|
EECON2 = 0x55;
|
||||||
|
EECON2 = 0xAA;
|
||||||
|
EECON1bits.WR = 1;
|
||||||
|
#else
|
||||||
|
_asm
|
||||||
|
//Now unlock sequence to set WR (make sure interrupts are disabled before executing this)
|
||||||
|
MOVLW 0x55
|
||||||
|
MOVWF EECON2, 0
|
||||||
|
MOVLW 0xAA
|
||||||
|
MOVWF EECON2, 0
|
||||||
|
BSF EECON1, 1, 0 //Performs write by setting WR bit
|
||||||
|
_endasm
|
||||||
|
#endif
|
||||||
|
|
||||||
|
while(EECON1bits.WR); //Wait until complete (relevant when programming EEPROM, not important when programming flash since processor stalls during flash program)
|
||||||
|
EECON1bits.WREN = 0; //Good practice now to clear the WREN bit, as further protection against any accidental activation of self write/erase operations.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Note: The ClrWdt() and "_asm tblrdpostinc _endasm" are inline assembly language
|
||||||
|
//instructions. The ClearWatchdog() and TableReadPostIncrement() functions are
|
||||||
|
//theoretically extraneous, since the operations being accomplished could be
|
||||||
|
//done without calling them as separate functions. However, when using inline
|
||||||
|
//assembly language, the C18 compiler normally doesn't know what the code will
|
||||||
|
//actually do (ex: will it modify STATUS reg, WREG, BSR contents??). As a
|
||||||
|
//result, it is potentially dangerous for the C compiler to make assumptions,
|
||||||
|
//that might turn out not to be correct. Therefore, the C18 compiler disables
|
||||||
|
//the compiler optimizations for a function, when one or more inline asm
|
||||||
|
//instructions are located within the C function. Therefore, to promote best
|
||||||
|
//code size optimizations from the C18 compiler, it is best to locate inline
|
||||||
|
//assembly sequences in their own separate C functions, that do not contain much
|
||||||
|
//other code (which could otherwise be optimized by the C compiler). This often
|
||||||
|
//results in the smallest code size, and is the reason it is being done here.
|
||||||
|
void TableReadPostIncrement(void)
|
||||||
|
{
|
||||||
|
#ifdef __XC8__
|
||||||
|
#asm
|
||||||
|
tblrdpostinc
|
||||||
|
#endasm
|
||||||
|
#else //must be C18 instead
|
||||||
|
_asm tblrdpostinc _endasm
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
47
bootloader/src/bootloader.h
Normal file
47
bootloader/src/bootloader.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/*************************************************************************
|
||||||
|
* Copyright (C) 2019 by Justin Byers
|
||||||
|
*
|
||||||
|
* This file is part of clubdance_v2.
|
||||||
|
*
|
||||||
|
* clubdance_v2 is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* clubdance_v2 is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with clubdance_v2. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file bootloader.h
|
||||||
|
* @author Justin Byers
|
||||||
|
* @date August 11, 2019
|
||||||
|
* @brief
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef BOOTLOADER_
|
||||||
|
#define BOOTLOADER_
|
||||||
|
|
||||||
|
void UserInit(void);
|
||||||
|
void ProcessIO(void);
|
||||||
|
void ClearWatchdog(void);
|
||||||
|
void DisableUSBandExecuteLongDelay(void);
|
||||||
|
|
||||||
|
|
||||||
|
//Vector remapping/absolute address constants
|
||||||
|
#define REMAPPED_APPLICATION_RESET_VECTOR 0x1400
|
||||||
|
//#define REMAPPED_APPLICATION_HIGH_ISR_VECTOR 0x1408 //See VectorRemap.asm
|
||||||
|
//#define REMAPPED_APPLICATION_LOW_ISR_VECTOR 0x1418 //See VectorRemap.asm
|
||||||
|
#define BOOTLOADER_ABSOLUTE_ENTRY_ADDRESS 0x001C //Execute a "goto 0x001C" inline assembly instruction, if you want to enter the bootloader mode from the application via software
|
||||||
|
|
||||||
|
#define APP_SIGNATURE_ADDRESS 0x1406 //0x1006 and 0x1007 contains the "signature" WORD, indicating successful erase/program/verify operation
|
||||||
|
#define APP_SIGNATURE_VALUE 0x600D //leet "GOOD", implying that the erase/program was a success and the bootloader intentionally programmed the APP_SIGNATURE_ADDRESS with this value
|
||||||
|
#define APP_VERSION_ADDRESS 0x1416 //0x1016 and 0x1017 should contain the application image firmware version number
|
||||||
|
|
||||||
|
#endif /* BOOTLOADER_ */
|
||||||
|
|
||||||
@@ -7,8 +7,11 @@
|
|||||||
|
|
||||||
#include <xc.h>
|
#include <xc.h>
|
||||||
#include "usb.h"
|
#include "usb.h"
|
||||||
|
#include "bootloader.h"
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
|
UserInit();
|
||||||
|
|
||||||
// initialize the USB framework
|
// initialize the USB framework
|
||||||
USBDeviceInit();
|
USBDeviceInit();
|
||||||
USBDeviceAttach();
|
USBDeviceAttach();
|
||||||
@@ -22,6 +25,6 @@ void main(void) {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
// run application specific tasks
|
// run application specific tasks
|
||||||
//DANCEPAD_Tasks();
|
ProcessIO();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
426
bootloader/src/typedefs.h
Normal file
426
bootloader/src/typedefs.h
Normal file
@@ -0,0 +1,426 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
Copyright 2016 Microchip Technology Inc. (www.microchip.com)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
To request to license the code under the MLA license (www.microchip.com/mla_license),
|
||||||
|
please contact mla_licensing@microchip.com
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __CUSTOMIZED_TYPE_DEFS_H_
|
||||||
|
#define __CUSTOMIZED_TYPE_DEFS_H_
|
||||||
|
|
||||||
|
#include <xc.h>
|
||||||
|
#define ROM const
|
||||||
|
#define rom
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#ifndef Nop()
|
||||||
|
#define Nop() {asm("NOP");}
|
||||||
|
#endif
|
||||||
|
#ifndef ClrWdt()
|
||||||
|
#define ClrWdt() {asm("CLRWDT");}
|
||||||
|
#endif
|
||||||
|
#ifndef Reset()
|
||||||
|
#define Reset() {asm("RESET");}
|
||||||
|
#endif
|
||||||
|
#ifndef Sleep()
|
||||||
|
#define Sleep() {asm("SLEEP");}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define __EXTENSION
|
||||||
|
|
||||||
|
#if !defined(__PACKED)
|
||||||
|
#define __PACKED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* get compiler defined type definitions (NULL, size_t, etc) */
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifndef TRUE
|
||||||
|
#define TRUE 1
|
||||||
|
#endif
|
||||||
|
#ifndef FALSE
|
||||||
|
#define FALSE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PUBLIC /* Function attributes */
|
||||||
|
#define PROTECTED
|
||||||
|
#define PRIVATE static
|
||||||
|
|
||||||
|
/* INT is processor specific in length may vary in size */
|
||||||
|
typedef signed int INT;
|
||||||
|
typedef signed char INT8;
|
||||||
|
typedef signed short int INT16;
|
||||||
|
typedef signed long int INT32;
|
||||||
|
|
||||||
|
/* UINT is processor specific in length may vary in size */
|
||||||
|
typedef unsigned int UINT;
|
||||||
|
typedef unsigned char UINT8;
|
||||||
|
typedef unsigned short int UINT16;
|
||||||
|
typedef unsigned long int UINT32; /* other name for 32-bit integer */
|
||||||
|
|
||||||
|
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
UINT8 Val;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
__EXTENSION UINT8 b0:1;
|
||||||
|
__EXTENSION UINT8 b1:1;
|
||||||
|
__EXTENSION UINT8 b2:1;
|
||||||
|
__EXTENSION UINT8 b3:1;
|
||||||
|
__EXTENSION UINT8 b4:1;
|
||||||
|
__EXTENSION UINT8 b5:1;
|
||||||
|
__EXTENSION UINT8 b6:1;
|
||||||
|
__EXTENSION UINT8 b7:1;
|
||||||
|
} bits;
|
||||||
|
} UINT8_VAL, UINT8_BITS;
|
||||||
|
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
UINT16 Val;
|
||||||
|
UINT8 v[2] __PACKED;
|
||||||
|
struct __PACKED
|
||||||
|
{
|
||||||
|
UINT8 LB;
|
||||||
|
UINT8 HB;
|
||||||
|
} byte;
|
||||||
|
struct __PACKED
|
||||||
|
{
|
||||||
|
__EXTENSION UINT8 b0:1;
|
||||||
|
__EXTENSION UINT8 b1:1;
|
||||||
|
__EXTENSION UINT8 b2:1;
|
||||||
|
__EXTENSION UINT8 b3:1;
|
||||||
|
__EXTENSION UINT8 b4:1;
|
||||||
|
__EXTENSION UINT8 b5:1;
|
||||||
|
__EXTENSION UINT8 b6:1;
|
||||||
|
__EXTENSION UINT8 b7:1;
|
||||||
|
__EXTENSION UINT8 b8:1;
|
||||||
|
__EXTENSION UINT8 b9:1;
|
||||||
|
__EXTENSION UINT8 b10:1;
|
||||||
|
__EXTENSION UINT8 b11:1;
|
||||||
|
__EXTENSION UINT8 b12:1;
|
||||||
|
__EXTENSION UINT8 b13:1;
|
||||||
|
__EXTENSION UINT8 b14:1;
|
||||||
|
__EXTENSION UINT8 b15:1;
|
||||||
|
} bits;
|
||||||
|
} UINT16_VAL, UINT16_BITS;
|
||||||
|
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
UINT32 Val;
|
||||||
|
UINT16 w[2] __PACKED;
|
||||||
|
UINT8 v[4] __PACKED;
|
||||||
|
struct __PACKED
|
||||||
|
{
|
||||||
|
UINT16 LW;
|
||||||
|
UINT16 HW;
|
||||||
|
} word;
|
||||||
|
struct __PACKED
|
||||||
|
{
|
||||||
|
UINT8 LB;
|
||||||
|
UINT8 HB;
|
||||||
|
UINT8 UB;
|
||||||
|
UINT8 MB;
|
||||||
|
} byte;
|
||||||
|
struct __PACKED
|
||||||
|
{
|
||||||
|
UINT16_VAL low;
|
||||||
|
UINT16_VAL high;
|
||||||
|
}wordUnion;
|
||||||
|
struct __PACKED
|
||||||
|
{
|
||||||
|
__EXTENSION UINT8 b0:1;
|
||||||
|
__EXTENSION UINT8 b1:1;
|
||||||
|
__EXTENSION UINT8 b2:1;
|
||||||
|
__EXTENSION UINT8 b3:1;
|
||||||
|
__EXTENSION UINT8 b4:1;
|
||||||
|
__EXTENSION UINT8 b5:1;
|
||||||
|
__EXTENSION UINT8 b6:1;
|
||||||
|
__EXTENSION UINT8 b7:1;
|
||||||
|
__EXTENSION UINT8 b8:1;
|
||||||
|
__EXTENSION UINT8 b9:1;
|
||||||
|
__EXTENSION UINT8 b10:1;
|
||||||
|
__EXTENSION UINT8 b11:1;
|
||||||
|
__EXTENSION UINT8 b12:1;
|
||||||
|
__EXTENSION UINT8 b13:1;
|
||||||
|
__EXTENSION UINT8 b14:1;
|
||||||
|
__EXTENSION UINT8 b15:1;
|
||||||
|
__EXTENSION UINT8 b16:1;
|
||||||
|
__EXTENSION UINT8 b17:1;
|
||||||
|
__EXTENSION UINT8 b18:1;
|
||||||
|
__EXTENSION UINT8 b19:1;
|
||||||
|
__EXTENSION UINT8 b20:1;
|
||||||
|
__EXTENSION UINT8 b21:1;
|
||||||
|
__EXTENSION UINT8 b22:1;
|
||||||
|
__EXTENSION UINT8 b23:1;
|
||||||
|
__EXTENSION UINT8 b24:1;
|
||||||
|
__EXTENSION UINT8 b25:1;
|
||||||
|
__EXTENSION UINT8 b26:1;
|
||||||
|
__EXTENSION UINT8 b27:1;
|
||||||
|
__EXTENSION UINT8 b28:1;
|
||||||
|
__EXTENSION UINT8 b29:1;
|
||||||
|
__EXTENSION UINT8 b30:1;
|
||||||
|
__EXTENSION UINT8 b31:1;
|
||||||
|
} bits;
|
||||||
|
} UINT32_VAL;
|
||||||
|
|
||||||
|
/***********************************************************************************/
|
||||||
|
|
||||||
|
/* Alternate definitions */
|
||||||
|
typedef void VOID;
|
||||||
|
|
||||||
|
typedef char CHAR8;
|
||||||
|
typedef unsigned char UCHAR8;
|
||||||
|
|
||||||
|
typedef unsigned char BYTE; /* 8-bit unsigned */
|
||||||
|
typedef unsigned short int WORD; /* 16-bit unsigned */
|
||||||
|
typedef unsigned long DWORD; /* 32-bit unsigned */
|
||||||
|
//typedef unsigned long long QWORD; /* 64-bit unsigned */
|
||||||
|
typedef signed char CHAR; /* 8-bit signed */
|
||||||
|
typedef signed short int SHORT; /* 16-bit signed */
|
||||||
|
typedef signed long LONG; /* 32-bit signed */
|
||||||
|
//typedef signed long long LONGLONG; /* 64-bit signed */
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
BYTE Val;
|
||||||
|
struct __PACKED
|
||||||
|
{
|
||||||
|
__EXTENSION BYTE b0:1;
|
||||||
|
__EXTENSION BYTE b1:1;
|
||||||
|
__EXTENSION BYTE b2:1;
|
||||||
|
__EXTENSION BYTE b3:1;
|
||||||
|
__EXTENSION BYTE b4:1;
|
||||||
|
__EXTENSION BYTE b5:1;
|
||||||
|
__EXTENSION BYTE b6:1;
|
||||||
|
__EXTENSION BYTE b7:1;
|
||||||
|
} bits;
|
||||||
|
} BYTE_VAL, BYTE_BITS;
|
||||||
|
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
WORD Val;
|
||||||
|
BYTE v[2] __PACKED;
|
||||||
|
struct __PACKED
|
||||||
|
{
|
||||||
|
BYTE LB;
|
||||||
|
BYTE HB;
|
||||||
|
} byte;
|
||||||
|
struct __PACKED
|
||||||
|
{
|
||||||
|
__EXTENSION BYTE b0:1;
|
||||||
|
__EXTENSION BYTE b1:1;
|
||||||
|
__EXTENSION BYTE b2:1;
|
||||||
|
__EXTENSION BYTE b3:1;
|
||||||
|
__EXTENSION BYTE b4:1;
|
||||||
|
__EXTENSION BYTE b5:1;
|
||||||
|
__EXTENSION BYTE b6:1;
|
||||||
|
__EXTENSION BYTE b7:1;
|
||||||
|
__EXTENSION BYTE b8:1;
|
||||||
|
__EXTENSION BYTE b9:1;
|
||||||
|
__EXTENSION BYTE b10:1;
|
||||||
|
__EXTENSION BYTE b11:1;
|
||||||
|
__EXTENSION BYTE b12:1;
|
||||||
|
__EXTENSION BYTE b13:1;
|
||||||
|
__EXTENSION BYTE b14:1;
|
||||||
|
__EXTENSION BYTE b15:1;
|
||||||
|
} bits;
|
||||||
|
} WORD_VAL, WORD_BITS;
|
||||||
|
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
DWORD Val;
|
||||||
|
WORD w[2] __PACKED;
|
||||||
|
BYTE v[4] __PACKED;
|
||||||
|
struct __PACKED
|
||||||
|
{
|
||||||
|
WORD LW;
|
||||||
|
WORD HW;
|
||||||
|
} word;
|
||||||
|
struct __PACKED
|
||||||
|
{
|
||||||
|
BYTE LB;
|
||||||
|
BYTE HB;
|
||||||
|
BYTE UB;
|
||||||
|
BYTE MB;
|
||||||
|
} byte;
|
||||||
|
struct __PACKED
|
||||||
|
{
|
||||||
|
WORD_VAL low;
|
||||||
|
WORD_VAL high;
|
||||||
|
}wordUnion;
|
||||||
|
struct __PACKED
|
||||||
|
{
|
||||||
|
__EXTENSION BYTE b0:1;
|
||||||
|
__EXTENSION BYTE b1:1;
|
||||||
|
__EXTENSION BYTE b2:1;
|
||||||
|
__EXTENSION BYTE b3:1;
|
||||||
|
__EXTENSION BYTE b4:1;
|
||||||
|
__EXTENSION BYTE b5:1;
|
||||||
|
__EXTENSION BYTE b6:1;
|
||||||
|
__EXTENSION BYTE b7:1;
|
||||||
|
__EXTENSION BYTE b8:1;
|
||||||
|
__EXTENSION BYTE b9:1;
|
||||||
|
__EXTENSION BYTE b10:1;
|
||||||
|
__EXTENSION BYTE b11:1;
|
||||||
|
__EXTENSION BYTE b12:1;
|
||||||
|
__EXTENSION BYTE b13:1;
|
||||||
|
__EXTENSION BYTE b14:1;
|
||||||
|
__EXTENSION BYTE b15:1;
|
||||||
|
__EXTENSION BYTE b16:1;
|
||||||
|
__EXTENSION BYTE b17:1;
|
||||||
|
__EXTENSION BYTE b18:1;
|
||||||
|
__EXTENSION BYTE b19:1;
|
||||||
|
__EXTENSION BYTE b20:1;
|
||||||
|
__EXTENSION BYTE b21:1;
|
||||||
|
__EXTENSION BYTE b22:1;
|
||||||
|
__EXTENSION BYTE b23:1;
|
||||||
|
__EXTENSION BYTE b24:1;
|
||||||
|
__EXTENSION BYTE b25:1;
|
||||||
|
__EXTENSION BYTE b26:1;
|
||||||
|
__EXTENSION BYTE b27:1;
|
||||||
|
__EXTENSION BYTE b28:1;
|
||||||
|
__EXTENSION BYTE b29:1;
|
||||||
|
__EXTENSION BYTE b30:1;
|
||||||
|
__EXTENSION BYTE b31:1;
|
||||||
|
} bits;
|
||||||
|
} DWORD_VAL;
|
||||||
|
|
||||||
|
/* MPLAB C Compiler for PIC18 does not support 64-bit integers */
|
||||||
|
/*typedef union
|
||||||
|
{
|
||||||
|
QWORD Val;
|
||||||
|
DWORD d[2] __PACKED;
|
||||||
|
WORD w[4] __PACKED;
|
||||||
|
BYTE v[8] __PACKED;
|
||||||
|
struct __PACKED
|
||||||
|
{
|
||||||
|
DWORD LD;
|
||||||
|
DWORD HD;
|
||||||
|
} dword;
|
||||||
|
struct __PACKED
|
||||||
|
{
|
||||||
|
WORD LW;
|
||||||
|
WORD HW;
|
||||||
|
WORD UW;
|
||||||
|
WORD MW;
|
||||||
|
} word;
|
||||||
|
struct __PACKED
|
||||||
|
{
|
||||||
|
__EXTENSION BYTE b0:1;
|
||||||
|
__EXTENSION BYTE b1:1;
|
||||||
|
__EXTENSION BYTE b2:1;
|
||||||
|
__EXTENSION BYTE b3:1;
|
||||||
|
__EXTENSION BYTE b4:1;
|
||||||
|
__EXTENSION BYTE b5:1;
|
||||||
|
__EXTENSION BYTE b6:1;
|
||||||
|
__EXTENSION BYTE b7:1;
|
||||||
|
__EXTENSION BYTE b8:1;
|
||||||
|
__EXTENSION BYTE b9:1;
|
||||||
|
__EXTENSION BYTE b10:1;
|
||||||
|
__EXTENSION BYTE b11:1;
|
||||||
|
__EXTENSION BYTE b12:1;
|
||||||
|
__EXTENSION BYTE b13:1;
|
||||||
|
__EXTENSION BYTE b14:1;
|
||||||
|
__EXTENSION BYTE b15:1;
|
||||||
|
__EXTENSION BYTE b16:1;
|
||||||
|
__EXTENSION BYTE b17:1;
|
||||||
|
__EXTENSION BYTE b18:1;
|
||||||
|
__EXTENSION BYTE b19:1;
|
||||||
|
__EXTENSION BYTE b20:1;
|
||||||
|
__EXTENSION BYTE b21:1;
|
||||||
|
__EXTENSION BYTE b22:1;
|
||||||
|
__EXTENSION BYTE b23:1;
|
||||||
|
__EXTENSION BYTE b24:1;
|
||||||
|
__EXTENSION BYTE b25:1;
|
||||||
|
__EXTENSION BYTE b26:1;
|
||||||
|
__EXTENSION BYTE b27:1;
|
||||||
|
__EXTENSION BYTE b28:1;
|
||||||
|
__EXTENSION BYTE b29:1;
|
||||||
|
__EXTENSION BYTE b30:1;
|
||||||
|
__EXTENSION BYTE b31:1;
|
||||||
|
__EXTENSION BYTE b32:1;
|
||||||
|
__EXTENSION BYTE b33:1;
|
||||||
|
__EXTENSION BYTE b34:1;
|
||||||
|
__EXTENSION BYTE b35:1;
|
||||||
|
__EXTENSION BYTE b36:1;
|
||||||
|
__EXTENSION BYTE b37:1;
|
||||||
|
__EXTENSION BYTE b38:1;
|
||||||
|
__EXTENSION BYTE b39:1;
|
||||||
|
__EXTENSION BYTE b40:1;
|
||||||
|
__EXTENSION BYTE b41:1;
|
||||||
|
__EXTENSION BYTE b42:1;
|
||||||
|
__EXTENSION BYTE b43:1;
|
||||||
|
__EXTENSION BYTE b44:1;
|
||||||
|
__EXTENSION BYTE b45:1;
|
||||||
|
__EXTENSION BYTE b46:1;
|
||||||
|
__EXTENSION BYTE b47:1;
|
||||||
|
__EXTENSION BYTE b48:1;
|
||||||
|
__EXTENSION BYTE b49:1;
|
||||||
|
__EXTENSION BYTE b50:1;
|
||||||
|
__EXTENSION BYTE b51:1;
|
||||||
|
__EXTENSION BYTE b52:1;
|
||||||
|
__EXTENSION BYTE b53:1;
|
||||||
|
__EXTENSION BYTE b54:1;
|
||||||
|
__EXTENSION BYTE b55:1;
|
||||||
|
__EXTENSION BYTE b56:1;
|
||||||
|
__EXTENSION BYTE b57:1;
|
||||||
|
__EXTENSION BYTE b58:1;
|
||||||
|
__EXTENSION BYTE b59:1;
|
||||||
|
__EXTENSION BYTE b60:1;
|
||||||
|
__EXTENSION BYTE b61:1;
|
||||||
|
__EXTENSION BYTE b62:1;
|
||||||
|
__EXTENSION BYTE b63:1;
|
||||||
|
} bits;
|
||||||
|
} QWORD_VAL;
|
||||||
|
*/
|
||||||
|
#undef __EXTENSION
|
||||||
|
|
||||||
|
#ifndef uint24_t
|
||||||
|
#define uint24_t uint32_t
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef void(*pFunc)(void);
|
||||||
|
/*
|
||||||
|
typedef union _POINTER
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
BYTE bLow;
|
||||||
|
BYTE bHigh;
|
||||||
|
//BYTE bUpper;
|
||||||
|
};
|
||||||
|
uint16_t _word; // bLow & bHigh
|
||||||
|
|
||||||
|
//pFunc _pFunc; // Usage: ptr.pFunc(); Init: ptr.pFunc = &<Function>;
|
||||||
|
|
||||||
|
BYTE* bRam; // Ram byte pointer: 2 bytes pointer pointing
|
||||||
|
// to 1 byte of data
|
||||||
|
uint16_t* wRam; // Ram word poitner: 2 bytes poitner pointing
|
||||||
|
// to 2 bytes of data
|
||||||
|
|
||||||
|
ROM BYTE* bRom; // Size depends on compiler setting
|
||||||
|
ROM WORD* wRom;
|
||||||
|
//ROM near BYTE* nbRom; // Near = 2 bytes pointer
|
||||||
|
//ROM near uint16_t* nwRom;
|
||||||
|
//ROM far BYTE* fbRom; // Far = 3 bytes pointer
|
||||||
|
//ROM far uint16_t* fwRom;
|
||||||
|
} POINTER;
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __CUSTOMIZED_TYPE_DEFS_H_ */
|
||||||
@@ -171,6 +171,9 @@
|
|||||||
#define HID_NUM_OF_DSC 1
|
#define HID_NUM_OF_DSC 1
|
||||||
#define HID_RPT01_SIZE 29
|
#define HID_RPT01_SIZE 29
|
||||||
|
|
||||||
|
#define HID_IN_EP 0
|
||||||
|
#define HID_OUT_EP 1
|
||||||
|
|
||||||
/** DEFINITIONS ****************************************************/
|
/** DEFINITIONS ****************************************************/
|
||||||
|
|
||||||
#endif //USBCFG_H
|
#endif //USBCFG_H
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "usb.h"
|
#include "usb.h"
|
||||||
#include "usb_device_hid.h"
|
#include "usb_device_hid.h"
|
||||||
|
#include "bootloader.h"
|
||||||
|
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
* Function: bool USER_USB_CALLBACK_EVENT_HANDLER(
|
* Function: bool USER_USB_CALLBACK_EVENT_HANDLER(
|
||||||
@@ -53,7 +54,9 @@ bool USER_USB_CALLBACK_EVENT_HANDLER(USB_EVENT event, void *pdata, uint16_t size
|
|||||||
|
|
||||||
case EVENT_CONFIGURED:
|
case EVENT_CONFIGURED:
|
||||||
// When the device is configured, we should (re)initialize our state variables
|
// When the device is configured, we should (re)initialize our state variables
|
||||||
USBEnableEndpoint(1, USB_IN_ENABLED|USB_HANDSHAKE_ENABLED|USB_DISALLOW_SETUP);
|
UserInit();
|
||||||
|
USBEnableEndpoint(HID_IN_EP, USB_IN_ENABLED|USB_HANDSHAKE_ENABLED|USB_DISALLOW_SETUP);
|
||||||
|
USBEnableEndpoint(HID_OUT_EP, USB_OUT_ENABLED|USB_HANDSHAKE_ENABLED|USB_DISALLOW_SETUP);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EVENT_SET_DESCRIPTOR:
|
case EVENT_SET_DESCRIPTOR:
|
||||||
|
|||||||
Reference in New Issue
Block a user