added hacked bootloader demo project that came with the MLA

This commit is contained in:
2019-08-10 15:36:38 -04:00
commit 1c236365d6
17 changed files with 5713 additions and 0 deletions

View File

@@ -0,0 +1,108 @@
#
# There exist several targets which are by default empty and which can be
# used for execution of your targets. These targets are usually executed
# before and after some main targets. They are:
#
# .build-pre: called before 'build' target
# .build-post: called after 'build' target
# .clean-pre: called before 'clean' target
# .clean-post: called after 'clean' target
# .clobber-pre: called before 'clobber' target
# .clobber-post: called after 'clobber' target
# .all-pre: called before 'all' target
# .all-post: called after 'all' target
# .help-pre: called before 'help' target
# .help-post: called after 'help' target
#
# Targets beginning with '.' are not intended to be called on their own.
#
# Main targets can be executed directly, and they are:
#
# build build a specific configuration
# clean remove built files from a configuration
# clobber remove all built files
# all build all configurations
# help print help mesage
#
# Targets .build-impl, .clean-impl, .clobber-impl, .all-impl, and
# .help-impl are implemented in nbproject/makefile-impl.mk.
#
# Available make variables:
#
# CND_BASEDIR base directory for relative paths
# CND_DISTDIR default top distribution directory (build artifacts)
# CND_BUILDDIR default top build directory (object files, ...)
# CONF name of current configuration
# CND_ARTIFACT_DIR_${CONF} directory of build artifact (current configuration)
# CND_ARTIFACT_NAME_${CONF} name of build artifact (current configuration)
# CND_ARTIFACT_PATH_${CONF} path to build artifact (current configuration)
# CND_PACKAGE_DIR_${CONF} directory of package (current configuration)
# CND_PACKAGE_NAME_${CONF} name of package (current configuration)
# CND_PACKAGE_PATH_${CONF} path to package (current configuration)
#
# NOCDDL
# Environment
MKDIR=mkdir
CP=cp
CCADMIN=CCadmin
RANLIB=ranlib
# build
build: .build-post
.build-pre:
# Add your pre 'build' code here...
.build-post: .build-impl
# Add your post 'build' code here...
# clean
clean: .clean-post
.clean-pre:
# Add your pre 'clean' code here...
.clean-post: .clean-impl
# Add your post 'clean' code here...
# clobber
clobber: .clobber-post
.clobber-pre:
# Add your pre 'clobber' code here...
.clobber-post: .clobber-impl
# Add your post 'clobber' code here...
# all
all: .all-post
.all-pre:
# Add your pre 'all' code here...
.all-post: .all-impl
# Add your post 'all' code here...
# help
help: .help-post
.help-pre:
# Add your pre 'help' code here...
.help-post: .help-impl
# Add your post 'help' code here...
# include project implementation makefile
include nbproject/Makefile-impl.mk
# include project make variables
include nbproject/Makefile-variables.mk

View File

@@ -0,0 +1,264 @@
<?xml version="1.0" encoding="UTF-8"?>
<configurationDescriptor version="65">
<logicalFolder name="root" displayName="root" projectFiles="true">
<logicalFolder name="HeaderFiles"
displayName="Header Files"
projectFiles="true">
<itemPath>../src/BootPIC18NonJ.h</itemPath>
<itemPath>../src/HardwareProfile.h</itemPath>
<itemPath>../src/typedefs.h</itemPath>
<itemPath>../src/usb.h</itemPath>
<itemPath>../src/usb_config.h</itemPath>
<itemPath>../src/usb_device.h</itemPath>
<itemPath>../src/usb_device_hid.h</itemPath>
</logicalFolder>
<logicalFolder name="LibraryFiles"
displayName="Library Files"
projectFiles="true">
</logicalFolder>
<logicalFolder name="LinkerScript"
displayName="Linker Files"
projectFiles="true">
</logicalFolder>
<logicalFolder name="ObjectFiles"
displayName="Object Files"
projectFiles="true">
</logicalFolder>
<logicalFolder name="SourceFiles"
displayName="Source Files"
projectFiles="true">
<itemPath>../src/BootPIC18NonJ.c</itemPath>
<itemPath>../src/VectorRemap.asm</itemPath>
<itemPath>../src/main.c</itemPath>
<itemPath>../src/usb_descriptors.c</itemPath>
<itemPath>../src/usb_device.c</itemPath>
<itemPath>../src/usb_device_hid.c</itemPath>
<itemPath>../../src/system.c</itemPath>
</logicalFolder>
<logicalFolder name="ExternalFiles"
displayName="Important Files"
projectFiles="false">
<itemPath>Makefile</itemPath>
</logicalFolder>
</logicalFolder>
<sourceRootList>
<Elem>../</Elem>
<Elem>../../src</Elem>
</sourceRootList>
<projectmakefile>Makefile</projectmakefile>
<confs>
<conf name="PIC18F2550_XC8" type="2">
<toolsSet>
<developmentServer>localhost</developmentServer>
<targetDevice>PIC18F2550</targetDevice>
<targetHeader></targetHeader>
<targetPluginBoard></targetPluginBoard>
<platformTool>PICkit3PlatformTool</platformTool>
<languageToolchain>XC8</languageToolchain>
<languageToolchainVersion>2.05</languageToolchainVersion>
<platform>3</platform>
</toolsSet>
<packs>
<pack name="PIC18Fxxxx_DFP" vendor="Microchip" version="1.0.9"/>
</packs>
<compileType>
<linkerTool>
<linkerLibItems>
</linkerLibItems>
</linkerTool>
<archiverTool>
</archiverTool>
<loading>
<useAlternateLoadableFile>false</useAlternateLoadableFile>
<parseOnProdLoad>true</parseOnProdLoad>
<alternateLoadableFile></alternateLoadableFile>
</loading>
<subordinates>
</subordinates>
</compileType>
<makeCustomizationType>
<makeCustomizationPreStepEnabled>false</makeCustomizationPreStepEnabled>
<makeCustomizationPreStep></makeCustomizationPreStep>
<makeCustomizationPostStepEnabled>false</makeCustomizationPostStepEnabled>
<makeCustomizationPostStep></makeCustomizationPostStep>
<makeCustomizationPutChecksumInUserID>false</makeCustomizationPutChecksumInUserID>
<makeCustomizationEnableLongLines>false</makeCustomizationEnableLongLines>
<makeCustomizationNormalizeHexFile>false</makeCustomizationNormalizeHexFile>
</makeCustomizationType>
<HI-TECH-COMP>
<property key="additional-warnings" value="true"/>
<property key="asmlist" value="true"/>
<property key="default-bitfield-type" value="true"/>
<property key="default-char-type" value="true"/>
<property key="define-macros" value=""/>
<property key="disable-optimizations" value="true"/>
<property key="extra-include-directories" value=""/>
<property key="favor-optimization-for" value="-speed,+space"/>
<property key="garbage-collect-data" value="true"/>
<property key="garbage-collect-functions" value="true"/>
<property key="identifier-length" value="255"/>
<property key="local-generation" value="false"/>
<property key="operation-mode" value="pro"/>
<property key="opt-xc8-compiler-strict_ansi" value="false"/>
<property key="optimization-assembler" value="true"/>
<property key="optimization-assembler-files" value="false"/>
<property key="optimization-debug" value="false"/>
<property key="optimization-invariant-enable" value="false"/>
<property key="optimization-invariant-value" value="16"/>
<property key="optimization-level" value="-O0"/>
<property key="optimization-speed" value="false"/>
<property key="optimization-stable-enable" value="false"/>
<property key="pack-struct" value="true"/>
<property key="preprocess-assembler" value="true"/>
<property key="short-enums" value="true"/>
<property key="undefine-macros" value=""/>
<property key="use-cci" value="true"/>
<property key="use-iar" value="false"/>
<property key="verbose" value="false"/>
<property key="warning-level" value="0"/>
<property key="what-to-do" value="require"/>
</HI-TECH-COMP>
<HI-TECH-LINK>
<property key="additional-options-checksum" value=""/>
<property key="additional-options-code-offset" value=""/>
<property key="additional-options-command-line" value=""/>
<property key="additional-options-errata" value=""/>
<property key="additional-options-extend-address" value="false"/>
<property key="additional-options-trace-type" value=""/>
<property key="additional-options-use-response-files" value="false"/>
<property key="backup-reset-condition-flags" value="false"/>
<property key="calibrate-oscillator" value="true"/>
<property key="calibrate-oscillator-value" value=""/>
<property key="clear-bss" value="true"/>
<property key="code-model-external" value="wordwrite"/>
<property key="code-model-rom" value="default,-1400-7FFF"/>
<property key="create-html-files" value="false"/>
<property key="data-model-ram" value=""/>
<property key="data-model-size-of-double" value="32"/>
<property key="data-model-size-of-double-gcc" value="no-short-double"/>
<property key="data-model-size-of-float" value="32"/>
<property key="data-model-size-of-float-gcc" value="no-short-float"/>
<property key="display-class-usage" value="false"/>
<property key="display-hex-usage" value="false"/>
<property key="display-overall-usage" value="true"/>
<property key="display-psect-usage" value="false"/>
<property key="extra-lib-directories" value=""/>
<property key="fill-flash-options-addr" value=""/>
<property key="fill-flash-options-const" value=""/>
<property key="fill-flash-options-how" value="0"/>
<property key="fill-flash-options-inc-const" value="1"/>
<property key="fill-flash-options-increment" value=""/>
<property key="fill-flash-options-seq" value=""/>
<property key="fill-flash-options-what" value="0"/>
<property key="format-hex-file-for-download" value="false"/>
<property key="initialize-data" value="true"/>
<property key="input-libraries" value="libm"/>
<property key="keep-generated-startup.as" value="true"/>
<property key="link-in-c-library" value="true"/>
<property key="link-in-c-library-gcc" value=""/>
<property key="link-in-peripheral-library" value="false"/>
<property key="managed-stack" value="false"/>
<property key="opt-xc8-linker-file" value="false"/>
<property key="opt-xc8-linker-link_startup" value="false"/>
<property key="opt-xc8-linker-serial" value=""/>
<property key="program-the-device-with-default-config-words" value="true"/>
<property key="remove-unused-sections" value="true"/>
</HI-TECH-LINK>
<ICD3PlatformTool>
<property key="AutoSelectMemRanges" value="auto"/>
<property key="Freeze Peripherals" value="true"/>
<property key="SecureSegment.SegmentProgramming" value="FullChipProgramming"/>
<property key="ToolFirmwareFilePath"
value="Press to browse for a specific firmware version"/>
<property key="ToolFirmwareOption.UseLatestFirmware" value="true"/>
<property key="debugoptions.useswbreakpoints" value="false"/>
<property key="hwtoolclock.frcindebug" value="false"/>
<property key="memories.aux" value="false"/>
<property key="memories.bootflash" value="false"/>
<property key="memories.configurationmemory" value="false"/>
<property key="memories.configurationmemory2" value="true"/>
<property key="memories.dataflash" value="true"/>
<property key="memories.eeprom" value="true"/>
<property key="memories.flashdata" value="true"/>
<property key="memories.id" value="true"/>
<property key="memories.instruction.ram" value="true"/>
<property key="memories.instruction.ram.ranges"
value="${memories.instruction.ram.ranges}"/>
<property key="memories.programmemory" value="true"/>
<property key="memories.programmemory.ranges" value="0-7fff"/>
<property key="poweroptions.powerenable" value="false"/>
<property key="programoptions.donoteraseauxmem" value="false"/>
<property key="programoptions.eraseb4program" value="true"/>
<property key="programoptions.preservedataflash" value="false"/>
<property key="programoptions.preservedataflash.ranges" value=""/>
<property key="programoptions.preserveeeprom" value="false"/>
<property key="programoptions.preserveeeprom.ranges" value="0-ff"/>
<property key="programoptions.preserveprogram.ranges" value=""/>
<property key="programoptions.preserveprogramrange" value="false"/>
<property key="programoptions.preserveuserid" value="false"/>
<property key="programoptions.programcalmem" value="false"/>
<property key="programoptions.programuserotp" value="false"/>
<property key="programoptions.testmodeentrymethod" value="VPPFirst"/>
<property key="programoptions.usehighvoltageonmclr" value="false"/>
<property key="programoptions.uselvpprogramming" value="false"/>
<property key="voltagevalue" value="5.0"/>
</ICD3PlatformTool>
<PICkit3PlatformTool>
<property key="AutoSelectMemRanges" value="auto"/>
<property key="Freeze Peripherals" value="true"/>
<property key="SecureSegment.SegmentProgramming" value="FullChipProgramming"/>
<property key="ToolFirmwareFilePath"
value="Press to browse for a specific firmware version"/>
<property key="ToolFirmwareOption.UseLatestFirmware" value="true"/>
<property key="debugoptions.useswbreakpoints" value="false"/>
<property key="firmware.download.all" value="false"/>
<property key="hwtoolclock.frcindebug" value="false"/>
<property key="memories.aux" value="false"/>
<property key="memories.bootflash" value="true"/>
<property key="memories.configurationmemory" value="true"/>
<property key="memories.configurationmemory2" value="true"/>
<property key="memories.dataflash" value="true"/>
<property key="memories.eeprom" value="true"/>
<property key="memories.flashdata" value="true"/>
<property key="memories.id" value="true"/>
<property key="memories.instruction.ram" value="true"/>
<property key="memories.instruction.ram.ranges"
value="${memories.instruction.ram.ranges}"/>
<property key="memories.programmemory" value="true"/>
<property key="memories.programmemory.ranges" value="0-7fff"/>
<property key="poweroptions.powerenable" value="false"/>
<property key="programmertogo.imagename" value=""/>
<property key="programoptions.donoteraseauxmem" value="false"/>
<property key="programoptions.eraseb4program" value="true"/>
<property key="programoptions.pgmspeed" value="2"/>
<property key="programoptions.preservedataflash" value="false"/>
<property key="programoptions.preservedataflash.ranges"
value="${programoptions.preservedataflash.ranges}"/>
<property key="programoptions.preserveeeprom" value="false"/>
<property key="programoptions.preserveeeprom.ranges" value="0-ff"/>
<property key="programoptions.preserveprogram.ranges" value=""/>
<property key="programoptions.preserveprogramrange" value="false"/>
<property key="programoptions.preserveuserid" value="false"/>
<property key="programoptions.programcalmem" value="false"/>
<property key="programoptions.programuserotp" value="false"/>
<property key="programoptions.testmodeentrymethod" value="VDDFirst"/>
<property key="programoptions.usehighvoltageonmclr" value="false"/>
<property key="programoptions.uselvpprogramming" value="false"/>
<property key="voltagevalue" value="5.0"/>
</PICkit3PlatformTool>
<XC8-config-global>
<property key="advanced-elf" value="true"/>
<property key="gcc-opt-driver-new" value="true"/>
<property key="gcc-opt-std" value="-std=c90"/>
<property key="gcc-output-file-format" value="dwarf-3"/>
<property key="omit-pack-options" value="false"/>
<property key="output-file-format" value="-mcof,+elf"/>
<property key="stack-size-high" value="auto"/>
<property key="stack-size-low" value="auto"/>
<property key="stack-size-main" value="auto"/>
<property key="stack-type" value="compiled"/>
<property key="user-pack-device-support" value=""/>
</XC8-config-global>
</conf>
</confs>
</configurationDescriptor>

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.netbeans.org/ns/project/1">
<type>com.microchip.mplab.nbide.embedded.makeproject</type>
<configuration>
<data xmlns="http://www.netbeans.org/ns/make-project/1">
<name>bootloader_hacked_from_mla</name>
<creation-uuid>10ecf416-ca94-402f-a3ea-0a0beb0c5a13</creation-uuid>
<make-project-type>0</make-project-type>
<c-extensions>c</c-extensions>
<cpp-extensions/>
<header-extensions>h</header-extensions>
<sourceEncoding>ISO-8859-1</sourceEncoding>
<asminc-extensions/>
<make-dep-projects/>
<sourceRootList>
<sourceRootElem>../</sourceRootElem>
<sourceRootElem>../../src</sourceRootElem>
</sourceRootList>
<confList>
<confElem>
<name>PIC18F2550_XC8</name>
<type>2</type>
</confElem>
</confList>
<formatting>
<project-formatting-style>false</project-formatting-style>
</formatting>
</data>
</configuration>
</project>

