0,0 → 1,484 |
/************************************************************************ |
main.c |
|
WFF USB Generic HID Demonstration 3 |
usbGenericHidCommunication reference firmware 3_0_0_0 |
Copyright (C) 2011 Simon Inns |
|
This program is free software: you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation, either version 3 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
You should have received a copy of the GNU General Public License |
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
Email: simon.inns@gmail.com |
|
************************************************************************/ |
|
#ifndef MAIN_C |
#define MAIN_C |
|
// Global includes |
// Note: string.h is required for sprintf commands for debug |
#include <string.h> |
|
// Local includes |
#include "HardwareProfile.h" |
#include "debug.h" |
|
// Microchip Application Library includes |
// (expects V2.9a of the USB library from "Microchip Solutions v2011-07-14") |
// |
// The library location must be set in: |
// Project -> Build Options Project -> Directories -> Include search path |
// in order for the project to compile. |
#include "./USB/usb.h" |
#include "./USB/usb_function_hid.h" |
|
// Ensure we have the correct target PIC device family |
#if !defined(__18F4550) && !defined(__18F2550) |
#error "This firmware only supports either the PIC18F4550 or PIC18F2550 microcontrollers." |
#endif |
|
// Define the globals for the USB data in the USB RAM of the PIC18F*550 |
#pragma udata |
#pragma udata USB_VARIABLES=0x500 |
unsigned char ReceivedDataBuffer[64]; |
unsigned char ToSendDataBuffer[64]; |
#pragma udata |
|
USB_HANDLE USBOutHandle = 0; |
USB_HANDLE USBInHandle = 0; |
BOOL blinkStatusValid = FLAG_TRUE; |
|
// PIC18F4550/PIC18F2550 configuration for the WFF Generic HID test device |
#pragma config PLLDIV = 5 // 20Mhz external oscillator |
#pragma config CPUDIV = OSC1_PLL2 |
#pragma config USBDIV = 2 // Clock source from 96MHz PLL/2 |
#pragma config FOSC = HSPLL_HS |
#pragma config FCMEN = OFF |
#pragma config IESO = OFF |
#pragma config PWRT = OFF |
#pragma config BOR = ON |
#pragma config BORV = 3 |
#pragma config VREGEN = ON |
#pragma config WDT = OFF |
#pragma config WDTPS = 32768 |
#pragma config MCLRE = ON |
#pragma config LPT1OSC = OFF |
#pragma config PBADEN = OFF |
// #pragma config CCP2MX = ON |
#pragma config STVREN = ON |
#pragma config LVP = OFF |
// #pragma config ICPRT = OFF |
#pragma config XINST = OFF |
#pragma config CP0 = OFF |
#pragma config CP1 = OFF |
// #pragma config CP2 = OFF |
// #pragma config CP3 = OFF |
#pragma config CPB = OFF |
// #pragma config CPD = OFF |
#pragma config WRT0 = OFF |
#pragma config WRT1 = OFF |
// #pragma config WRT2 = OFF |
// #pragma config WRT3 = OFF |
#pragma config WRTB = OFF |
#pragma config WRTC = OFF |
// #pragma config WRTD = OFF |
#pragma config EBTR0 = OFF |
#pragma config EBTR1 = OFF |
// #pragma config EBTR2 = OFF |
// #pragma config EBTR3 = OFF |
#pragma config EBTRB = OFF |
|
// Private function prototypes |
static void initialisePic(void); |
void processUsbCommands(void); |
void applicationInit(void); |
void USBCBSendResume(void); |
void highPriorityISRCode(); |
void lowPriorityISRCode(); |
|
// Remap vectors for compatibilty with Microchip USB boot loaders |
#if defined(PROGRAMMABLE_WITH_USB_HID_BOOTLOADER) |
#define REMAPPED_RESET_VECTOR_ADDRESS 0x1000 |
#define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS 0x1008 |
#define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS 0x1018 |
#elif defined(PROGRAMMABLE_WITH_USB_MCHPUSB_BOOTLOADER) |
#define REMAPPED_RESET_VECTOR_ADDRESS 0x800 |
#define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS 0x808 |
#define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS 0x818 |
#else |
#define REMAPPED_RESET_VECTOR_ADDRESS 0x00 |
#define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS 0x08 |
#define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS 0x18 |
#endif |
|
#if defined(PROGRAMMABLE_WITH_USB_HID_BOOTLOADER) || defined(PROGRAMMABLE_WITH_USB_MCHPUSB_BOOTLOADER) |
extern void _startup (void); |
#pragma code REMAPPED_RESET_VECTOR = REMAPPED_RESET_VECTOR_ADDRESS |
void _reset (void) |
{ |
_asm goto _startup _endasm |
} |
#endif |
|
#pragma code REMAPPED_HIGH_INTERRUPT_VECTOR = REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS |
void Remapped_High_ISR (void) |
{ |
_asm goto highPriorityISRCode _endasm |
} |
|
#pragma code REMAPPED_LOW_INTERRUPT_VECTOR = REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS |
void Remapped_Low_ISR (void) |
{ |
_asm goto lowPriorityISRCode _endasm |
} |
|
#if defined(PROGRAMMABLE_WITH_USB_HID_BOOTLOADER) || defined(PROGRAMMABLE_WITH_USB_MCHPUSB_BOOTLOADER) |
#pragma code HIGH_INTERRUPT_VECTOR = 0x08 |
void High_ISR (void) |
{ |
_asm goto REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS _endasm |
} |
|
#pragma code LOW_INTERRUPT_VECTOR = 0x18 |
void Low_ISR (void) |
{ |
_asm goto REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS _endasm |
} |
#endif |
|
#pragma code |
|
// High-priority ISR handling function |
#pragma interrupt highPriorityISRCode |
void highPriorityISRCode() |
{ |
// Application specific high-priority ISR code goes here |
|
#if defined(USB_INTERRUPT) |
// Perform USB device tasks |
USBDeviceTasks(); |
#endif |
|
} |
|
// Low-priority ISR handling function |
#pragma interruptlow lowPriorityISRCode |
void lowPriorityISRCode() |
{ |
// Application specific low-priority ISR code goes here |
} |
|
// String for creating debug messages |
char debugString[64]; |
|
// Main program entry point |
void main(void) |
{ |
// Initialise and configure the PIC ready to go |
initialisePic(); |
|
// If we are running in interrupt mode attempt to attach the USB device |
#if defined(USB_INTERRUPT) |
USBDeviceAttach(); |
#endif |
|
// Initialise the debug log functions |
debugInitialise(); |
|
// Show that we are up and running |
mStatusLED0_on(); |
|
sprintf(debugString, "USB Generic HID Demonstration 3"); |
debugOut(debugString); |
|
sprintf(debugString, "(C)2011 Simon Inns - http://www.waitingforfriday.com"); |
debugOut(debugString); |
|
sprintf(debugString, "USB Device Initialised."); |
debugOut(debugString); |
|
// Main processing loop |
while(1) |
{ |
#if defined(USB_POLLING) |
// If we are in polling mode the USB device tasks must be processed here |
// (otherwise the interrupt is performing this task) |
USBDeviceTasks(); |
#endif |
|
// Process USB Commands |
processUsbCommands(); |
|
// Note: Other application specific actions can be placed here |
} |
} |
|
// Initialise the PIC |
static void initialisePic(void) |
{ |
// PIC port set up -------------------------------------------------------- |
|
// Default all pins to digital |
ADCON1 = 0x0F; |
|
// Configure ports as inputs (1) or outputs(0) |
TRISA = 0b00000000; |
TRISB = 0b00000000; |
TRISC = 0b00000000; |
#if defined(__18F4550) |
TRISD = 0b00000000; |
TRISE = 0b00000000; |
#endif |
|
// Clear all ports |
PORTA = 0b00000000; |
PORTB = 0b00000000; |
PORTC = 0b00000000; |
#if defined(__18F4550) |
PORTD = 0b00000000; |
PORTE = 0b00000000; |
#endif |
|
// If you have a VBUS sense pin (for self-powered devices when you |
// want to detect if the USB host is connected) you have to specify |
// your input pin in HardwareProfile.h |
#if defined(USE_USB_BUS_SENSE_IO) |
tris_usb_bus_sense = INPUT_PIN; |
#endif |
|
// In the case of a device which can be both self-powered and bus-powered |
// the device must respond correctly to a GetStatus (device) request and |
// tell the host how it is currently powered. |
// |
// To do this you must device a pin which is high when self powered and low |
// when bus powered and define this in HardwareProfile.h |
#if defined(USE_SELF_POWER_SENSE_IO) |
tris_self_power = INPUT_PIN; |
#endif |
|
// Application specific initialisation |
applicationInit(); |
|
// Initialise the USB device |
USBDeviceInit(); |
} |
|
// Application specific device initialisation |
void applicationInit(void) |
{ |
// Initialise the status LEDs |
mInitStatusLeds(); |
|
// Initialise the switch |
mInitAllSwitches(); |
|
// Initialize the variable holding the USB handle for the last transmission |
USBOutHandle = 0; |
USBInHandle = 0; |
} |
|
// Process USB commands |
void processUsbCommands(void) |
{ |
// Check if we are in the configured state; otherwise just return |
if((USBDeviceState < CONFIGURED_STATE) || (USBSuspendControl == 1)) |
{ |
// We are not configured |
return; |
} |
|
// Check if data was received from the host. |
if(!HIDRxHandleBusy(USBOutHandle)) |
{ |
// Command mode |
switch(ReceivedDataBuffer[0]) |
{ |
case 0x10: // Debug information request from host |
// Copy any waiting debug text to the send data buffer |
copyDebugToSendBuffer((BYTE*)&ToSendDataBuffer[0]); |
|
// Transmit the response to the host |
if(!HIDTxHandleBusy(USBInHandle)) |
{ |
USBInHandle = HIDTxPacket(HID_EP,(BYTE*)&ToSendDataBuffer[0],64); |
} |
break; |
|
// Place application specific commands here: |
|
case 0x80: // Toggle the LED |
sprintf(debugString, "Received command 0x80 from host - Toggle LED"); |
debugOut(debugString); |
|
// Toggle the LED0 |
mStatusLED0_Toggle(); |
break; |
|
case 0x81: // Read the push switch status |
ToSendDataBuffer[0] = sw0; |
|
// Transmit the response to the host |
if(!HIDTxHandleBusy(USBInHandle)) |
{ |
USBInHandle = HIDTxPacket(HID_EP,(BYTE*)&ToSendDataBuffer[0],64); |
} |
break; |
|
case 0x82: // Read the LED status |
// Get the LED state and put it in the send buffer |
ToSendDataBuffer[0] = mStatusLED0_Get(); |
|
// Transmit the response to the host |
if(!HIDTxHandleBusy(USBInHandle)) |
{ |
USBInHandle = HIDTxPacket(HID_EP,(BYTE*)&ToSendDataBuffer[0],64); |
} |
break; |
|
default: // Unknown command received |
break; |
} |
|
// Re-arm the OUT endpoint for the next packet |
USBOutHandle = HIDRxPacket(HID_EP,(BYTE*)&ReceivedDataBuffer,64); |
} |
} |
|
// USB Callback handling routines ----------------------------------------------------------- |
|
// Call back that is invoked when a USB suspend is detected |
void USBCBSuspend(void) |
{ |
} |
|
// This call back is invoked when a wakeup from USB suspend is detected. |
void USBCBWakeFromSuspend(void) |
{ |
} |
|
// The USB host sends out a SOF packet to full-speed devices every 1 ms. |
void USBCB_SOF_Handler(void) |
{ |
// No need to clear UIRbits.SOFIF to 0 here. Callback caller is already doing that. |
} |
|
// The purpose of this callback is mainly for debugging during development. |
// Check UEIR to see which error causes the interrupt. |
void USBCBErrorHandler(void) |
{ |
// No need to clear UEIR to 0 here. |
// Callback caller is already doing that. |
} |
|
// Check other requests callback |
void USBCBCheckOtherReq(void) |
{ |
USBCheckHIDRequest(); |
} |
|
// Callback function is called when a SETUP, bRequest: SET_DESCRIPTOR request arrives. |
void USBCBStdSetDscHandler(void) |
{ |
// You must claim session ownership if supporting this request |
} |
|
//This function is called when the device becomes initialized |
void USBCBInitEP(void) |
{ |
// Enable the HID endpoint |
USBEnableEndpoint(HID_EP,USB_IN_ENABLED|USB_OUT_ENABLED|USB_HANDSHAKE_ENABLED|USB_DISALLOW_SETUP); |
|
// Re-arm the OUT endpoint for the next packet |
USBOutHandle = HIDRxPacket(HID_EP,(BYTE*)&ReceivedDataBuffer,64); |
} |
|
// Send resume call-back |
void USBCBSendResume(void) |
{ |
static WORD delay_count; |
|
// Verify that the host has armed us to perform remote wakeup. |
if(USBGetRemoteWakeupStatus() == FLAG_TRUE) |
{ |
// Verify that the USB bus is suspended (before we send remote wakeup signalling). |
if(USBIsBusSuspended() == FLAG_TRUE) |
{ |
USBMaskInterrupts(); |
|
// Bring the clock speed up to normal running state |
USBCBWakeFromSuspend(); |
USBSuspendControl = 0; |
USBBusIsSuspended = FLAG_FALSE; |
|
// Section 7.1.7.7 of the USB 2.0 specifications indicates a USB |
// device must continuously see 5ms+ of idle on the bus, before it sends |
// remote wakeup signalling. One way to be certain that this parameter |
// gets met, is to add a 2ms+ blocking delay here (2ms plus at |
// least 3ms from bus idle to USBIsBusSuspended() == FLAG_TRUE, yeilds |
// 5ms+ total delay since start of idle). |
delay_count = 3600U; |
do |
{ |
delay_count--; |
} while(delay_count); |
|
// Start RESUME signaling for 1-13 ms |
USBResumeControl = 1; |
delay_count = 1800U; |
do |
{ |
delay_count--; |
} while(delay_count); |
USBResumeControl = 0; |
|
USBUnmaskInterrupts(); |
} |
} |
} |
|
// USB callback function handler |
BOOL USER_USB_CALLBACK_EVENT_HANDLER(USB_EVENT event, void *pdata, WORD size) |
{ |
switch(event) |
{ |
case EVENT_TRANSFER: |
// Application callback tasks and functions go here |
break; |
case EVENT_SOF: |
USBCB_SOF_Handler(); |
break; |
case EVENT_SUSPEND: |
USBCBSuspend(); |
break; |
case EVENT_RESUME: |
USBCBWakeFromSuspend(); |
break; |
case EVENT_CONFIGURED: |
USBCBInitEP(); |
break; |
case EVENT_SET_DESCRIPTOR: |
USBCBStdSetDscHandler(); |
break; |
case EVENT_EP0_REQUEST: |
USBCBCheckOtherReq(); |
break; |
case EVENT_BUS_ERROR: |
USBCBErrorHandler(); |
break; |
default: |
break; |
} |
return FLAG_TRUE; |
} |
|
#endif |