+ All Categories
Home > Documents > pic18_usb.h

pic18_usb.h

Date post: 02-Jun-2018
Category:
Upload: shariful-islam
View: 219 times
Download: 0 times
Share this document with a friend

of 23

Transcript
  • 8/10/2019 pic18_usb.h

    1/23

    ///////////////////////////////////////////////////////////////////////////// pic18_usb.c //////// //////// Hardware layer for CCS's USB library. This hardware layer //////// supports the USB peripheral on the PIC18 family chips. Current //////// supported families are: //////// PIC18F2455/2550/4455/4550 //////// PIC18F2450/4450 //////// PIC18F65J50/66J50/66J55/67J50/85J50/86J50/86J55/87J50 //////// //////// This file is part of CCS's PIC USB driver code, which includes: //////// usb_desc_*.h - an example set of config and device descriptor //////// usb.c - USB token and request handler code //////// usb.h - definitions, prototypes and global variables //////// //////// The following examples are provided by CCS: //////// ex_usb_mouse.c - A HID Mouse. //////// ex_usb_hid.c - A custom application using HID protocol. //////// ex_usb_kbmouse.c - A HID Mouse/Keyboard combo using multiple //////// interfaces. //////// ex_usb_kbmouse2.c - A HID Mouse/Keyboard combo using multiple //////// HID Reports. //////// ex_usb_scope.c - A digital oscilloscope using a custom //////// protocol requiring custom Windows drivers. ////

    //// ex_usb_serial.c - //////// ex_usb_serial2.c - Two examples of using the CDC driver for //////// a virtual COM port. //////// //////// *********** NOTE ABOUT 18F2450/4450 LIMITATIONS ********** //////// Due to the limited USB RAM of this family, a limitation of //////// this driver is that there are only 3 endpoints (0, 1 and 2). //////// The HW actually supports more endpoints, but to simplify //////// driver development this driver will only support the first 3 //////// so there is an easier memory block to work with. //////// //////// USB_MAX_EP0_PACKET_LENGTH will also be set to 8 regardless //////// of USB speed, to save RAM. ////

    //// //////// ************** NOTE ABOUT HW REQUIREMENTS **************** //////// If you are not using internal pullups, you will need to put //////// an internal pullup resistor on C4 or C5 depending on if you //////// want to use slow speed or full speed. This code configures //////// the device to use internal pullups, see usb_init() if you //////// want to change that. //////// //////// You need approximately 470nF cap on C3, even if you are using //////// the internal 3.3V USB regulator. //////// //////// To run at full speed, you must use the oscillator //////// configuration (PLLx) to set the PLL divide to 4MHz. You can ////

    //// configure the MCU clock to any speed (up to 48MHz) but the //////// PLL must run at 4Mhz to provide the USB peripheral with a //////// 96MHz clock. See the datasheet for details. //////// //////// To run at slow speed you must configure your MCU to run at //////// 24Mhz. See the datasheet for details. //////// //////// **************** NOTE ABOUT INTERRUPTS ****************** //////// This driver uses INT_USB. It requires INT_USB to interrupt the //////// PIC when an event has happened on the USB Bus. Therfore ////

  • 8/10/2019 pic18_usb.h

    2/23

    //// this code enables interrupts. A user modification can be made //////// to poll the USB interrupt flag instead of relying on an //////// interrupt. //////// //////// **************** USER FUNCTIONS *********************** //////// //////// usb_init() - Initializes the USB stack, the USB peripheral and //////// attaches the unit to the usb bus. Enables //////// interrupts. //////// //////// usb_init_cs() - A smaller usb_init(), does not attach unit //////// to usb bus or enable interrupts. //////// //////// usb_put_packet() - Sends one packet to the host. //////// If you need to send a message that spans //////// more than one packet then see usb_puts() in //////// usb.c //////// //////// usb_kbhit() - Returns true if OUT endpoint contains data from //////// host. //////// //////// usb_rx_packet_size() - Returns the size of packet that was //////// received. usb_kbhit() must return TRUE else //////// this is not valid. Don't forget in USB there ////

    //// are 0 len packets! //////// //////// usb_get_packet() - Gets one packet that from the host. //////// usb_kbhit() must return true before you call //////// this routine or your data may not be valid. //////// Once usb_kbhit() returns true you want to //////// call this as soon as possible to get data //////// out of the endpoint buffer so the PC can //////// start sending more data, if needed. //////// This only receives one packet, if you are //////// trying to receive a multi-packet message //////// see usb_gets() in usb.c. //////// ////

    //// usb_detach() - De-attach USB from the system. //////// //////// usb_attach() - Attach USB to the system. //////// //////// usb_attached() - Returns TRUE if the device is attached to a //////// USB cable. A macro that looks at the defined //////// connection sense pin. //////// //////// usb_task() - Keeps track of connection sense, calling //////// usb_detach() and usb_attach() when needed. //////// //////// For more documentation on these functions read the comments at //////// each function. ////

    //// //////// The other functions defined in this file are for use by the //////// USB code, and is not meant to be used by the user. //////// ///////////////////////////////////////////////////////////////////////////////// //////// Version History: //////// //////// 07-17-07: Added 18F4450,2450 support //////// ////

  • 8/10/2019 pic18_usb.h

    3/23

    //// 07-13-07: Added 87J50 family support //////// //////// 11-01-05: usb_detach(), usb_attach() and usb_init_cs() //////// changed for the better. //////// //////// 10-28-05: Added usb_rx_packet_size() //////// //////// 07-13-05: usb_put_packet() changed for 16bit packet sizes //////// usb_flush_in() changed for 16bit packet sizes //////// usb_get_packet() changed for 16bit packet sizes //////// usb_flush_out() changed for 16bit packet sizes //////// usb_set_configured() changed for 16bit packet sizes //////// //////// 06-30-05: usb_tbe() added //////// The way endpoint 0 DTS is set has been changed. //////// //////// 06-20-05: Initial Release //////// //////// 05-13-05: Beta Release (Full Speed works) //////// //////// 03-21-05: Initial Alpha Release //////// ///////////////////////////////////////////////////////////////////////////////// (C) Copyright 1996,2005 Custom Computer Services ////

    //// This source code may only be used by licensed users of the CCS //////// C compiler. This source code may only be distributed to other //////// licensed users of the CCS C compiler. No other use, //////// reproduction or distribution is permitted without written //////// permission. Derivative programs created using this software //////// in object code form are not restricted in any way. /////////////////////////////////////////////////////////////////////////////

    #IFNDEF __USB_HARDWARE__#DEFINE __USB_HARDWARE__

    //let the USB Stack know that we are using a PIC with internal USB peripheral#DEFINE __PIC__ 1

    #if ((getenv("DEVICE")=="PIC18F87J50") || (getenv("DEVICE")=="PIC18F86J55") || (getenv("DEVICE")=="PIC18F86J50") || (getenv("DEVICE")=="PIC18F85J50") || (getenv("DEVICE")=="PIC18F67J50") || (getenv("DEVICE")=="PIC18F66J55") || (getenv("DEVICE")=="PIC18F66J50") || (getenv("DEVICE")=="PIC18F65J50"))#define __USB_87J50__#define USB_TOTAL_BUFFER_SPACE ((int16)getenv("RAM")-0x500)#define USB_MAX_NUM_ENDPOINTS 16#elif ((getenv("DEVICE")=="PIC18F2450") || (getenv("DEVICE")=="PIC18F4450"))#define __USB_4450__#if (USB_EP3_TX_SIZE+USB_EP3_RX_SIZE+USB_EP4_TX_SIZE+USB_EP4_RX_SIZE+USB_EP5_TX

    _SIZE+USB_EP5_RX_SIZE+USB_EP6_TX_SIZE+USB_EP6_RX_SIZE+USB_EP7_TX_SIZE+USB_EP7_RX_SIZE+USB_EP8_TX_SIZE+USB_EP8_RX_SIZE+USB_EP9_TX_SIZE+USB_EP9_RX_SIZE+USB_EP10_T

    X_SIZE+USB_EP10_RX_SIZE+USB_EP11_TX_SIZE+USB_EP11_RX_SIZE+USB_EP12_TX_SIZE+USB_EP12_RX_SIZE+USB_EP13_TX_SIZE+USB_EP13_RX_SIZE+USB_EP14_TX_SIZE+USB_EP14_RX_SIZE+USB_EP15_TX_SIZE+USB_EP15_RX_SIZE)>0 #error This driver only supports endpoints 0, 1 and 2 for this chip.#endif#define USB_MAX_NUM_ENDPOINTS 3#define USB_TOTAL_BUFFER_SPACE (0x100 - USB_MAX_NUM_ENDPOINTS*8)#else#define __USB_4550__#define USB_TOTAL_BUFFER_SPACE ((int16)0x300)

  • 8/10/2019 pic18_usb.h

    4/23

    #define USB_MAX_NUM_ENDPOINTS 16#endif

    #ifndef USB_USE_FULL_SPEED#define USB_USE_FULL_SPEED TRUE#endif

    #ifndef USB_CON_SENSE_PIN#define USB_CON_SENSE_PIN 0#endif

    #if defined(__USB_4450__) #define USB_MAX_EP0_PACKET_LENGTH 8#else #if USB_USE_FULL_SPEED==FALSE //slow speed requires 8byte max packet size for endpoint 0 #DEFINE USB_MAX_EP0_PACKET_LENGTH 8 #else //for full speed you can still use 8bytes, but 64 will be faster #DEFINE USB_MAX_EP0_PACKET_LENGTH 64 #endif#endif

    #INCLUDE

    #define USB_BUFFER_NEEDED (USB_EP0_TX_SIZE+USB_EP0_RX_SIZE+USB_EP1_TX_SIZE+USB_EP1_RX_SIZE+USB_EP2_TX_SIZE+USB_EP2_RX_SIZE+USB_EP3_TX_SIZE+USB_EP3_RX_SIZE+USB_EP4_TX_SIZE+USB_EP4_RX_SIZE+USB_EP5_TX_SIZE+USB_EP5_RX_SIZE+USB_EP6_TX_SIZE+USB_EP6_RX_SIZE+USB_EP7_TX_SIZE+USB_EP7_RX_SIZE+USB_EP8_TX_SIZE+USB_EP8_RX_SIZE+USB_EP9_TX_SIZE+USB_EP9_RX_SIZE+USB_EP10_TX_SIZE+USB_EP10_RX_SIZE+USB_EP11_TX_SIZE+USB_EP11_RX_SIZE+USB_EP12_TX_SIZE+USB_EP12_RX_SIZE+USB_EP13_TX_SIZE+USB_EP13_RX_SIZE+USB_EP14_TX_SIZE+USB_EP14_RX_SIZE+USB_EP15_TX_SIZE+USB_EP15_RX_SIZE)

    #if (USB_BUFFER_NEEDED > USB_TOTAL_BUFFER_SPACE)#error You are trying to allocate more memory for endpoints than the PIC can handle#endif

    #if defined(__USB_4450__)#reserve 0x400:0x4FF#else#reserve 0x400:0x4FF+USB_BUFFER_NEEDED#endif

    #define debug_usb(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z)//#define debug_usb printf//#define debug_putc putc_tbe#define debug_display_ram(x,y)/*void debug_display_ram(int8 len, int8 *ptr) {

    int8 max=16; debug_usb(debug_putc,"%U - ",len); if (max>len) {max=len;} while(max--) { debug_usb(debug_putc,"%X",*ptr); len--; ptr++; } if (len) {debug_usb(debug_putc,"...");}}

  • 8/10/2019 pic18_usb.h

    5/23

    */

    //if you are worried that the PIC is not receiving packets because a bug in the//DATA0/DATA1 synch code, you can set this to TRUE to ignore the DTS on//receiving.#ifndef USB_IGNORE_RX_DTS#define USB_IGNORE_RX_DTS FALSE#endif

    #ifndef USB_IGNORE_TX_DTS#define USB_IGNORE_TX_DTS FALSE#endif

    //if you enable this it will keep a counter of the 6 possible errors the//pic can detect. disabling this will save you ROM, RAM and execution time.#ifndef USB_USE_ERROR_COUNTER #define USB_USE_ERROR_COUNTER FALSE#endif

    #define USB_PING_PONG_MODE_OFF 0 //no ping pong#define USB_PING_PONG_MODE_E0 1 //ping pong endpoint 0 only#define USB_PING_PONG_MODE_ON 2 //ping pong all endpoints

    //NOTE - PING PONG MODE IS NOT SUPPORTED BY CCS!

    #ifndef USB_PING_PONG_MODE #define USB_PING_PONG_MODE USB_PING_PONG_MODE_OFF#endif

    #if USB_USE_ERROR_COUNTER int ERROR_COUNTER[6];#endif

    //---pic18fxx5x memory locations#if defined(__USB_4550__) #byte UFRML = 0xF66 #byte UFRMH = 0xF67 #byte UIR = 0xF68

    #byte UIE = 0xF69 #byte UEIR = 0xF6A #byte UEIE = 0xF6B #byte USTAT = 0xF6C #byte UCON = 0xF6D #byte UADDR = 0xF6E #byte UCFG = 0xF6F #define UEP0_LOC 0xF70#else #byte UFRML = 0xF60 #byte UFRMH = 0xF61 #byte UIR = 0xF62 #byte UIE = 0xF5C

    #byte UEIR = 0xF63 #byte UEIE = 0xF5D #byte USTAT = 0xF64 #byte UCON = 0xF65 #byte UADDR = 0xF5E #byte UCFG = 0xF5F #define UEP0_LOC 0xF4C#endif

    #byte UEP0 = UEP0_LOC

  • 8/10/2019 pic18_usb.h

    6/23

    #if defined(__USB_4450__)#define USB_BUFFER (0x400 + (USB_MAX_NUM_ENDPOINTS*8))//#define USB_BUFFER 0x418 //if you have an old compiler you will need to usethis#else#define USB_BUFFER 0x500#endif

    #byte BD0STAT = 0x400#byte BD0CNT = 0x401#byte BD0ADRL = 0x402#byte BD0ADRJ = 0x403

    #define BD0STAT_LOC 0x400#define BD0CNT_LOC 0x401#define BD0ADRL_LOC 0x402#define BD0ADRH_LOC 0x403

    #define UEP(x) *(UEP0_LOC+x)

    #BIT UIR_SOF = UIR.6#BIT UIR_STALL = UIR.5#BIT UIR_IDLE = UIR.4

    #BIT UIR_TRN = UIR.3#BIT UIR_ACTV = UIR.2#BIT UIR_UERR = UIR.1#BIT UIR_URST = UIR.0

    #BIT UIE_SOF = UIE.6#BIT UIE_STALL = UIE.5#BIT UIE_IDLE = UIE.4#BIT UIE_TRN = UIE.3#BIT UIE_ACTV = UIE.2#BIT UIE_UERR = UIE.1#BIT UIE_URST = UIE.0

    #bit UCON_PBRST=UCON.6#bit UCON_SE0=UCON.5#bit UCON_PKTDIS=UCON.4#bit UCON_USBEN=UCON.3#bit UCON_RESUME=UCON.2#bit UCON_SUSPND=UCON.1

    #if (USB_PING_PONG_MODE==USB_PING_PONG_MODE_OFF)#define EP_BDxST_O(x) *(BD0STAT_LOC + x*8)#define EP_BDxCNT_O(x) *(BD0CNT_LOC + x*8)#define EP_BDxADR_O(x) *(int16 *)(BD0ADRL_LOC + x*8)#define EP_BDxST_I(x) *(BD0STAT_LOC + 4 + x*8)#define EP_BDxCNT_I(x) *(BD0CNT_LOC + 4 + x*8)

    #define EP_BDxADR_I(x) *(int16 *)(BD0ADRL_LOC + 4 + x*8)#else#error Right now this driver only supports no ping pong#endif

    //See UEPn (0xF70-0xF7F)#define ENDPT_DISABLED 0x00 //endpoint not used#define ENDPT_IN_ONLY 0x02 //endpoint supports IN transactions only#define ENDPT_OUT_ONLY 0x04 //endpoint supports OUT transactions only#define ENDPT_CONTROL 0x06 //Supports IN, OUT and CONTROL transactions - On

  • 8/10/2019 pic18_usb.h

    7/23

    ly use with EP0#define ENDPT_NON_CONTROL 0x0E //Supports both IN and OUT transactions

    //Define the states that the USB interface can be inenum {USB_STATE_DETACHED=0, USB_STATE_ATTACHED=1, USB_STATE_POWERED=2, USB_STATE

    _DEFAULT=3, USB_STATE_ADDRESS=4, USB_STATE_CONFIGURED=5} usb_state=0;

    //--BDendST has their PIDs upshifed 2#define USB_PIC_PID_IN 0x24 //device to host transactions#define USB_PIC_PID_OUT 0x04 //host to device transactions#define USB_PIC_PID_SETUP 0x34 //host to device setup transaction

    #define USTAT_IN_E0 4#define USTAT_OUT_SETUP_E0 0

    #define __USB_UIF_RESET 0x01#define __USB_UIF_ERROR 0x02#define __USB_UIF_ACTIVE 0x04#define __USB_UIF_TOKEN 0x08#define __USB_UIF_IDLE 0x10#define __USB_UIF_STALL 0x20#define __USB_UIF_SOF 0x40

    #if USB_USE_ERROR_COUNTER#define STANDARD_INTS 0x3F#else#define STANDARD_INTS 0x3D#endif

    #define __USB_UCFG_UTEYE 0x80#if defined(__USB_4550__)#define __USB_UCFG_UOEMON 0x40#endif#define __USB_UCFG_UPUEN 0x10#define __USB_UCFG_UTRDIS 0x08#define __USB_UCFG_FSEN 0x04

    #if USB_USE_FULL_SPEED #define __UCFG_VAL_ENABLED__ (__USB_UCFG_UPUEN | __USB_UCFG_FSEN | USB_PING_PONG_MODE)#else #define __UCFG_VAL_ENABLED__ (__USB_UCFG_UPUEN | USB_PING_PONG_MODE);#endif

    #define __UCFG_VAL_DISABLED__ 0x08

    char usb_ep0_rx_buffer[USB_MAX_EP0_PACKET_LENGTH];#locate usb_ep0_rx_buffer=USB_BUFFER

    char usb_ep0_tx_buffer[USB_MAX_EP0_PACKET_LENGTH];#locate usb_ep0_tx_buffer=USB_BUFFER+USB_MAX_EP0_PACKET_LENGTH

    char usb_data_buffer[USB_TOTAL_BUFFER_SPACE-USB_MAX_EP0_PACKET_LENGTH-USB_MAX_EP0_PACKET_LENGTH];#locate usb_data_buffer=USB_BUFFER+USB_MAX_EP0_PACKET_LENGTH+USB_MAX_EP0_PACKET_LENGTH

    int8 __setup_0_tx_size;

  • 8/10/2019 pic18_usb.h

    8/23

    //interrupt handler, specific to PIC18Fxx5x peripheral onlyvoid usb_handle_interrupt();void usb_isr_rst();void usb_isr_uerr();void usb_isr_sof(void);void usb_isr_activity();void usb_isr_uidle();void usb_isr_tok_dne();void usb_isr_stall(void);void usb_init_ep0_setup(void);

    //following functions standard part of CCS PIC USB driver, and used by usb.cvoid usb_init();void usb_detach();int1 usb_put_packet(int endpoint, int * ptr, int16 len, USB_DTS_BIT tgl);int1 usb_flush_in(int8 endpoint, int16 len, USB_DTS_BIT tgl); //marks the transmit buffer as ready for transmissionint16 usb_get_packet(int8 endpoint, int8 * ptr, int16 max);int16 usb_rx_packet_size(int8 endpoint);int16 usb_get_packet_buffer(int8 endpoint, int8 *ptr, int16 max);void usb_flush_out(int8 endpoint, USB_DTS_BIT tgl);void usb_stall_ep(int8 endpoint);void usb_unstall_ep(int8 endpoint);int1 usb_endpoint_stalled(int8 endpoint);

    void usb_set_address(int8 address);void usb_set_configured(int config);void usb_disable_endpoints(void);

    //// BEGIN User Functions:

    /******************************************************************************/* usb_attached()/*/* Summary: Returns TRUE if the device is attached to a USB cable/*/*****************************************************************************/#if USB_CON_SENSE_PIN

    #define usb_attached() input(USB_CON_SENSE_PIN)#else#define usb_attached() TRUE#endif

    /******************************************************************************/* usb_detach()/*/* Summary: Remove the D+/D- lines from the USB bus. Basically, disable USB./*/*****************************************************************************/void usb_detach(void) { //done UCON=0; //disable USB hardware

    UIE=0; //disable USB interrupts UCFG = __UCFG_VAL_DISABLED__; set_tris_c(*0xF94 | 0x30); usb_state=USB_STATE_DETACHED; usb_token_reset(); //clear the chapter9 stack __usb_kbhit_status=0;}

    /******************************************************************************/* usb_attach()

  • 8/10/2019 pic18_usb.h

    9/23

    /*/* Summary: Attach the D+/D- lines to the USB bus. Enable the USB peripheral./*/* You should wait until UCON_SE0 is clear before enabling reset/idle interrupt/*/*****************************************************************************/void usb_attach(void) { usb_token_reset(); UCON = 0; UCFG = __UCFG_VAL_ENABLED__; UIE = 0; // Mask all USB interrupts UCON_USBEN = 1; // Enable module & attach to bus usb_state = USB_STATE_ATTACHED; // Defined in usbmmap.c & .h}

    /*****************************************************************************/* usb_init_cs()/*/* Summary: Resets and initalizes USB peripheral. Does not attach the peripheral/* to the USB bus. See usb_attach() and usb_task() on how to/* attach to the USB bus./*/* You must call this before any other USB code.

    /*/* NOTE: an alternative function, usb_init(), is provided that/* initializes the USB and then connects./*/*****************************************************************************/#define usb_init_cs usb_detach

    /*****************************************************************************/* usb_task()/*/* Summary: Keeps an eye on the connection sense pin to determine if we are/* attached to a USB cable or not. If we are attached to a USB cable,/* initialize the USB peripheral if needed. If we are disconnected

    /* from the USB cable, disable the USB peripheral./*/* NOTE: If you are not using a connection sense pin, will automatically/* enable the USB peripheral./*/* NOTE: this enables interrupts once the USB peripheral is ready/*/*****************************************************************************/void usb_task(void) { if (usb_attached()) { if (UCON_USBEN==0) { debug_usb(debug_putc, "\r\n\nUSB TASK: ATTACH");

    usb_attach(); } } else { if (UCON_USBEN==1) { debug_usb(debug_putc, "\r\n\nUSB TASK: DE-ATTACH"); usb_detach(); } }

  • 8/10/2019 pic18_usb.h

    10/23

    if ((usb_state == USB_STATE_ATTACHED)&&(!UCON_SE0)) { UIR=0; UIE=0; enable_interrupts(INT_USB); enable_interrupts(GLOBAL); UIE=__USB_UIF_IDLE | __USB_UIF_RESET; //enable IDLE and RESET USB interrupt usb_state=USB_STATE_POWERED; debug_usb(debug_putc, "\r\n\nUSB TASK: POWERED"); }}

    /*****************************************************************************/* usb_init()/*/* Summary: Resets and initalizes USB hardware. You must call this first before/* using code. Will attach the USB periperhal to the USB bus./*/* NOTE: If you are using a connection sense pin, this will wait in/* an infinite loop until the device is connected to a USB cable./*/* NOTE: If you are not using a connection sense pin, this will wait/* in an infinte loop until the SE0 condition clears, which usually

    /* doesn't take long/*/* NOTE: this enables interrupts./*/*****************************************************************************/void usb_init(void) { usb_init_cs();

    do { usb_task(); } while (usb_state != USB_STATE_POWERED);}

    /**************************************************************/* usb_flush_in()/*/* Input: endpoint - which endpoint to mark for transfer/* len - length of data that is being tramsferred/* tgl - Data toggle synchronization for this packet/*/* Output: TRUE if success, FALSE if error (we don't control the endpoint)/*/* Summary: Marks the endpoint ready for transmission. You must/* have already loaded the endpoint buffer with data./* (IN is PIC -> PC)

    /***************************************************************/int1 usb_flush_in(int8 endpoint, int16 len, USB_DTS_BIT tgl) { int8 i;

    debug_usb(debug_putc,"\r\nPUT %X %U %LU",endpoint, tgl, len);

    i=EP_BDxST_I(endpoint); if (!bit_test(i,7)) {

    EP_BDxCNT_I(endpoint)=len;

  • 8/10/2019 pic18_usb.h

    11/23

    debug_display_ram(len, EP_BDxADR_I(endpoint));

    #if USB_IGNORE_TX_DTS i=0x80; #else if (tgl == USB_DTS_TOGGLE) { i=EP_BDxST_I(endpoint); if (bit_test(i,6)) tgl=USB_DTS_DATA0; //was DATA1, goto DATA0 else tgl=USB_DTS_DATA1; //was DATA0, goto DATA1 } else if (tgl == USB_DTS_USERX) { i=EP_BDxST_O(endpoint); if (bit_test(i,6)) tgl=USB_DTS_DATA1; else tgl=USB_DTS_DATA0; } if (tgl == USB_DTS_DATA1) { i=0xC8; //DATA1, UOWN } else if (tgl == USB_DTS_DATA0) {

    i=0x88; //DATA0, UOWN } #endif

    //set BC8 and BC9 if (bit_test(len,8)) {bit_set(i,0);} if (bit_test(len,9)) {bit_set(i,1);}

    debug_usb(debug_putc," %X",i);

    EP_BDxST_I(endpoint)=i;//save changes

    return(1);

    } else { debug_usb(debug_putc,"\r\nPUT ERR"); } return(0);}

    /*******************************************************************************/* usb_put_packet(endpoint,*ptr,len,toggle)/*/* Input: endpoint - endpoint to send packet to/* ptr - points to data to send/* len - amount of data to send

    /* toggle - whether to send data with a DATA0 pid, a DATA1 pid, or togglefrom the last DATAx pid./*/* Output: TRUE if data was sent correctly, FALSE if it was not. The only reason it will/* return FALSE is if because the TX buffer is still full from the lasttime you/* tried to send a packet./*/* Summary: Sends one packet out the EP to the host. Notice that there is a dif

  • 8/10/2019 pic18_usb.h

    12/23

    ference/* between a packet and a message. If you wanted to send a 512 byte message you/* would accomplish this by sending 8 64-byte packets, followed by a 0length packet./* If the last (or only packet) being sent is less than the max packetsize defined/* in your descriptor then you do not need to send a 0 length packet toidentify/* an end of message./*/* usb_puts() (provided in usb.c) will send a multi-packet message correctly./*/********************************************************************************/int1 usb_put_packet(int8 endpoint, int8 * ptr, int16 len, USB_DTS_BIT tgl) { //done int16 j; int8 i; int8 * buff_add;

    i=EP_BDxST_I(endpoint); if (!bit_test(i,7)) {

    buff_add=EP_BDxADR_I(endpoint);

    for (j=0;j

  • 8/10/2019 pic18_usb.h

    13/23

    int16 len;

    #if USB_IGNORE_RX_DTS if (tgl == USB_DTS_STALL) { debug_usb(debug_putc, '*'); i=0x84; EP_BDxST_I(endpoint)=0x84; return; } else i=0x80; #else i=EP_BDxST_O(endpoint); if (tgl == USB_DTS_TOGGLE) { if (bit_test(i,6)) tgl=USB_DTS_DATA0; //was DATA1, goto DATA0 else tgl=USB_DTS_DATA1; //was DATA0, goto DATA1 } if (tgl == USB_DTS_STALL) { i=0x84; EP_BDxST_I(endpoint)=0x84; //stall both in and out endpoints } else if (tgl == USB_DTS_DATA1) {

    i=0xC8; //DATA1, UOWN } else if (tgl == USB_DTS_DATA0) { i=0x88; //DATA0, UOWN } #endif

    bit_clear(__usb_kbhit_status,endpoint);

    len=usb_ep_rx_size[endpoint]; EP_BDxCNT_O(endpoint)=len; if (bit_test(len,8)) {bit_set(i,0);} if (bit_test(len,9)) {bit_set(i,1);}

    EP_BDxST_O(endpoint)=i;}

    int16 usb_rx_packet_size(int8 endpoint) { return(EP_BDxCNT_O(endpoint));}

    /*******************************************************************************/* usb_get_packet_buffer(endpoint, *ptr, max)/*/* Input: endpoint - endpoint to get data from

    /* ptr - where to save data to local PIC RAM/* max - max amount of data to receive from buffer/*/* Output: the amount of data taken from the buffer./*/* Summary: Gets a packet of data from the USB buffer and puts into local PIC RAM./* Does not mark the endpoint as ready for more data. Once you are/* done with data, call usb_flush_out() to mark the endpoint ready/* to receive more data.

  • 8/10/2019 pic18_usb.h

    14/23

    /*/********************************************************************************/int16 usb_get_packet_buffer(int8 endpoint, int8 *ptr, int16 max) { int8 * al; int8 st; int16 i;

    al=EP_BDxADR_O(endpoint); i=EP_BDxCNT_O(endpoint); st=EP_BDxST_O(endpoint);

    //read BC8 and BC9 if (bit_test(st,0)) {bit_set(i,8);} if (bit_test(st,1)) {bit_set(i,9);}

    if (i

  • 8/10/2019 pic18_usb.h

    15/23

    /*/* Input: endpoint - endpoint to check/* ptr - where to save data to local PIC RAM/* max - max amount of data to receive from buffer/*/* Output: returns TRUE if this endpoint's IN buffer (PIC-PC) is empty and ready/* returns FALSE if this endpoint's IN buffer is still processing the last/* transmit or if this endpoint is invalid./*/********************************************************************************/int8 usb_tbe(int8 endpoint) { int8 st; st=EP_BDxST_I(endpoint); if (!bit_test(st,7)) return(TRUE); return(FALSE);}

    /*******************************************************************************/* usb_stall_ep(endpoint,direction)/*/* Input: endpoint - endpoint to stall.

    /* top most bit indicates direction (set is IN, clear is OUT)/*/* Summary: Stalls specified endpoint. If endpoint is stalled it will send STALL packet/* if the host tries to access this endpoint's buffer./*/*/* NOTE: WE ASSUME ENDPOINT IS VALID. USB.C SHOULD CHECK THIS/*/********************************************************************************/void usb_stall_ep(int8 endpoint) { //done int1 direction;

    direction=bit_test(endpoint,7); endpoint&=0x7F; if (direction) { EP_BDxST_I(endpoint)=0x84; } else { EP_BDxST_O(endpoint)=0x84; }}

    /*******************************************************************************/* usb_unstall_ep(endpoint, direction)/*

    /* Input: endpoint - endpoint to un-stall./* top most bit indicates direction (set is IN, clear is OUT)/*/* Summary: Un-stalls endpoint./*/* NOTE: WE ASSUME ENDPOINT IS VALID. USB.C SHOULD CHECK THIS/********************************************************************************/void usb_unstall_ep(int8 endpoint) { //done int1 direction;

  • 8/10/2019 pic18_usb.h

    16/23

    direction=bit_test(endpoint,7); endpoint&=0x7F; if (direction) { #if USB_IGNORE_RX_DTS EP_BDxST_I(endpoint)=0x80; #else EP_BDxST_I(endpoint)=0x88; #endif } else { EP_BDxST_O(endpoint)=0x00; }}

    /*******************************************************************************/* usb_endpoint_stalled(endpoint)/*/* Input: endpoint - endpoint to check/* top most bit indicates direction (set is IN, clear is OUT)/*/* Output: returns a TRUE if endpoint is stalled, FALSE if it is not./*/* Summary: Looks to see if an endpoint is stalled, or not. Does not look to/* see if endpoint has been issued a STALL, just whether or not it is

    /* configured to STALL on the next packet. See Set_Feature and Clear_Feature/* Chapter 9 requests./*/* NOTE: WE ASSUME ENDPOINT IS VALID. USB.C SHOULD CHECK THIS/********************************************************************************/int1 usb_endpoint_stalled(int8 endpoint) { //done int1 direction; int8 st; direction=bit_test(endpoint,7); endpoint&=0x7F; if (direction) {

    st=EP_BDxST_I(endpoint); } else { st=EP_BDxST_O(endpoint); } return(bit_test(st,7) && bit_test(st,2));}

    /*******************************************************************************/* usb_set_address(address)/*/* Input: address - address the host specified that we use

    /*/* Summary: Configures the USB Peripheral for the specified device address. Thehost/* will now talk to use with the following address./*/********************************************************************************/void usb_set_address(int8 address) { //done UADDR=address; if (address) {

  • 8/10/2019 pic18_usb.h

    17/23

    usb_state=USB_STATE_ADDRESS; } else { usb_state=USB_STATE_POWERED; }}

    /*******************************************************************************/* usb_set_configured(config)/*/* Input: config - Configuration to use. 0 to uncofigure device./*/* Summary: Configures or unconfigures device. If configuring device it will/* enable all the endpoints the user specified for this configuration./* If un-configuring device it will disable all endpoints./*/* NOTE: CCS only provides code to handle 1 configuration./*/********************************************************************************/void usb_set_configured(int config) { int8 en; int16 addy;

    int8 new_uep; int16 len; int8 i; if (config==0) { //if config=0 then set addressed state usb_state=USB_STATE_ADDRESS; usb_disable_endpoints(); } else { usb_state=USB_STATE_CONFIGURED; //else set configed state addy=(int16)USB_BUFFER+(2*USB_MAX_EP0_PACKET_LENGTH); for (en=1;en

  • 8/10/2019 pic18_usb.h

    18/23

    new_uep|=0x10; } UEP(en)=new_uep; } }}

    /// END Hardware layer functions required by USB.C

    /// BEGIN USB Interrupt Service Routine

    /*******************************************************************************/* usb_handle_interrupt()/*/* Summary: Checks the interrupt, and acts upon event. Processing finished/* tokens is the majority of this code, and is handled by usb.c/*/* NOTE: If you wish to change to a polling method (and not an interrupt method),/* then you must call this function rapidly. If there is more than 10ms/* latency the PC may think the USB device is stalled and disable it./* To switch to a polling method, remove the #int_usb line above this fuction.

    /* Also, goto usb_init() and remove the code that enables the USB interrupt./********************************************************************************/#int_usbvoid usb_isr() { if (usb_state==USB_STATE_DETACHED) return; //should never happen, though if (UIR) { debug_usb(debug_putc,"\r\n\n[%X] ",UIR); if (UIR_ACTV && UIE_ACTV) {usb_isr_activity();} //activity detected. (only enable after sleep)

    if (UCON_SUSPND) return;

    if (UIR_UERR && UIE_UERR) {usb_isr_uerr();} //error has been detected

    if (UIR_URST && UIE_URST) {usb_isr_rst();} //usb reset has been detected

    if (UIR_IDLE && UIE_IDLE) {usb_isr_uidle();} //idle time, we can goto sleep if (UIR_SOF && UIE_SOF) {usb_isr_sof();} if (UIR_STALL && UIE_STALL) {usb_isr_stall();} //a stall handshakewas sent

    if (UIR_TRN && UIE_TRN) { usb_isr_tok_dne(); UIR_TRN=0; // clear the token done interrupt., 0x190.3 } //a token has been detected (majority of isrs) }}

    //SOF interrupt not handled. user must add this depending on applicationvoid usb_isr_sof(void) { debug_usb(debug_putc,"\r\nSOF");

  • 8/10/2019 pic18_usb.h

    19/23

    UIR_SOF=0;}

    /*******************************************************************************/* usb_disable_endpoints()/*/* Summary: Disables endpoints 1 thru 15/*/********************************************************************************/void usb_disable_endpoints(void) { int8 i; for (i=1;i

  • 8/10/2019 pic18_usb.h

    20/23

    EP_BDxCNT_O(0) = USB_MAX_EP0_PACKET_LENGTH; EP_BDxADR_O(0) = USB_BUFFER; #if USB_IGNORE_RX_DTS EP_BDxST_O(0) = 0x80; //give control to SIE, data toggle synch off #else EP_BDxST_O(0) = 0x88; //give control to SIE, DATA0, data toggle synch on #endif

    EP_BDxST_I(0) = 0; EP_BDxADR_I(0) = USB_BUFFER + (int16)USB_MAX_EP0_PACKET_LENGTH;}

    /*******************************************************************************/* usb_isr_uerr()/*/* Summary: The USB peripheral had an error. If user specified, error counter/* will incerement. If having problems check the status of these 8 bytes./*/* NOTE: This code is not enabled by default./********************************************************************************/void usb_isr_uerr() {#if USB_USE_ERROR_COUNTER

    int ints;#endif

    debug_usb(debug_putc,"E %X ",UEIR);

    #if USB_USE_ERROR_COUNTER

    ints=UEIR & UEIE; //mask off the flags with the ones that are enabled

    if ( bit_test(ints,0) ) { //increment pid_error counter debug_usb(debug_putc,"PID "); ERROR_COUNTER[0]++; }

    if ( bit_test(ints,1) ) { //increment crc5 error counter debug_usbdebug_putc,"CRC5 "); ERROR_COUNTER[1]++; }

    if ( bit_test(ints,2) ) { //increment crc16 error counter debug_usb(debug_putc,"CRC16 "); ERROR_COUNTER[2]++; }

    if ( bit_test(ints,3) ) { //increment dfn8 error counter debug_usb(debug_putc,"DFN8 ");

    ERROR_COUNTER[3]++; }

    if ( bit_test(ints,4) ) { //increment bto error counter debug_usb(debug_putc,"BTO "); ERROR_COUNTER[4]++; }

    if ( bit_test(ints,7) ) { //increment bts error counter debug_usb(debug_putc,"BTS ");

  • 8/10/2019 pic18_usb.h

    21/23

    ERROR_COUNTER[5]++; }#endif

    UEIR=0; UIR_UERR=0;}

    /*******************************************************************************/* usb_isr_uidle()/*/* Summary: USB peripheral detected IDLE. Put the USB peripheral to sleep./*/********************************************************************************/void usb_isr_uidle() { debug_usb(debug_putc,"I");

    UIE_ACTV=1; //enable activity interrupt flag. (we are now suspended until we get an activity interrupt. nice) UIR_IDLE=0; //clear idle interrupt flag UCON_SUSPND=1; //set suspend. we are now suspended}

    /*******************************************************************************/* usb_isr_activity()/*/* Summary: USB peripheral detected activity on the USB device. Wake-up the USB/* peripheral./*/********************************************************************************/void usb_isr_activity() { debug_usb(debug_putc,"A");

    UCON_SUSPND=0; //turn off low power suspending

    UIE_ACTV=0; //clear activity interupt enabling UIR_ACTV=0;}

    /*******************************************************************************/* usb_isr_stall()/*/* Summary: Stall handshake detected./*/********************************************************************************/void usb_isr_stall(void) { debug_usb(debug_putc,"S");

    if (bit_test(UEP(0),0)) { usb_init_ep0_setup(); bit_clear(UEP(0),0); } UIR_STALL=0;}

    /*******************************************************************************

  • 8/10/2019 pic18_usb.h

    22/23

    /* usb_isr_tok_dne()/*/* Summary: A Token (IN/OUT/SETUP) has been received by the USB peripheral./* If a setup token on EP0 was received, run the chapter 9 code and/* handle the request./* If an IN token on EP0 was received, continue transmitting any/* unfinished requests that may take more than one packet to transmit/* (if necessary)./* If an OUT token on any other EP was received, mark that EP as ready/* for a usb_get_packet()./* Does not handle any IN or OUT tokens on EP0./*/********************************************************************************/void usb_isr_tok_dne() { int8 en;

    en=USTAT>>3;

    debug_usb(debug_putc,"T "); debug_usb(debug_putc,"%X ", USTAT);

    if (USTAT==USTAT_OUT_SETUP_E0) { //new out or setup token in the buffer debug_usb(debug_putc,"%X ", EP_BDxST_O(0));

    if ((EP_BDxST_O(0) & 0x3C)==USB_PIC_PID_SETUP) { EP_BDxST_I(0)=0; // return the in buffer to us (dequeue any pending requests)

    debug_usb(debug_putc,"(%U) ", EP_BDxCNT_O(0)); debug_display_ram(EP_BDxCNT_O(0), usb_ep0_rx_buffer);

    usb_isr_tok_setup_dne();

    //if setup_0_tx_size==0xFF - stall ep0 (unhandled request) //if setup_0_tx_size==0xFE - get EP0OUT ready for a data packet, leave EP0IN alone //else setup_0_tx_size=size of response, get EP0OUT ready for a setu

    p packet, mark EPOIN ready for transmit if (__setup_0_tx_size==0xFF) usb_flush_out(0,USB_DTS_STALL); else { usb_flush_out(0,USB_DTS_TOGGLE); if (__setup_0_tx_size!=0xFE) { usb_flush_in(0,__setup_0_tx_size,USB_DTS_USERX); } } UCON_PKTDIS=0; // UCON,PKT_DIS ; Assuming there is nothing todequeue, clear the packet disable bit } else if ((EP_BDxST_O(0) & 0x3C)==USB_PIC_PID_OUT) {

    usb_isr_tok_out_dne(0); usb_flush_out(0,USB_DTS_TOGGLE); if ((__setup_0_tx_size!=0xFE)&&(__setup_0_tx_size!=0xFF)) { usb_flush_in(0,__setup_0_tx_size,USB_DTS_DATA1); //send response (usually a 0len) } } }

    else if (USTAT==USTAT_IN_E0) { //pic -> host transfer completed

  • 8/10/2019 pic18_usb.h

    23/23

    __setup_0_tx_size=0xFF; usb_isr_tok_in_dne(0); if (__setup_0_tx_size!=0xFF) usb_flush_in(0,__setup_0_tx_size,USB_DTS_TOGGLE); else usb_init_ep0_setup(); }

    else { if (!bit_test(USTAT,2)) { usb_isr_tok_out_dne(en); } else { usb_isr_tok_in_dne(en); } }}

    /**************************************************************/* usb_request_send_response(len)/* usb_request_get_data()/* usb_request_stall()/*/* Input: len - size of packet to send

    /*/* Summary: After we process a SETUP request, we have 1 of three responses:/* 1.) send a response IN packet/* 2.) wait for followup OUT packet(s) with data/* 3.) stall because we don't support that SETUP request/*/* If we are sending data, the array usb_ep0_tx_buffer[] will hold/* the response and the USB Request handler code will call/* usb_request_send_response() to let us know how big the packet is./*/* If we are waiting for more data, usb_request_get_data() will/* be called by the USB request handler code to configure the EP0 OUT/* endpoint to be ready for more data

    /*/* If we don't support a request, usb_request_stall() will be called/* by the USB request handler code to stall the endpoint 0./*/***************************************************************/void usb_request_send_response(int len) { __setup_0_tx_size=len;}

    void usb_request_get_data(void) { __setup_0_tx_size=0xFE;}

    void usb_request_stall(void) { __setup_0_tx_size=0xFF;}

    /// END USB Interrupt Service Routine

    #ENDIF