View File

@@ -0,0 +1,926 @@
/*******************************************************************************
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
*******************************************************************************/
/** I N C L U D E S **********************************************************/
#include "usb.h"
#include "BootPIC18NonJ.h"
/** C O N S T A N T S **********************************************************/
//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.
#if defined(__18F4550)||defined(__18F2550)||defined(__18F45K50)||defined(__18LF45K50)||defined(__18F25K50)||defined(__18LF25K50)
#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
#elif defined(__18F4553)||defined(__18F2553)
#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
#elif defined(__18F4455)||defined(__18F2455)
#define MAX_PAGE_TO_ERASE 383 //Last 64 byte page of flash on the PIC18F4455
#define PROGRAM_MEM_STOP_ADDRESS 0x006000 //**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
#elif defined(__18F4458)||defined(__18F2458)
#define MAX_PAGE_TO_ERASE 383 //Last 64 byte page of flash on the PIC18F4455
#define PROGRAM_MEM_STOP_ADDRESS 0x006000 //**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 UserIDSize 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
#elif defined(__18F4450)||defined(__18F2450)
#define MAX_PAGE_TO_ERASE 255 //Last 64 byte page of flash on the PIC18F4450
#define PROGRAM_MEM_STOP_ADDRESS 0x004000 //**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 WRITE_BLOCK_SIZE 0x10 //16 byte programming block size on the PIC18F4450/2450 family devices
#define ERASE_PAGE_SIZE 64
#elif defined(__18F24K50)||defined(__18LF24K50)
#define MAX_PAGE_TO_ERASE 255 //Last 64 byte page of flash on the PIC18F4450
#define PROGRAM_MEM_STOP_ADDRESS 0x004000 //**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 0x10 //16 byte programming block size on the PIC18F4450/2450 family devices
#define ERASE_PAGE_SIZE 64
#elif defined(__18F14K50) || defined(__18LF14K50)
#define MAX_PAGE_TO_ERASE 255 //Last 64 byte page of flash on the PIC18F4455
#define PROGRAM_MEM_STOP_ADDRESS 0x004000 //**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 0x10 //16 byte programming block size on the PIC18F14K50 family devices
#define ERASE_PAGE_SIZE 64
#elif defined(__18F13K50) || defined(__18LF13K50)
#define MAX_PAGE_TO_ERASE 127 //Last 64 byte page of flash on the PIC18F4455
#define PROGRAM_MEM_STOP_ADDRESS 0x002000 //**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 0x08 //8 byte programming block size on the PIC18F14K50 family devices
#define ERASE_PAGE_SIZE 64
#endif
//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;
/** V A R I A B L E S ********************************************************/
#ifndef __XC8__
#pragma udata
#endif
PacketToFromPC PacketFromPC;
#ifndef __XC8__
#pragma udata SomeSectionName3
#endif
PacketToFromPC PacketToPC;
#ifndef __XC8__
#pragma udata WriteBufferSection
#endif
unsigned char ProgrammingBuffer[ERASE_PAGE_SIZE];
#ifndef __XC8__
#pragma udata OtherVariablesSection
#endif
unsigned char BootState;
unsigned int ErasePageTracker;
unsigned char BufferedDataIndex;
uint24_t ProgrammedPointer;
unsigned char ConfigsLockValue;
/** P R I V A T E P R O T O T Y P E S ***************************************/
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);
/** D E C L A R A T I O N S **************************************************/
#ifndef __XC8__
#pragma code
#endif
void UserInit(void)
{
//Initialize bootloader state variables
BootState = IDLE;
ProgrammedPointer = INVALID_ADDRESS;
BufferedDataIndex = 0;
ConfigsLockValue = TRUE;
}//end UserInit
/******************************************************************************
* 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(!mHIDRxIsBusy()) //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.
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(!mHIDTxIsBusy())
{
//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.
HIDTxReport((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(!mHIDTxIsBusy())
{
HIDTxReport((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(!mHIDTxIsBusy())
{
HIDTxReport((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)
}//End ProcessIO()
//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
}
/** EOF BootPIC18NonJ.c *********************************************************/

View File

@@ -0,0 +1,41 @@
/*******************************************************************************
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 BOOTPIC18NONJ_H
#define BOOTPIC18NONJ_H
/** P U B L I C P R O T O T Y P E S *****************************************/
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 //BOOTPIC18NONJ_H

View File

@@ -0,0 +1,30 @@
/*******************************************************************************
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 __HARDWARE_PROFILE_H_
#define __HARDWARE_PROFILE_H_
/** I N C L U D E S *************************************************/
#include "usb_config.h"
#endif //__HARDWARE_PROFILE_H_

View File

@@ -0,0 +1,39 @@
;/*******************************************************************************
;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
;*******************************************************************************/
;//High priority interrupt vector remapping
#ifdef __XC8__
PSECT HiVector,class=CODE,delta=1,abs
#endif
org 0x08
goto 0x1408 ;Resides at 0x0008 (hardware high priority interrupt vector), and causes PC to jump to 0x1408 upon a high priority interrupt event
;//Low priority interrupt vector remapping, as well as bootloader mode absolute
;//entry point (located at 0x001C).
#ifdef __XC8__
PSECT LoVector,class=CODE,delta=1,abs
#endif
org 0x18
goto 0x1418 ;Resides at 0x0018 (hardware low priority interrupt vector), and causes PC to jump to 0x1418 upon a low priority interrupt event
goto 0x30 ;Resides at 0x001C //Serves as absolute entry point from application program into the bootloader mode
end

View File

@@ -0,0 +1,626 @@
/*******************************************************************************
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
*******************************************************************************/
/*********************************************************************
IMPORTANT NOTES: This code can be readily adapted for use with the
both the F and LF versions of the following devices:
PIC18F4553/4458/2553/2458
PIC18F4550/4455/2550/2455
PIC18F4450/2450
PIC18F14K50/13K50
PIC18F45K50/25K50/24K50
However, the default device that is currently selected in the project
may not be the device you are interested. To change the device:
Replace the linker script with an appropriate version, and
click "Configure --> Select Device" and select the proper
microcontroller. Also double check to verify that the HardwareProfile.h and
usb_config.h are properly configured to match your desired application
platform.
Verify that the configuration bits are set correctly for the intended
target application, and fix any build errors that result from either
the #error directives, or due to I/O pin count mismatch issues (such
as when using a 28-pin device, but without making sufficient changes
to the HardwareProfile.h file)
-------------------------------------------------------------------
NOTE FOR BUILDING WITH C18 COMPILER:
-------------------------------------------------------------------
This project needs to be built with the full compiler optimizations
enabled, and using the Default storage class "Static" or the total
code size will be too large to fit within the program memory
range 0x000-0xFFF. The default linker script included
in the project has this range reserved for the use by the bootloader,
but marks the rest of program memory as "PROTECTED". If you try to
build this project with the compiler optimizations turned off, or
you try to modify some of this code, but add too much code to fit
within the 0x000-0xFFF region, a linker error like that below may occur:
Error - section '.code' can not fit the section. Section '.code' length=0x00000020
To fix this error, either optimize the program to fit within 0x000-0xFFF
(such as by turning on all compiler optimizations, and making sure the
"default storage class" is set to "Static"), or modify the linker
and vector remapping (as well as the application projects) to allow this
bootloader to use more program memory.
-------------------------------------------------------------------
NOTE FOR BUILDING THIS BOOTLOADER FIRMWARE WITH THE XC8 COMPILER:
-------------------------------------------------------------------
To build this code with the XC8 compiler, make sure to use the linker
option:
ROM ranges: default,-1000-XXXXXX //Where "XXXXXX" is the last implemented flash memory
address, excluding the config bit region (ex: "default,-1000-7FFF" for the 32kB PIC18F45K50)
This setting is found in the XC8 compiler linker settings, Option category: Memory Model.
If any errors are encountered relating to "cannot find space", this
presumably means that either the compiler was configured to build the
code in Free or Standard mode, or that modifications have been made to
the code that have increased the code size to exceed the 0x000-0xFFF program
memory region. If this error is encountered, make sure to build the project
with all PRO mode optimizations enabled, and/or optimize any user added code
that is causing the project size to exceed the 0x000-0xFFF region.
----------------------------------------------------------------------
NOTE FOR BUILDING APPLICATION FIRMWARE PROJECTS WITH THE XC8 COMPILER:
----------------------------------------------------------------------
When building the application project that is meant to be programmed by this
bootloader, you must use different XC8 linker settings as this project.
For application projects, two linker settings are required:
ROM ranges: default,-0-FFF,-1006-1007,-1016-1017
Codeoffset: 0x1000
When the above settings are implemented, the application firmware will no longer work
without the bootloader present. Therefore, it is recommended to add the bootloader
firmware output (from this bootloader project) .hex file as a "Loadable" into
the application firmware project. This will allow the "HEXMATE" tool to run
after building the application firmware project, which will merge the application
output .hex file contents with the bootloader output .hex file contents (which was
added as a loadable file).
However, in some cases you may encounter build errors during the hex merge operation.
This will occur if there are any overlapping regions in the bootloader firmware
.hex file, with the application firmware .hex file, when the contents of these
overlapping regions are not 100% exact matches to each other. Normally, only the
configuration bit settings will be overlapping between the two projects.
Therefore, to prevent build errors, the configuration bit settings between the
bootloader firmware project and the application firmware project must be set to
100% exactly identical values (or they must only be set in one of the projects,
to eliminate the overlapping region altogether).
----------------------Bootloader Entry------------------------------------------
Entry into this bootloader firmware can be done by either of two possible
ways:
1. I/O pin check at power up/after any reset. and/or:
2. Software entry via absolute jump to address 0x001C.
The I/O pin check method is the most rugged, since it does not require the
application firmware image to be intact (at all) to get into the bootloader
mode. However, software entry is also possible and may be more convenient
in applications that do not have user exposed pushbuttons available.
When the "application" image is executing, it may optionally jump into
bootloader mode, by executing a _asm goto 0x001C _endasm instruction.
Before doing so however, the firwmare should configure the current
clock settings to be compatible with USB module operation, in they
are not already. Once the goto 0x001C has been executed the USB device
will detach from the USB bus (if it was previously attached), and will
re-enumerate as a HID class device with a new VID/PID (adjustable via
usb_dsc.c settings), which can communicate with the associated
USB host software that loads and programs the new .hex file.
--------------------------------------------------------------------------------
Anytime that an application implements flash self erase/write capability,
special care should be taken to make sure that the microcontroller is operated
within all datasheet ratings, especially those associated with voltage versus
frequency.
Operating the device at too high of a frequency (for a given voltage, ex: by
operating at 48MHz at 2.1V, while the device datasheet indicates some higher
value such as 2.35V+ is required) can cause unexpected code operation. This
could potentially allow inadvertent execution of bootloader or other self
erase/write routines, causing corruption of the flash memory of the application.
To avoid this, all applications that implement self erase/write capability
should make sure to prevent execution during overclocked/undervolted conditions.
For this reason, enabling and using the microcontroller hardware Brown-out-Reset
feature is particularly recommended for applications using a bootloader. If
BOR is not used, or the trip threshold is too low for the intended application
frequency, it is suggested to add extra code in the application to detect low
voltage conditions, and to intentionally clock switch to a lower frequency
(or put the device to sleep) during the low voltage condition. Hardware
modules such as the ADC, comparators, or the HLVD (high/low voltage detect)
can often be used for this purpose.
--------------------------------------------------------------------------------
This bootloader supports reprogramming of the microcontroller configuration bits,
however, it is strongly recommended never to do so, unless absolutely necessary.
Reprogramming the config bits is potentially risky, since it requires that the
new configuration bits be 100% compatible with USB operation (ex: oscillator
settings, etc.). If a .hex file with incorrect config bits is programmed
into this device, it can render the bootloader inoperable. Additionally,
unexpected power failure or device detachment during the reprogramming of the
config bits could result in unknown values getting stored in the config bits,
which could "brick" the application.
Normally, the application firmware project and this bootloader project should
be configured to use/set the exact same configuration bit values. Only one set
of configuration bits actually exists in the microcontroller, and these values
must be shared between the bootloader and application firmware.
*******************************************************************************/
/** I N C L U D E S **********************************************************/
#include "usb.h"
#include "HardwareProfile.h"
#include "BootPIC18NonJ.h"
/** V A R I A B L E S ********************************************************/
//NOTE: You must not use initalized variables in this bootloader project. This
//firmware project does not rely on the standard C initializer, which is
//responsible for setting up initialized variables in RAM. Therefore, all
//variables will be non-initialized/random at start up.
#ifndef __XC8__
#pragma udata
#endif
unsigned int uint_delay_counter;
//------------------------------------------------------------------------------
//Private prototypes
//------------------------------------------------------------------------------
void main(void);
void BootMain(void);
void LowVoltageCheck(void);
void InitializeSystem(void);
//Special "flash signature" located in the application program memory space (not
//part of the bootloader firmware program space). This flash signature is used
//to improve application recoverability/robustness, in the event the user unplugs
//the USB cable or AC power is lost during an erase/program/verify sequence.
#ifdef __XC8__
const unsigned int __at(APP_SIGNATURE_ADDRESS) FlashSignatureWord = APP_SIGNATURE_VALUE;
#else
#pragma romdata FLASH_SIG_SECTION = APP_SIGNATURE_ADDRESS
ROM unsigned int FlashSignatureWord = APP_SIGNATURE_VALUE;
#pragma code
#endif
//Special handling for modified linker script.
#ifndef __XC8__
//Note: This project uses a modified linker script, which does not include the
//c018i.o standard C initializer for C18 projects. Therefore, we must manually
//place a goto main() at the hardware reset vector.
#pragma code _entry_scn=0x000000 //Reset vector is at 0x00. Device begins executing code from 0x00 after a reset or POR event
void _entry (void)
{
_asm goto main _endasm
}
#pragma code
#endif
/******************************************************************************
* Function: void main(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: This is the first code that executes during boot up of
* the microcontroller. This code checks to see if execution
* should stay in the "bootloader" mode, or if it should jump
* into the "application" (non-bootloder) execution mode.
* No other unrelated code should be added to this function.
*
* Note: THIS FUNCTION EXECUTES PRIOR TO INITIALIZATION OF THE C
* STACK. NO C INITIALIZATION OF STATIC VARIABLES OR RESOURCES
* WILL OCCUR, PRIOR TO EXECUTING THIS FUNCTION. THEREFORE,
* THE CODE IN THIS FUNCTION MUST NOT CALL OTHER FUNCTIONS OR
* PERFORM ANY OPERATIONS THAT WILL REQUIRE C INITIALIZED
* BEHAVIOR.
*****************************************************************************/
void main(void)
{
//Assuming the I/O pin check entry method is enabled, check the I/O pin value
//to see if we should stay in bootloader mode, or jump to normal applicaiton
//execution mode.
/*#ifdef ENABLE_IO_PIN_CHECK_BOOTLOADER_ENTRY
//Check Bootload Mode Entry Condition from the I/O pin (ex: place a
//pushbutton and pull up resistor on the pin)
if(0)
{
//Before going to application image however, make sure the image
//is properly signed and is intact.
goto DoFlashSignatureCheck;
}
else
{
//User is pressing the pushbutton. We should stay in bootloader mode
BootMain();
}
#endif //#ifdef ENABLE_IO_PIN_CHECK_BOOTLOADER_ENTRY
*/
DoFlashSignatureCheck:
//Check if the application region flash signature is valid
if(*(ROM 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(*(ROM unsigned int*)REMAPPED_APPLICATION_RESET_VECTOR != 0xFFFF)
{
//Go ahead and jump out of bootloader mode into the application run mode
#ifdef __XC8__
#asm
goto REMAPPED_APPLICATION_RESET_VECTOR
#endasm
#else //Must be C18 instead
_asm goto REMAPPED_APPLICATION_RESET_VECTOR _endasm
#endif
}
}
//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.
//We should stay in bootloader mode
BootMain();
}//end UninitializedMain
/******************************************************************************
* Function: void BootMain(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: This is the main function for this bootloader mode firmware.
* if execution gets to this function, it is assumed that we
* want to stay in bootloader mode for now.
*
* Note: If adding code to this function, make sure to add it only
* after the C initializer like code at the top of this function.
* Additionally, code written in this project should not assume
* any variables or registers have been initialized by the C
* compiler (since they may not have been, if the user jumped
* from the application run mode into bootloader mode directly).
*****************************************************************************/
#ifdef __XC8__
void __at(0x30) BootMain(void)
#else
#pragma code BOOT_MAIN_SECTION=0x30
void BootMain(void)
#endif
{
//NOTE: The c018.o file is not included in the linker script for this project.
//The C initialization code in the c018.c (comes with C18 compiler in the src directory)
//file is instead modified and included here manually. This is done so as to provide
//a more convenient entry method into the bootloader firmware. Ordinarily the _entry_scn
//program code section starts at 0x00 and is created by the code of c018.o. However,
//the linker will not work if there is more than one section of code trying to occupy 0x00.
//Therefore, must not use the c018.o code, must instead manually include the useful code
//here instead.
//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;
//Initialize the C stack pointer, and other compiler managed items as
//normally done in the c018.c file (applicable when using C18 compiler)
#ifndef __XC8__
_asm
lfsr 1, _stack
lfsr 2, _stack
clrf TBLPTRU, 0
_endasm
#endif
//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(); //Some USB, I/O pins, and other initialization
//Execute main loop
while(1)
{
ClrWdt();
//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
}
#ifndef __XC8__
#pragma code
#endif
/******************************************************************************
* Function: static void InitializeSystem(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: InitializeSystem is a centralize initialization routine.
* All required USB initialization routines are called from
* here.
*
* User application initialization routine should also be
* called from here.
*
* Note: None
*****************************************************************************/
void InitializeSystem(void)
{
UserInit(); //Initialize bootloader application variables (see Bootxxxx.c file)
//Initialize USB module only after oscillator and other settings are compatible with USB operation
USBDeviceInit(); //Initializes USB module SFRs and firmware
//variables to known states.
}//end InitializeSystem
// ******************************************************************************************************
// ************** 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();
}
//Compiler mode and version check. This code needs to fit within the [0x000-0xFFF] program
//memory region that is reserved for use by the bootloader. However, if this
//code is built in XC8 Standard or Free mode (instead of PRO),
//the code may be too large to fit within the region, and a variety of linker
//error messages (ex: "can't find space") will result. Unfortunately these
//linker error messages can be cryptic to a user, so instead we add a deliberate
//#error to make a more human friendly error appear, in the event the wrong
//compiler mode is attempted to use to build this code. If you get this error
//message, please upgrade to the PRO compiler, and then use the mode
//(ex: build configuration --> XC8 compiler --> Option Categories: Optimizations --> Operation Mode: PRO)
//#ifdef __XC8__
// #if _HTC_EDITION_ < 2 //Check if PRO, Standard, or Free mode
// #error "This bootloader project must be built in PRO mode to fit within the reserved region. Double click this message for more details."
// #endif
//#endif
/** EOF main.c ***************************************************************/

View File

@@ -0,0 +1,425 @@
/*******************************************************************************
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_ */

View File

@@ -0,0 +1,56 @@
/*******************************************************************************
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 USB_H
#define USB_H
/*
* usb.h provides a centralize way to include all files
* required by Microchip USB Firmware.
*
* The order of inclusion is important.
* Dependency conflicts are resolved by the correct ordering.
*/
#include "typedefs.h"
#include "usb_config.h"
#include "usb_device.h"
#include "HardwareProfile.h"
#if defined(USB_USE_HID) // See usb_config.h
#include "usb_device_hid.h"
#endif
//These callback functions belong in your main.c (or equivalent) file. The USB
//stack will call these callback functions in response to specific USB bus events,
//such as entry into USB suspend mode, exit from USB suspend mode, and upon
//receiving the "set configuration" control tranfer request, which marks the end
//of the USB enumeration sequence and the start of normal application run mode (and
//where application related variables and endpoints may need to get (re)-initialized.
void USBCBSuspend(void);
void USBCBWakeFromSuspend(void);
void USBCBInitEP(uint8_t ConfigurationIndex);
void USBCBCheckOtherReq(void);
//API renaming wrapper functions
#define HIDTxHandleBusy(a) {mHIDTxIsBusy()}
#define HIDRxHandleBusy(a) {mHIDRxIsBusy()}
#endif //USB_H

View File

@@ -0,0 +1,74 @@
/*******************************************************************************
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 USBCFG_H
#define USBCFG_H
//----------------------------------------------------------------------------------------------------------
//User configurable options
//----------------------------------------------------------------------------------------------------------
//When defined/enabled, this option allows the boot up code to check an I/O pin
//(as defined by the sw2() macro in HardwareProfile.h), and if logic low, execution
//stays within the bootloader, allowing the user to update the firmware. If this
//option is not enabled, then the only method of entering the bootloader will
//be from the application firmware project, by executing a goto 0x001C operation.
//Enabling the I/O pin to enter the bootloader is recommended, since it is more
//robust/recoverable (compared to software only entry into the bootloader), in
//the event of a failed erase/program/verify operation, or an otherwise corrupted
//application firmware image is loaded.
#define ENABLE_IO_PIN_CHECK_BOOTLOADER_ENTRY //Uncomment if you wish to enable I/O pin entry method into bootloader mode
//Make sure proper sw2() macro definition is provided in HardwareProfile.h
//----------------------------------------------------------------------------------------------------------
//Other semi-configurable settings that tell the USB stack how to operate (but usually don't need changing)
//----------------------------------------------------------------------------------------------------------
#define MAX_EP_NUMBER 1 // EP0 and EP1 are the only EPs used in this application
#define MAX_NUM_INT 1 // For tracking Alternate Setting - make sure this matches the number of interfaces implemented in the device
#define EP0_BUFF_SIZE 8 // Valid Options: 8, 16, 32, or 64 bytes.
// There is little advantage in using
// more than 8 bytes on EP0 IN/OUT in most cases.
#define USB_MAX_NUM_CONFIG_DSC 1 // Number of configurations that this firmware implements
//#define ENABLE_CONTROL_TRANSFERS_WITH_OUT_DATA_STAGE //Commented out to save code size, since this bootloader firmware doesn't use OUT control transfers with data stage
#define CONFIG_DESC_TOTAL_LEN 41 //Make sure this matches the size of your configuration descriptor + all subordinate
//descriptors returned by the get descriptor(configuration) request
/* Parameter definitions are defined in usb_device.h */
#define MODE_PP _PPBM1 //This code is only written to support _PPBM1 mode only (ping pong on EP0 OUT buffer only). Do not change.
#define UCFG_VAL _PUEN|_TRINT|_FS|MODE_PP
//Device class and endpoint definitions
#define USB_USE_HID
/* HID */
#define HID_INTF_ID 0x00
#define HID_UEP UEP1
#define HID_BD_OUT ep1Bo
#define HID_INT_OUT_EP_SIZE 64
#define HID_BD_IN ep1Bi
#define HID_INT_IN_EP_SIZE 64
#define HID_NUM_OF_DSC 1 //Just the Report descriptor (no physical descriptor present)
#define HID_RPT01_SIZE 29 //Make sure this matches the size of your HID report descriptor
#endif //USBCFG_H

View File

@@ -0,0 +1,282 @@
/*******************************************************************************
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
*******************************************************************************/
/*********************************************************************
* -usb_descriptors.c-
* This file contains the USB descriptor information. It is used
* in conjunction with the usb_descriptors.h file. When a descriptor is added
* or removed from the main configuration descriptor, i.e. CFG01,
* the user must also change the descriptor structure defined in
* the usb_descriptors.h file. The structure is used to calculate the
* descriptor size, i.e. sizeof(CFG01).
*
* A typical configuration descriptor consists of:
* At least one configuration descriptor (USB_CFG_DSC)
* One or more interface descriptors (USB_INTF_DSC)
* One or more endpoint descriptors (USB_EP_DSC)
*
* Naming Convention:
* To resolve ambiguity, the naming convention are as followed:
* - USB_CFG_DSC type should be named cdxx, where xx is the
* configuration number. This number should match the actual
* index value of this configuration.
* - USB_INTF_DSC type should be named i<yy>a<zz>, where yy is the
* interface number and zz is the alternate interface number.
* - USB_EP_DSC type should be named ep<##><d>_i<yy>a<zz>, where
* ## is the endpoint number and d is the direction of transfer.
* The interface name should also be listed as a suffix to identify
* which interface does the endpoint belong to.
*
* Example:
* If a device has one configuration, two interfaces; interface 0
* has two endpoints (in and out), and interface 1 has one endpoint(in).
* Then the CFG01 structure in the usb_descriptors.h should be:
*
* #define CFG01 ROM struct \
* { USB_CFG_DSC cd01; \
* USB_INTF_DSC i00a00; \
* USB_EP_DSC ep01o_i00a00; \
* USB_EP_DSC ep01i_i00a00; \
* USB_INTF_DSC i01a00; \
* USB_EP_DSC ep02i_i01a00; \
* } cfg01
*
* Note the hierarchy of the descriptors above, it follows the USB
* specification requirement. All endpoints belonging to an interface
* should be listed immediately after that interface.
*
* -------------------------------------------------------------------
* Filling in the descriptor values in the usb_descriptors.c file:
* -------------------------------------------------------------------
* Most items should be self-explanatory, however, a few will be
* explained for clarification.
*
* [Configuration Descriptor(USB_CFG_DSC)]
* The configuration attribute must always have the _DEFAULT
* definition at the minimum. Additional options can be ORed
* to the _DEFAULT attribute. Available options are _SELF and _RWU.
* These definitions are defined in the usb_device.h file. The
* _SELF tells the USB host that this device is self-powered. The
* _RWU tells the USB host that this device supports Remote Wakeup.
*
* [Endpoint Descriptor(USB_EP_DSC)]
* Assume the following example:
* sizeof(USB_EP_DSC),DSC_EP,_EP01_OUT,_BULK,64,0x00
*
* The first two parameters are self-explanatory. They specify the
* length of this endpoint descriptor (7) and the descriptor type.
* The next parameter identifies the endpoint, the definitions are
* defined in usb_device.h and has the following naming
* convention:
* _EP<##>_<dir>
* where ## is the endpoint number and dir is the direction of
* transfer. The dir has the value of either 'OUT' or 'IN'.
* The next parameter identifies the type of the endpoint. Available
* options are _BULK, _INT, _ISO, and _CTRL. The _CTRL is not
* typically used because the default control transfer endpoint is
* not defined in the USB descriptors. When _ISO option is used,
* addition options can be ORed to _ISO. Example:
* _ISO|_AD|_FE
* This describes the endpoint as an isochronous pipe with adaptive
* and feedback attributes. See usb_device.h and the USB
* specification for details. The next parameter defines the size of
* the endpoint. The last parameter in the polling interval.
*
* -------------------------------------------------------------------
* Adding a USB String
* -------------------------------------------------------------------
* A string descriptor array should have the following format:
*
* ROM struct{uint8_t bLength;uint8_t bDscType;uint16_t string[size];}sdxxx={
* sizeof(sdxxx),DSC_STR,<text>};
*
* The above structure provides a means for the C compiler to
* calculate the length of string descriptor sdxxx, where xxx is the
* index number. The first two bytes of the descriptor are descriptor
* length and type. The rest <text> are string texts which must be
* in the unicode format. The unicode format is achieved by declaring
* each character as a word type. The whole text string is declared
* as a word array with the number of characters equals to <size>.
* <size> has to be manually counted and entered into the array
* declaration. Let's study this through an example:
* if the string is "USB" , then the string descriptor should be:
* (Using index 02)
* ROM struct{byte bLength;uint8_t bDscType;uint16_t string[3];}sd002={
* sizeof(sd002),DSC_STR,'U','S','B'};
*
* A USB project may have multiple strings and the firmware supports
* the management of multiple strings through a look-up table.
* The look-up table is defined as:
* ROM const unsigned char *ROM USB_SD_Ptr[]={&sd000,&sd001,&sd002};
*
* The above declaration has 3 strings, sd000, sd001, and sd002.
* Strings can be removed or added. sd000 is a specialized string
* descriptor. It defines the language code, usually this is
* US English (0x0409). The index of the string must match the index
* position of the USB_SD_Ptr array, &sd000 must be in position
* USB_SD_Ptr[0], &sd001 must be in position USB_SD_Ptr[1] and so on.
* The look-up table USB_SD_Ptr is used by the get string handler
* function in usb9.c.
*
* -------------------------------------------------------------------
*
* The look-up table scheme also applies to the configuration
* descriptor. A USB device may have multiple configuration
* descriptors, i.e. CFG01, CFG02, etc. To add a configuration
* descriptor, user must implement a structure similar to CFG01.
* The next step is to add the configuration descriptor name, i.e.
* cfg01, cfg02,.., to the look-up table USB_CD_Ptr. USB_CD_Ptr[0]
* is a dummy place holder since configuration 0 is the un-configured
* state according to the definition in the USB specification.
*
********************************************************************/
/** I N C L U D E S *************************************************/
#include "usb.h"
/** C O N S T A N T S ************************************************/
#ifndef __XC8__
#pragma romdata
#endif
/* Device Descriptor */
ROM USB_DEV_DSC device_dsc=
{
sizeof(USB_DEV_DSC), // Size of this descriptor in bytes
DSC_DEV, // DEVICE descriptor type
0x0200, // USB Spec Release Number in BCD format
0x00, // Class Code
0x00, // Subclass code
0x00, // Protocol code
EP0_BUFF_SIZE, // Max packet size for EP0, see usb_config.h
0x04D8, // Vendor ID: Microchip
0x003C, // Product ID: HID Bootloader
0x0101, // Device release number in BCD format
0x01, // Manufacturer string index
0x02, // Product string index
0x00, // Device serial number string index
0x01 // Number of possible configurations
};
/* Configuration 1 Descriptors */
ROM uint8_t CFG01[CONFIG_DESC_TOTAL_LEN]={
/* Configuration Descriptor */
sizeof(USB_CFG_DSC), // Size of this descriptor in bytes
DSC_CFG, // CONFIGURATION descriptor type
(uint8_t)CONFIG_DESC_TOTAL_LEN, // Total length of data for this cfg - LSB
(uint8_t)(CONFIG_DESC_TOTAL_LEN>>8), // Total length of data for this cfg - MSB
1, // Number of interfaces in this cfg
1, // Index value of this configuration
0, // Configuration string index
_DEFAULT, // Attributes, see usb_device.h
50, // Max power consumption (2X mA)
/* Interface Descriptor */
sizeof(USB_INTF_DSC), // Size of this descriptor in bytes
DSC_INTF, // INTERFACE descriptor type
0, // Interface Number
0, // Alternate Setting Number
2, // Number of endpoints in this intf
HID_INTF, // Class code
0, // Subclass code, no subclass
0, // Protocol code, no protocol
0, // Interface string index
/* HID Class-Specific Descriptor */
sizeof(USB_HID_DSC), // Size of this descriptor in bytes
DSC_HID, // HID descriptor type
0x11, // HID Spec Release Number in BCD format (0x0111 = v1.11) - LSB
0x01, // HID Spec Release Number in BCD format (0x0111 = v1.11) - MSB
0x00, // Country Code (0x00 for Not supported)
HID_NUM_OF_DSC, // Number of class descriptors, see usb_config.h
DSC_RPT, // Report descriptor type
(uint8_t)HID_RPT01_SIZE, // Size of the report descriptor - LSB
(uint8_t)((uint16_t)HID_RPT01_SIZE >> 8), // Size of the report descriptor - MSB
/* Endpoint Descriptor */
sizeof(USB_EP_DSC), //Endpoint descriptor size
DSC_EP, //Type of descriptor (endpoint)
_EP01_IN, //Endpoint number + direction
_INT, //Endpoint transfer type implemented
HID_INT_IN_EP_SIZE, //LSB - endpoint size
0x00, //MSB - endpoint size
0x01, //bInterval
/* Endpoint Descriptor */
sizeof(USB_EP_DSC), //Endpoint descriptor size
DSC_EP, //Type of descriptor (endpoint)
_EP01_OUT, //Endpoint number + direction
_INT, //Endpoint transfer type implemented
HID_INT_OUT_EP_SIZE, //LSB - endpoint size
0x00, //MSB - endpoint size
0x01 //bInterval
};
ROM struct{uint8_t bLength;uint8_t bDscType;uint16_t string[1];}sd000={
sizeof(sd000),DSC_STR,0x0409};
ROM struct{uint8_t bLength;uint8_t bDscType;uint16_t string[25];}sd001={
sizeof(sd001),DSC_STR,
'M','i','c','r','o','c','h','i','p',' ',
'T','e','c','h','n','o','l','o','g','y',' ','I','n','c','.'};
ROM struct{uint8_t bLength;uint8_t bDscType;uint16_t string[18];}sd002={
sizeof(sd002),DSC_STR,
'H','I','D',' ','U','S','B',' ','B','o','o',
't','l','o','a','d','e','r'};
ROM uint8_t hid_rpt01[HID_RPT01_SIZE]=
// First byte in each row is the "item". First byte's two least significant
// bits are the number of data bytes that follow, but encoded (0=0, 1=1, 2=2, 3=4 bytes).
// bSize should match number of bytes that follow, or REPORT descriptor parser won't work. The bytes
// that follow in each item line are data bytes
{
0x06, 0x00, 0xFF, // Usage Page = 0xFF00 (Vendor Defined Page 1)
0x09, 0x01, // Usage (Vendor Usage 1)
0xA1, 0x01, // Collection (Application)
0x19, 0x01, // Usage Minimum
0x29, 0x40, // Usage Maximum //64 input usages total (0x01 to 0x40)
0x15, 0x00, // Logical Minimum (data bytes in the report may have minimum value = 0x00)
0x26, 0xFF, 0x00, // Logical Maximum (data bytes in the report may have maximum value = 0x00FF = unsigned 255)
0x75, 0x08, // Report Size: 8-bit field size
0x95, 0x40, // Report Count: Make sixty-four 8-bit fields (the next time the parser hits an "Input", "Output", or "Feature" item)
0x81, 0x00, // Input (Data, Array, Abs): Instantiates input packet fields based on the above report size, count, logical min/max, and usage.
0x19, 0x01, // Usage Minimum
0x29, 0x40, // Usage Maximum //64 output usages total (0x01 to 0x40)
0x91, 0x00, // Output (Data, Array, Abs): Instantiates output packet fields. Uses same report size and count as "Input" fields, since nothing new/different was specified to the parser since the "Input" item.
0xC0 // End Collection
};
ROM unsigned char* ROM USB_SD_Ptr[]=
{
(ROM const unsigned char *ROM)&sd000,
(ROM const unsigned char *ROM)&sd001,
(ROM const unsigned char *ROM)&sd002
};
#ifndef __XC8__
#pragma code
#endif
/** EOF usb_descriptors.c ****************************************************/

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,699 @@
/*******************************************************************************
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 _USB_DEVICE_H
#define _USB_DEVICE_H
/** I N C L U D E S **********************************************************/
#include "usb.h"
//Hardware abstraction. The USBIF and USBIE bits reside in different registers
//on different USB microcontrollers.
#if defined(__18F45K50) || defined(__18F25K50) || defined(__18F24K50) || defined(__18LF45K50) || defined(__18LF25K50) || defined(__18LF24K50)
#define USBIF_FLAG PIR3bits.USBIF
#define USBIE_BIT PIE3bits.USBIE
#else
#define USBIF_FLAG PIR2bits.USBIF
#define USBIE_BIT PIE2bits.USBIE
#endif
/** D E F I N I T I O N S ****************************************************/
/******************************************************************************
* Standard Request Codes
* USB 2.0 Spec Ref Table 9-4
*****************************************************************************/
#define GET_STATUS 0
#define CLR_FEATURE 1
#define SET_FEATURE 3
#define SET_ADR 5
#define GET_DSC 6
#define SET_DSC 7
#define GET_CFG 8
#define SET_CFG 9
#define GET_INTF 10
#define SET_INTF 11
#define SYNCH_FRAME 12
/* Standard Feature Selectors */
#define DEVICE_REMOTE_WAKEUP 0x01
#define ENDPOINT_HALT 0x00
/* UCFG Initialization Parameters */
#define _PPBM0 0x00 // Pingpong Buffer Mode 0 - ping pong bufferring disabled
#define _PPBM1 0x01 // Pingpong Buffer Mode 1 - ping pong on EP0 OUT only
#define _PPBM2 0x02 // Pingpong Buffer Mode 2 - ping pong on all endpoints
#define _LS 0x00 // Use Low-Speed USB Mode
#define _FS 0x04 // Use Full-Speed USB Mode
#define _TRINT 0x00 // Use internal transceiver
#define _TREXT 0x08 // Use external transceiver
#define _PUEN 0x10 // Use internal pull-up resistor
#define _OEMON 0x40 // Use SIE output indicator
#define _UTEYE 0x80 // Use Eye-Pattern test
/* UEPn Initialization Parameters */
#define EP_CTRL 0x06 // Cfg Control pipe for this ep
#define EP_OUT 0x0C // Cfg OUT only pipe for this ep
#define EP_IN 0x0A // Cfg IN only pipe for this ep
#define EP_OUT_IN 0x0E // Cfg both OUT & IN pipes for this ep
#define HSHK_EN 0x10 // Enable handshake packet
// Handshake should be disable for isoch
/******************************************************************************
* USB - PICmicro Endpoint Definitions
* PICmicro EP Address Format: X:EP3:EP2:EP1:EP0:DIR:PPBI:X
* This is used when checking the value read from USTAT
*
* NOTE: These definitions are not used in the descriptors.
* EP addresses used in the descriptors have different format and
* are defined in: usb_device.h
*****************************************************************************/
#define OUT 0
#define IN 1
#define PIC_EP_NUM_MASK 0b01111000
#define PIC_EP_DIR_MASK 0b00000100
#define EP00_OUT ((0x00<<3)|(OUT<<2))
#define EP00_IN ((0x00<<3)|(IN<<2))
#define EP01_OUT ((0x01<<3)|(OUT<<2))
#define EP01_IN ((0x01<<3)|(IN<<2))
#define EP02_OUT ((0x02<<3)|(OUT<<2))
#define EP02_IN ((0x02<<3)|(IN<<2))
#define EP03_OUT ((0x03<<3)|(OUT<<2))
#define EP03_IN ((0x03<<3)|(IN<<2))
#define EP04_OUT ((0x04<<3)|(OUT<<2))
#define EP04_IN ((0x04<<3)|(IN<<2))
#define EP05_OUT ((0x05<<3)|(OUT<<2))
#define EP05_IN ((0x05<<3)|(IN<<2))
#define EP06_OUT ((0x06<<3)|(OUT<<2))
#define EP06_IN ((0x06<<3)|(IN<<2))
#define EP07_OUT ((0x07<<3)|(OUT<<2))
#define EP07_IN ((0x07<<3)|(IN<<2))
#define EP08_OUT ((0x08<<3)|(OUT<<2))
#define EP08_IN ((0x08<<3)|(IN<<2))
#define EP09_OUT ((0x09<<3)|(OUT<<2))
#define EP09_IN ((0x09<<3)|(IN<<2))
#define EP10_OUT ((0x0A<<3)|(OUT<<2))
#define EP10_IN ((0x0A<<3)|(IN<<2))
#define EP11_OUT ((0x0B<<3)|(OUT<<2))
#define EP11_IN ((0x0B<<3)|(IN<<2))
#define EP12_OUT ((0x0C<<3)|(OUT<<2))
#define EP12_IN ((0x0C<<3)|(IN<<2))
#define EP13_OUT ((0x0D<<3)|(OUT<<2))
#define EP13_IN ((0x0D<<3)|(IN<<2))
#define EP14_OUT ((0x0E<<3)|(OUT<<2))
#define EP14_IN ((0x0E<<3)|(IN<<2))
#define EP15_OUT ((0x0F<<3)|(OUT<<2))
#define EP15_IN ((0x0F<<3)|(IN<<2))
#define EP0_OUT_EVEN_BDT_INDEX 0
#define EP0_OUT_ODD_BDT_INDEX 1
/* Buffer Descriptor Status Register Initialization Parameters */
#define _BSTALL 0x04 //Buffer Stall enable
#define _DTSEN 0x08 //Data Toggle Synch enable
#define _INCDIS 0x10 //Address increment disable
#define _KEN 0x20 //SIE keeps buff descriptors enable
#define _DAT0 0x00 //DATA0 packet expected next
#define _DAT1 0x40 //DATA1 packet expected next
#define _DTSMASK 0x40 //DTS Mask
#define _USIE 0x80 //SIE owns buffer
#define _UCPU 0x00 //CPU owns buffer
/* USB Device States - To be used with [byte usb_device_state] */
#define DETACHED_STATE 0
#define ATTACHED_STATE 1
#define POWERED_STATE 2
#define DEFAULT_STATE 3
#define ADR_PENDING_STATE 4
#define ADDRESS_STATE 5
#define CONFIGURED_STATE 6
/* Memory Types for Control Transfer - used in USB_DEVICE_STATUS */
#define _RAM 0
#define _ROM 1
/* Descriptor Types */
#define DSC_DEV 0x01
#define DSC_CFG 0x02
#define DSC_STR 0x03
#define DSC_INTF 0x04
#define DSC_EP 0x05
/******************************************************************************
* USB Endpoint Definitions
* USB Standard EP Address Format: DIR:X:X:X:EP3:EP2:EP1:EP0
* This is used in the descriptors. See usb_descriptors.c
*
* NOTE: Do not use these values for checking against USTAT.
* To check against USTAT, use values defined in "usb_device.h"
*****************************************************************************/
#define _EP01_OUT 0x01
#define _EP01_IN 0x81
#define _EP02_OUT 0x02
#define _EP02_IN 0x82
#define _EP03_OUT 0x03
#define _EP03_IN 0x83
#define _EP04_OUT 0x04
#define _EP04_IN 0x84
#define _EP05_OUT 0x05
#define _EP05_IN 0x85
#define _EP06_OUT 0x06
#define _EP06_IN 0x86
#define _EP07_OUT 0x07
#define _EP07_IN 0x87
#define _EP08_OUT 0x08
#define _EP08_IN 0x88
#define _EP09_OUT 0x09
#define _EP09_IN 0x89
#define _EP10_OUT 0x0A
#define _EP10_IN 0x8A
#define _EP11_OUT 0x0B
#define _EP11_IN 0x8B
#define _EP12_OUT 0x0C
#define _EP12_IN 0x8C
#define _EP13_OUT 0x0D
#define _EP13_IN 0x8D
#define _EP14_OUT 0x0E
#define _EP14_IN 0x8E
#define _EP15_OUT 0x0F
#define _EP15_IN 0x8F
/* Configuration Attributes */
#define _DEFAULT 0x01<<7 //Default Value (Bit 7 is set)
#define _SELF 0x01<<6 //Self-powered (Supports if set)
#define _RWU 0x01<<5 //Remote Wakeup (Supports if set)
/* Endpoint Transfer Type */
#define _CTRL 0x00 //Control Transfer
#define _ISO 0x01 //Isochronous Transfer
#define _BULK 0x02 //Bulk Transfer
#define _INT 0x03 //Interrupt Transfer
/* Isochronous Endpoint Synchronization Type */
#define _NS 0x00<<2 //No Synchronization
#define _AS 0x01<<2 //Asynchronous
#define _AD 0x02<<2 //Adaptive
#define _SY 0x03<<2 //Synchronous
/* Isochronous Endpoint Usage Type */
#define _DE 0x00<<4 //Data endpoint
#define _FE 0x01<<4 //Feedback endpoint
#define _IE 0x02<<4 //Implicit feedback Data endpoint
/** T Y P E S ****************************************************************/
typedef union _USB_DEVICE_STATUS
{
uint8_t _byte;
struct
{
unsigned RemoteWakeup:1;// [0]Disabled [1]Enabled: See usb_device.c,usb9.c
unsigned ctrl_trf_mem:1;// [0]RAM [1]ROM
};
} USB_DEVICE_STATUS;
typedef union _BD_STAT
{
uint8_t _byte;
struct{
unsigned BC8:1;
unsigned BC9:1;
unsigned BSTALL:1; //Buffer Stall Enable
unsigned DTSEN:1; //Data Toggle Synch Enable
unsigned INCDIS:1; //Address Increment Disable
unsigned KEN:1; //BD Keep Enable
unsigned DTS:1; //Data Toggle Synch Value
unsigned UOWN:1; //USB Ownership
};
struct{
unsigned :2;
unsigned PID0:1;
unsigned PID1:1;
unsigned PID2:1;
unsigned PID3:1;
unsigned :2;
};
struct{
unsigned :2;
unsigned PID:4; //Packet Identifier
unsigned :2;
};
} BD_STAT; //Buffer Descriptor Status Register
typedef union _BDT
{
struct
{
BD_STAT Stat;
uint8_t Cnt;
uint8_t ADRL; //Buffer Address Low
uint8_t ADRH; //Buffer Address High
};
struct
{
unsigned :8;
unsigned :8;
uint8_t* ADR; //Buffer Address
};
} BDT; //Buffer Descriptor Table
/******************************************************************************
* CTRL_TRF_SETUP:
*
* Every setup packet has 8 bytes.
* However, the buffer size has to equal the EP0_BUFF_SIZE value specified
* in usb_config.h
* The value of EP0_BUFF_SIZE can be 8, 16, 32, or 64.
*
* First 8 bytes are defined to be directly addressable to improve speed
* and reduce code size.
* Bytes beyond the 8th byte have to be accessed using indirect addressing.
*****************************************************************************/
typedef union _CTRL_TRF_SETUP
{
/** Array for indirect addressing ****************************************/
struct
{
uint8_t _byte[EP0_BUFF_SIZE];
};
/** Standard Device Requests *********************************************/
struct
{
uint8_t bmRequestType;
uint8_t bRequest;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
};
struct
{
unsigned :8;
unsigned :8;
WORD_VAL W_Value;
WORD_VAL W_Index;
WORD_VAL W_Length;
};
struct
{
unsigned Recipient:5; //Device,Interface,Endpoint,Other
unsigned RequestType:2; //Standard,Class,Vendor,Reserved
unsigned DataDir:1; //Host-to-device,Device-to-host
unsigned :8;
uint8_t bFeature; //DEVICE_REMOTE_WAKEUP,ENDPOINT_HALT
unsigned :8;
unsigned :8;
unsigned :8;
unsigned :8;
unsigned :8;
};
struct
{
unsigned :8;
unsigned :8;
uint8_t bDscIndex; //For Configuration and String DSC Only
uint8_t bDscType; //Device,Configuration,String
uint16_t wLangID; //Language ID
unsigned :8;
unsigned :8;
};
struct
{
unsigned :8;
unsigned :8;
uint8_t bDevADR; //Device Address 0-127
uint8_t bDevADRH; //Must equal zero
unsigned :8;
unsigned :8;
unsigned :8;
unsigned :8;
};
struct
{
unsigned :8;
unsigned :8;
uint8_t bCfgValue; //Configuration Value 0-255
uint8_t bCfgRSD; //Must equal zero (Reserved)
unsigned :8;
unsigned :8;
unsigned :8;
unsigned :8;
};
struct
{
unsigned :8;
unsigned :8;
uint8_t bAltID; //Alternate Setting Value 0-255
uint8_t bAltID_H; //Must equal zero
uint8_t bIntfID; //Interface Number Value 0-255
uint8_t bIntfID_H; //Must equal zero
unsigned :8;
unsigned :8;
};
struct
{
unsigned :8;
unsigned :8;
unsigned :8;
unsigned :8;
uint8_t bEPID; //Endpoint ID (Number & Direction)
uint8_t bEPID_H; //Must equal zero
unsigned :8;
unsigned :8;
};
struct
{
unsigned :8;
unsigned :8;
unsigned :8;
unsigned :8;
unsigned EPNum:4; //Endpoint Number 0-15
unsigned :3;
unsigned EPDir:1; //Endpoint Direction: 0-OUT, 1-IN
unsigned :8;
unsigned :8;
unsigned :8;
};
/** End: Standard Device Requests ****************************************/
} CTRL_TRF_SETUP;
/******************************************************************************
* CTRL_TRF_DATA:
*
* Buffer size has to equal the EP0_BUFF_SIZE value specified
* in usb_config.h
* The value of EP0_BUFF_SIZE can be 8, 16, 32, or 64.
*
* First 8 bytes are defined to be directly addressable to improve speed
* and reduce code size.
* Bytes beyond the 8th byte have to be accessed using indirect addressing.
*****************************************************************************/
typedef union _CTRL_TRF_DATA
{
/** Array for indirect addressing ****************************************/
struct
{
uint8_t _byte[EP0_BUFF_SIZE];
};
/** First 8-byte direct addressing ***************************************/
struct
{
uint8_t _byte0;
uint8_t _byte1;
uint8_t _byte2;
uint8_t _byte3;
uint8_t _byte4;
uint8_t _byte5;
uint8_t _byte6;
uint8_t _byte7;
};
struct
{
uint16_t _word0;
uint16_t _word1;
uint16_t _word2;
uint16_t _word3;
};
} CTRL_TRF_DATA;
/******************************************************************************
* USB Device Descriptor Structure
*****************************************************************************/
typedef struct _USB_DEV_DSC
{
uint8_t bLength; uint8_t bDscType; uint16_t bcdUSB;
uint8_t bDevCls; uint8_t bDevSubCls; uint8_t bDevProtocol;
uint8_t bMaxPktSize0; uint16_t idVendor; uint16_t idProduct;
uint16_t bcdDevice; uint8_t iMFR; uint8_t iProduct;
uint8_t iSerialNum; uint8_t bNumCfg;
} USB_DEV_DSC;
/******************************************************************************
* USB Configuration Descriptor Structure
*****************************************************************************/
typedef struct _USB_CFG_DSC
{
uint8_t bLength; uint8_t bDscType; uint16_t wTotalLength;
uint8_t bNumIntf; uint8_t bCfgValue; uint8_t iCfg;
uint8_t bmAttributes; uint8_t bMaxPower;
} USB_CFG_DSC;
/******************************************************************************
* USB Interface Descriptor Structure
*****************************************************************************/
typedef struct _USB_INTF_DSC
{
uint8_t bLength; uint8_t bDscType; uint8_t bIntfNum;
uint8_t bAltSetting; uint8_t bNumEPs; uint8_t bIntfCls;
uint8_t bIntfSubCls; uint8_t bIntfProtocol; uint8_t iIntf;
} USB_INTF_DSC;
/******************************************************************************
* USB Endpoint Descriptor Structure
*****************************************************************************/
typedef struct _USB_EP_DSC
{
uint8_t bLength; uint8_t bDscType; uint8_t bEPAdr;
uint8_t bmAttributes; uint16_t wMaxPktSize; uint8_t bInterval;
} USB_EP_DSC;
/******************************************************************************
* Macro: void mInitializeUSBDriver(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: Configures the USB module, definition of UCFG_VAL can be
* found in usb_config.h
*
* This register determines: USB Speed, On-chip pull-up
* resistor selection, On-chip tranceiver selection, bus
* eye pattern generation mode, Ping-pong buffering mode
* selection.
*
* Note: None
*****************************************************************************/
#define mInitializeUSBDriver() {UCFG = UCFG_VAL; \
usb_device_state = DETACHED_STATE; \
USBProtocolResetHandler();}
/******************************************************************************
* Macro: void mDisableEP1to15(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: This macro disables all endpoints except EP0.
* This macro should be called when the host sends a RESET
* signal or a SET_CONFIGURATION request.
*
* Note: None
*****************************************************************************/
//#if defined(__18F14K50) || defined(__18F13K50) || defined(__18LF14K50) || defined(__18LF13K50)
// #define mDisableEP1to15() ClearArray((uint8_t*)&UEP1,7);
//#else
// #define mDisableEP1to15() ClearArray((uint8_t*)&UEP1,15);
//#endif
//Using below instead to save code space. Dedicated bootloader project,
//will never use UEP3+, therefore no need to really mess with those registers
#define mDisableEP1to7() UEP1=0x00;UEP2=0x00;UEP3=0x00;\
UEP4=0x00;UEP5=0x00;UEP6=0x00;UEP7=0x00;
// UEP8=0x00;UEP9=0x00;UEP10=0x00;UEP11=0x00;\
// UEP12=0x00;UEP13=0x00;UEP14=0x00;UEP15=0x00;
/******************************************************************************
* Macro: void mUSBBufferReady(buffer_dsc)
*
* PreCondition: IN Endpoint: Buffer is loaded and ready to be sent.
* OUT Endpoint: Buffer is free to be written to by SIE.
*
* Input: byte buffer_dsc: Root name of the buffer descriptor group.
* i.e. ep0Bo, ep1Bi, ... Declared in usbmmap.c
* Names can be remapped for readability, see examples in
* usb_config.h (#define HID_BD_OUT ep1Bo)
*
* Output: None
*
* Side Effects: None
*
* Overview: This macro should be called each time after:
* 1. A non-EP0 IN endpoint buffer is populated with data.
* 2. A non-EP0 OUT endpoint buffer is read.
* This macro turns the buffer ownership to SIE for servicing.
* It also toggles the DTS bit for synchronization.
*
* Note: None
*****************************************************************************/
#define mUSBBufferReady(buffer_dsc) \
{ \
buffer_dsc.Stat._byte &= _DTSMASK; /* Save only DTS bit */ \
buffer_dsc.Stat.DTS = !buffer_dsc.Stat.DTS; /* Toggle DTS bit */ \
buffer_dsc.Stat._byte |= _DTSEN; /* Configure other settings */ \
buffer_dsc.Stat._byte |= _USIE; /* Turn ownership to SIE */ \
}
/** D E F I N I T I O N S ****************************************************/
/*
* MUID = Microchip USB Class ID
* Used to identify which of the USB classes owns the current
* session of control transfer over EP0
*/
#define MUID_NULL 0
#define MUID_USB9 1
#define MUID_HID 2
#define MUID_CDC 3
/* Control Transfer States */
#define WAIT_SETUP 0
#define CTRL_TRF_TX 1
#define CTRL_TRF_RX 2
/* Short Packet States - Used by Control Transfer Read - CTRL_TRF_TX */
#define SHORT_PKT_NOT_SENT 0
#define SHORT_PKT_PENDING 1
#define SHORT_PKT_SENT 2
/* USB PID: Token Types - See chapter 8 in the USB specification */
#define SETUP_TOKEN 0b00001101
#define OUT_TOKEN 0b00000001
#define IN_TOKEN 0b00001001
/* bmRequestType Definitions */
#define HOST_TO_DEV 0
#define DEV_TO_HOST 1
#define STANDARD 0x00
#define CLASS 0x01
#define VENDOR 0x02
#define RCPT_DEV 0
#define RCPT_INTF 1
#define RCPT_EP 2
#define RCPT_OTH 3
/** E X T E R N S ************************************************************/
extern uint8_t ctrl_trf_session_owner;
extern POINTER pSrc;
extern POINTER pDst;
extern WORD_VAL wCount;
extern uint8_t usb_device_state;
extern USB_DEVICE_STATUS usb_stat;
extern uint8_t usb_active_cfg;
extern uint8_t usb_alt_intf[MAX_NUM_INT];
extern volatile BDT ep0Bo; //Endpoint #0 BD Out
extern volatile BDT ep0Bi; //Endpoint #0 BD In
extern volatile BDT ep1Bo; //Endpoint #1 BD Out
extern volatile BDT ep1Bi; //Endpoint #1 BD In
extern volatile BDT ep2Bo; //Endpoint #2 BD Out
extern volatile BDT ep2Bi; //Endpoint #2 BD In
extern volatile BDT ep3Bo; //Endpoint #3 BD Out
extern volatile BDT ep3Bi; //Endpoint #3 BD In
extern volatile BDT ep4Bo; //Endpoint #4 BD Out
extern volatile BDT ep4Bi; //Endpoint #4 BD In
extern volatile BDT ep5Bo; //Endpoint #5 BD Out
extern volatile BDT ep5Bi; //Endpoint #5 BD In
extern volatile BDT ep6Bo; //Endpoint #6 BD Out
extern volatile BDT ep6Bi; //Endpoint #6 BD In
extern volatile BDT ep7Bo; //Endpoint #7 BD Out
extern volatile BDT ep7Bi; //Endpoint #7 BD In
extern volatile BDT ep8Bo; //Endpoint #8 BD Out
extern volatile BDT ep8Bi; //Endpoint #8 BD In
extern volatile BDT ep9Bo; //Endpoint #9 BD Out
extern volatile BDT ep9Bi; //Endpoint #9 BD In
extern volatile BDT ep10Bo; //Endpoint #10 BD Out
extern volatile BDT ep10Bi; //Endpoint #10 BD In
extern volatile BDT ep11Bo; //Endpoint #11 BD Out
extern volatile BDT ep11Bi; //Endpoint #11 BD In
extern volatile BDT ep12Bo; //Endpoint #12 BD Out
extern volatile BDT ep12Bi; //Endpoint #12 BD In
extern volatile BDT ep13Bo; //Endpoint #13 BD Out
extern volatile BDT ep13Bi; //Endpoint #13 BD In
extern volatile BDT ep14Bo; //Endpoint #14 BD Out
extern volatile BDT ep14Bi; //Endpoint #14 BD In
extern volatile BDT ep15Bo; //Endpoint #15 BD Out
extern volatile BDT ep15Bi; //Endpoint #15 BD In
extern CTRL_TRF_SETUP SetupPkt;
volatile extern CTRL_TRF_DATA CtrlTrfData;
#if defined(USB_USE_HID)
extern volatile unsigned char hid_report_out[HID_INT_OUT_EP_SIZE];
extern volatile unsigned char hid_report_in[HID_INT_IN_EP_SIZE];
#endif
extern ROM USB_DEV_DSC device_dsc;
extern ROM uint8_t CFG01[CONFIG_DESC_TOTAL_LEN];
extern ROM const unsigned char *ROM USB_CD_Ptr[];
extern ROM unsigned char* ROM USB_SD_Ptr[];
/** P U B L I C P R O T O T Y P E S *****************************************/
void USBDeviceInit(void);
void USBCheckBusStatus(void);
void USBSoftAttach(void);
void USBSoftDetach(void);
void USBDeviceTasks(void);
void USBDisableWithLongDelay(void);
void DelayRoutine(unsigned int DelayAmount);
void ClearWatchdog(void);
#define USBGetDeviceState() usb_device_state
#define USBIsDeviceSuspended() UCONbits.SUSPND
#endif //_USB_DEVICE_H

View File

@@ -0,0 +1,302 @@
/*******************************************************************************
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
*******************************************************************************/
/** I N C L U D E S **********************************************************/
#include "usb.h"
#ifdef USB_USE_HID
/** V A R I A B L E S ********************************************************/
#ifndef __XC8__
#pragma udata
#endif
uint8_t idle_rate;
uint8_t active_protocol; // [0] Boot Protocol [1] Report Protocol
uint8_t hid_rpt_rx_len;
/** P R I V A T E P R O T O T Y P E S ***************************************/
void HIDGetReportHandler(void);
void HIDSetReportHandler(void);
/** D E C L A R A T I O N S **************************************************/
#ifndef __XC8__
#pragma code
#endif
/** C L A S S S P E C I F I C R E Q ****************************************/
/******************************************************************************
* Function: void USBCheckHIDRequest(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: This routine checks the setup data packet to see if it
* knows how to handle it
*
* Note: None
*****************************************************************************/
void USBCheckHIDRequest(void)
{
if(SetupPkt.Recipient != RCPT_INTF) return;
if(SetupPkt.bIntfID != HID_INTF_ID) return;
/*
* There are two standard requests that hid.c may support.
* 1. GET_DSC(DSC_HID,DSC_RPT,DSC_PHY);
* 2. SET_DSC(DSC_HID,DSC_RPT,DSC_PHY);
*/
if(SetupPkt.bRequest == GET_DSC)
{
switch(SetupPkt.bDscType)
{
case DSC_HID:
ctrl_trf_session_owner = MUID_HID;
pSrc.bRom = &CFG01[18]; //18 is a magic number (offset from start of configuration descriptor, to the start of the HID descriptor)
wCount.Val = sizeof(USB_HID_DSC);
break;
case DSC_RPT:
ctrl_trf_session_owner = MUID_HID;
mUSBGetHIDRptDscAdr(pSrc.bRom); // See usb_config.h
mUSBGetHIDRptDscSize(wCount.Val); // See usb_config.h
break;
case DSC_PHY:
// ctrl_trf_session_owner = MUID_HID;
break;
}//end switch(SetupPkt.bDscType)
usb_stat.ctrl_trf_mem = _ROM;
}//end if(SetupPkt.bRequest == GET_DSC)
if(SetupPkt.RequestType != CLASS) return;
switch(SetupPkt.bRequest)
{
case GET_REPORT:
HIDGetReportHandler();
break;
case SET_REPORT:
HIDSetReportHandler();
break;
case GET_IDLE:
ctrl_trf_session_owner = MUID_HID;
pSrc.bRam = (uint8_t*)&idle_rate; // Set source
usb_stat.ctrl_trf_mem = _RAM; // Set memory type
wCount.v[0] = 1; // Set data count
break;
case SET_IDLE:
ctrl_trf_session_owner = MUID_HID;
//idle_rate = MSB(SetupPkt.W_Value);
idle_rate = SetupPkt.W_Value.v[1];
break;
case GET_PROTOCOL:
ctrl_trf_session_owner = MUID_HID;
pSrc.bRam = (uint8_t*)&active_protocol;// Set source
usb_stat.ctrl_trf_mem = _RAM; // Set memory type
wCount.v[0] = 1; // Set data count
break;
case SET_PROTOCOL:
ctrl_trf_session_owner = MUID_HID;
//active_protocol = LSB(SetupPkt.W_Value);
active_protocol = SetupPkt.W_Value.v[0];
break;
}//end switch(SetupPkt.bRequest)
}//end USBCheckHIDRequest
void HIDGetReportHandler(void)
{
// ctrl_trf_session_owner = MUID_HID;
}//end HIDGetReportHandler
void HIDSetReportHandler(void)
{
// ctrl_trf_session_owner = MUID_HID;
// pDst.bRam = (byte*)&hid_report_out;
}//end HIDSetReportHandler
/** U S E R A P I ***********************************************************/
/******************************************************************************
* Function: void HIDInitEP(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: HIDInitEP initializes HID endpoints, buffer descriptors,
* internal state-machine, and variables.
* It should be called after the USB host has sent out a
* SET_CONFIGURATION request.
* See USBStdSetCfgHandler() in usb9.c for examples.
*
* Note: None
*****************************************************************************/
void HIDInitEP(void)
{
hid_rpt_rx_len =0;
HID_UEP = EP_OUT_IN|HSHK_EN; // Enable 2 data pipes
//Arm the OUT interrupt endpoint so the host can send the first packet of data.
HID_BD_OUT.Cnt = sizeof(hid_report_out); // Set buffer size
HID_BD_OUT.ADR = (uint8_t*)&hid_report_out; // Set buffer address
HID_BD_OUT.Stat._byte = _DAT0|_DTSEN; // Set status
HID_BD_OUT.Stat._byte |= _USIE;
/*
* Do not have to init Cnt of IN pipes here.
* Reason: Number of bytes to send to the host
* varies from one transaction to
* another. Cnt should equal the exact
* number of bytes to transmit for
* a given IN transaction.
* This number of bytes will only
* be known right before the data is
* sent.
*/
HID_BD_IN.ADR = (uint8_t*)&hid_report_in; // Set buffer address
HID_BD_IN.Stat._byte = _UCPU|_DAT1; // Set status
}//end HIDInitEP
/******************************************************************************
* Function: void HIDTxReport(char *buffer, byte len)
*
* PreCondition: mHIDTxIsBusy() must return false.
*
* Value of 'len' must be equal to or smaller than
* HID_INT_IN_EP_SIZE
* For an interrupt endpoint, the largest buffer size is
* 64 bytes.
*
* Input: buffer : Pointer to the starting location of data bytes
* len : Number of bytes to be transferred
*
* Output: None
*
* Side Effects: None
*
* Overview: Use this macro to transfer data located in data memory.
*
* Remember: mHIDTxIsBusy() must return false before user
* can call this function.
* Unexpected behavior will occur if this function is called
* when mHIDTxIsBusy() == 0
*
* Typical Usage:
* if(!mHIDTxIsBusy())
* HIDTxReport(buffer, 3);
*
* Note: None
*****************************************************************************/
void HIDTxReport(char *buffer, uint8_t len)
{
uint8_t i;
/*
* Value of len should be equal to or smaller than HID_INT_IN_EP_SIZE.
* This check forces the value of len to meet the precondition.
*/
if(len > HID_INT_IN_EP_SIZE)
len = HID_INT_IN_EP_SIZE;
/*
* Copy data from user's buffer to a USB module accessible RAM packet buffer
*/
for (i = 0; i < len; i++)
hid_report_in[i] = buffer[i];
HID_BD_IN.Cnt = len;
mUSBBufferReady(HID_BD_IN);
}//end HIDTxReport
/******************************************************************************
* Function: byte HIDRxReport(char *buffer, byte len)
*
* PreCondition: Value of input argument 'len' should be smaller than the
* maximum endpoint size responsible for receiving report
* data from USB host for HID class.
* Input argument 'buffer' should point to a buffer area that
* is bigger or equal to the size specified by 'len'.
*
* Input: buffer : Pointer to where received bytes are to be stored
* len : The number of bytes expected.
*
* Output: The number of bytes copied to buffer.
*
* Side Effects: Publicly accessible variable hid_rpt_rx_len is updated
* with the number of bytes copied to buffer.
* Once HIDRxReport is called, subsequent retrieval of
* hid_rpt_rx_len can be done by calling macro
* mHIDGetRptRxLength().
*
* Overview: HIDRxReport copies a string of bytes received through
* USB HID OUT endpoint to a user's specified location.
* It is a non-blocking function. It does not wait
* for data if there is no data available. Instead it returns
* '0' to notify the caller that there is no data available.
*
* Note: If the actual number of bytes received is larger than the
* number of bytes expected (len), only the expected number
* of bytes specified will be copied to buffer.
* If the actual number of bytes received is smaller than the
* number of bytes expected (len), only the actual number
* of bytes received will be copied to buffer.
*****************************************************************************/
uint8_t HIDRxReport(char *buffer, uint8_t len)
{
hid_rpt_rx_len = 0;
if(!mHIDRxIsBusy())
{
/*
* Adjust the expected number of bytes to equal
* the actual number of bytes received.
*/
if(len > HID_BD_OUT.Cnt)
len = HID_BD_OUT.Cnt;
/*
* Copy data from dual-ram buffer to user's buffer
*/
for(hid_rpt_rx_len = 0; hid_rpt_rx_len < len; hid_rpt_rx_len++)
buffer[hid_rpt_rx_len] = hid_report_out[hid_rpt_rx_len];
/*
* Prepare dual-ram buffer for next OUT transaction
*/
HID_BD_OUT.Cnt = sizeof(hid_report_out);
mUSBBufferReady(HID_BD_OUT);
}//end if
return hid_rpt_rx_len;
}//end HIDRxReport
#endif //def USB_USE_HID
/** EOF hid.c ***************************************************************/

View File

@@ -0,0 +1,163 @@
/*******************************************************************************
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 HID_H
#define HID_H
/** I N C L U D E S **********************************************************/
#include "typedefs.h"
/** D E F I N I T I O N S ****************************************************/
/* Class-Specific Requests */
#define GET_REPORT 0x01
#define GET_IDLE 0x02
#define GET_PROTOCOL 0x03
#define SET_REPORT 0x09
#define SET_IDLE 0x0A
#define SET_PROTOCOL 0x0B
/* Class Descriptor Types */
#define DSC_HID 0x21
#define DSC_RPT 0x22
#define DSC_PHY 0x23
/* Protocol Selection */
#define BOOT_PROTOCOL 0x00
#define RPT_PROTOCOL 0x01
/* HID Interface Class Code */
#define HID_INTF 0x03
/* HID Interface Class SubClass Codes */
#define BOOT_INTF_SUBCLASS 0x01
/* HID Interface Class Protocol Codes */
#define HID_PROTOCOL_NONE 0x00
#define HID_PROTOCOL_KEYBOAD 0x01
#define HID_PROTOCOL_MOUSE 0x02
/******************************************************************************
* Macro: (bit) mHIDRxIsBusy(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: This macro is used to check if HID OUT endpoint is
* busy (owned by SIE) or not.
* Typical Usage: if(mHIDRxIsBusy())
*
* Note: None
*****************************************************************************/
#define mHIDRxIsBusy() HID_BD_OUT.Stat.UOWN
/******************************************************************************
* Macro: (bit) mHIDTxIsBusy(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: This macro is used to check if HID IN endpoint is
* busy (owned by SIE) or not.
* Typical Usage: if(mHIDTxIsBusy())
*
* Note: None
*****************************************************************************/
#define mHIDTxIsBusy() HID_BD_IN.Stat.UOWN
/******************************************************************************
* Macro: uint8_t mHIDGetRptRxLength(void)
*
* PreCondition: None
*
* Input: None
*
* Output: mHIDGetRptRxLength returns hid_rpt_rx_len
*
* Side Effects: None
*
* Overview: mHIDGetRptRxLength is used to retrieve the number of bytes
* copied to user's buffer by the most recent call to
* HIDRxReport function.
*
* Note: None
*****************************************************************************/
#define mHIDGetRptRxLength() hid_rpt_rx_len
/* HID macros */
#define mUSBGetHIDDscAdr(ptr) \
{ \
if(usb_active_cfg == 1) \
ptr = (ROM uint8_t*)&cfg01.hid_i00a00; \
}
#define mUSBGetHIDRptDscAdr(ptr) \
{ \
if(usb_active_cfg == 1) \
ptr = (ROM uint8_t*)&hid_rpt01; \
}
#define mUSBGetHIDRptDscSize(count) \
{ \
if(usb_active_cfg == 1) \
count = sizeof(hid_rpt01); \
}
/** S T R U C T U R E S ******************************************************/
typedef struct _USB_HID_DSC_HEADER
{
uint8_t bDscType;
uint16_t wDscLength;
} USB_HID_DSC_HEADER;
typedef struct _USB_HID_DSC
{
uint8_t bLength; uint8_t bDscType; uint16_t bcdHID;
uint8_t bCountryCode; uint8_t bNumDsc;
USB_HID_DSC_HEADER hid_dsc_header[HID_NUM_OF_DSC];
/*
* HID_NUM_OF_DSC is defined in autofiles\usb_config.h
*/
} USB_HID_DSC;
/** E X T E R N S ************************************************************/
extern uint8_t hid_rpt_rx_len;
extern ROM uint8_t hid_rpt01[HID_RPT01_SIZE];
/** P U B L I C P R O T O T Y P E S *****************************************/
void HIDInitEP(void);
void USBCheckHIDRequest(void);
void HIDTxReport(char *buffer, uint8_t len);
uint8_t HIDRxReport(char *buffer, uint8_t len);
#endif //HID_H