/////////////////////////////////////////////////////////////////////////
//// pic24_usb.c ////
//// ////
//// Hardware layer for CCS's USB library. See pic24_usb.h more ////
//// documentation about the PIC24 hardware layer. ////
//// ////
//// This file is part of CCS's PIC USB driver code. See USB.H ////
//// for more documentation and a list of examples. ////
//// ////
/////////////////////////////////////////////////////////////////////////
//// ////
//// Version History: ////
//// ////
//// March 5th, 2009: ////
//// Cleanup for Wizard. ////
//// PIC24 Initial release. ////
//// ////
/////////////////////////////////////////////////////////////////////////
//// (C) Copyright 1996,2009 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 __PIC24_USB_C__
#DEFINE __PIC24_USB_C__
#INCLUDE <usb.h>
#if USB_EP15_TX_SIZE || USB_EP15_RX_SIZE
#define USB_LAST_DEFINED_ENDPOINT 15
#elif USB_EP14_TX_SIZE || USB_EP14_RX_SIZE
#define USB_LAST_DEFINED_ENDPOINT 14
#elif USB_EP13_TX_SIZE || USB_EP13_RX_SIZE
#define USB_LAST_DEFINED_ENDPOINT 13
#elif USB_EP12_TX_SIZE || USB_EP12_RX_SIZE
#define USB_LAST_DEFINED_ENDPOINT 12
#elif USB_EP11_TX_SIZE || USB_EP11_RX_SIZE
#define USB_LAST_DEFINED_ENDPOINT 11
#elif USB_EP10_TX_SIZE || USB_EP10_RX_SIZE
#define USB_LAST_DEFINED_ENDPOINT 10
#elif USB_EP9_TX_SIZE || USB_EP9_RX_SIZE
#define USB_LAST_DEFINED_ENDPOINT 9
#elif USB_EP8_TX_SIZE || USB_EP8_RX_SIZE
#define USB_LAST_DEFINED_ENDPOINT 8
#elif USB_EP7_TX_SIZE || USB_EP7_RX_SIZE
#define USB_LAST_DEFINED_ENDPOINT 7
#elif USB_EP6_TX_SIZE || USB_EP6_RX_SIZE
#define USB_LAST_DEFINED_ENDPOINT 6
#elif USB_EP5_TX_SIZE || USB_EP5_RX_SIZE
#define USB_LAST_DEFINED_ENDPOINT 5
#elif USB_EP4_TX_SIZE || USB_EP4_RX_SIZE
#define USB_LAST_DEFINED_ENDPOINT 4
#elif USB_EP3_TX_SIZE || USB_EP3_RX_SIZE
#define USB_LAST_DEFINED_ENDPOINT 3
#elif USB_EP2_TX_SIZE || USB_EP2_RX_SIZE
#define USB_LAST_DEFINED_ENDPOINT 2
#elif USB_EP1_TX_SIZE || USB_EP1_RX_SIZE
#define USB_LAST_DEFINED_ENDPOINT 1
#else
#define USB_LAST_DEFINED_ENDPOINT 0
#endif
#define USB_CONTROL_REGISTER_SIZE ((USB_LAST_DEFINED_ENDPOINT+1)*8)
#define USB_DATA_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_DATA_BUFFER_NEEDED+USB_CONTROL_REGISTER_SIZE) > getenv("RAM"))
#error You are trying to allocate more memory for endpoints than the PIC can handle
#endif
//reserve the control space needed
union
{
struct
{
unsigned int16 BDnSTo;
unsigned int16 BDnADo;
unsigned int16 BDnSTi;
unsigned int16 BDnADi;
} ep[USB_LAST_DEFINED_ENDPOINT+1];
char buffer[USB_CONTROL_REGISTER_SIZE];
} usb_endpoint_control_registers;
#locate usb_endpoint_control_registers=0xA00
#error/warning usb_endpoint_control_registers needs to be positioned at the start of a 512 byte boundry
union
{
struct
{
unsigned int8 ep0_rx_buffer[USB_MAX_EP0_PACKET_LENGTH];
unsigned int8 ep0_tx_buffer[USB_MAX_EP0_PACKET_LENGTH];
//these buffer definitions needed for CDC library
#if USB_EP1_RX_SIZE
unsigned int8 ep1_rx_buffer[USB_EP1_RX_SIZE];
#endif
#if USB_EP1_TX_SIZE
unsigned int8 ep1_tx_buffer[USB_EP1_TX_SIZE];
#endif
#if USB_EP2_RX_SIZE
unsigned int8 ep2_rx_buffer[USB_EP2_RX_SIZE];
#endif
#if USB_EP2_TX_SIZE
unsigned int8 ep2_tx_buffer[USB_EP2_TX_SIZE];
#endif
};
unsigned int8 general[USB_DATA_BUFFER_NEEDED];
} g_USBDataBuffer;
#define USB_DATA_BUFFER_LOCATION &g_USBDataBuffer.general[0]
#define usb_ep0_rx_buffer g_USBDataBuffer.ep0_rx_buffer
#define usb_ep0_tx_buffer g_USBDataBuffer.ep0_tx_buffer
//these buffer definitions needed for CDC library
#define usb_ep1_rx_buffer g_USBDataBuffer.ep1_rx_buffer
#define usb_ep1_tx_buffer g_USBDataBuffer.ep1_tx_buffer
#define usb_ep2_rx_buffer g_USBDataBuffer.ep2_rx_buffer
#define usb_ep2_tx_buffer g_USBDataBuffer.ep2_tx_buffer
#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_putc(c)
#define debug_display_ram(x,y)
/*
void debug_putc(char c) {putc(c);}
#define debug_usb printf
*/
/*
void debug_display_ram(unsigned int8 len, int8 *ptr) {
unsigned 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,"...");}
}
*/
//#define debug_putc putc_tbe
//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.
#if !defined(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!
#if !defined(USB_PING_PONG_MODE)
#define USB_PING_PONG_MODE USB_PING_PONG_MODE_OFF
#endif
#if (USB_PING_PONG_MODE==USB_PING_PONG_MODE_OFF)
#define EP_BDxST_O(x) usb_endpoint_control_registers.ep[x].BDnSTo
#define EP_BDxADR_O(x) usb_endpoint_control_registers.ep[x].BDnADo
#define EP_BDxST_I(x) usb_endpoint_control_registers.ep[x].BDnSTi
#define EP_BDxADR_I(x) usb_endpoint_control_registers.ep[x].BDnADi
#else
#error Right now this driver only supports no ping pong
#endif
#define __BDST_UOWN 0x8000 //set = buffer control, clear = cpu control
#define __BDST_DTS 0x4000 //set = data1 packet, clear = data0 packet
#define __BDST_DTSEN 0x0800 //set = dts enabled, clear = disabled
#define __BDST_BSTALL 0x0400 //set = buffer stalled
#if USB_USE_ERROR_COUNTER
int ERROR_COUNTER[6];
#endif
//---pic24 memory locations
#word UOTGIR = 0x480
#word UOTGIE = 0x482
#word UOTGCON = 0x486
#word UPWRC = 0x488
#word UIR = 0x48A
#word UIE = 0x48C
#word UEIR = 0x48E
#word UEIE = 0x490
#word USTAT = 0x492
#word UCON = 0x494
#word UADDR = 0x496
#word UBDTP1 = 0x498
#word UFRML = 0x49A
#word UFRMH = 0x49C
#word UCFG1 = 0x4A6
#word UCFG2 = 0x4A8
#define UEP0_LOC 0x4AA
int16 UEP_SFR[16];
#locate UEP_SFR=UEP0_LOC
#define UEP(x) UEP_SFR[x]
#define UIE_BIT_URST 0
#define UIE_BIT_UERR 1
#define UIE_BIT_SOF 2
#define UIE_BIT_TRN 3
#define UIE_BIT_IDLE 4
#define UIE_BIT_STALL 7
#BIT UIE_SOF = UIE.UIE_BIT_SOF
#BIT UIE_STALL = UIE.UIE_BIT_STALL
#BIT UIE_IDLE = UIE.UIE_BIT_IDLE
#BIT UIE_TRN = UIE.UIE_BIT_TRN
#BIT UIE_UERR = UIE.UIE_BIT_UERR
#BIT UIE_URST = UIE.UIE_BIT_URST
#define UOTGIE_BIT_ACTV 4
#BIT UOTGIE_ACTV=UOTGIE.UOTGIE_BIT_ACTV
#BIT UIR_SOF = UIR.UIE_BIT_SOF
#BIT UIR_STALL = UIR.UIE_BIT_STALL
#BIT UIR_IDLE = UIR.UIE_BIT_IDLE
#BIT UIR_TRN = UIR.UIE_BIT_TRN
#BIT UIR_UERR = UIR.UIE_BIT_UERR
#BIT UIR_URST = UIR.UIE_BIT_URST
#BIT UOTGIR_ACTV=UOTGIR.UOTGIE_BIT_ACTV
#ifndef BIT
#define BIT(x) (1<<x)
#endif
#define __USB_UIF_RESET BIT(UIE_BIT_URST)
#define __USB_UIF_ERROR BIT(UIE_BIT_UERR)
#define __USB_UIF_TOKEN BIT(UIE_BIT_TRN)
#define __USB_UIF_IDLE BIT(UIE_BIT_IDLE)
#define __USB_UIF_STALL BIT(UIE_BIT_STALL)
#define __USB_UIF_SOF BIT(UIE_BIT_SOF)
#if USB_USE_ERROR_COUNTER
#define STANDARD_INTS __USB_UIF_STALL|__USB_UIF_IDLE|__USB_UIF_TOKEN|__USB_UIF_ERROR|__USB_UIF_RESET
#else
#define STANDARD_INTS __USB_UIF_STALL|__USB_UIF_IDLE|__USB_UIF_TOKEN|__USB_UIF_RESET
#endif
//#bit UOTGCON_DPPULUP = UOTGCON.7
//#bit UOTGCON_DPMULUP = UOTGCON.6
#bit UCON_SE0=UCON.6
#bit UCON_PKTDIS=UCON.5
#bit UCON_USBEN=UCON.0
#bit UCON_RESUME=UCON.2
#bit UCON_PPBRST=UCON.1
#bit UPWRC_USBPWR=UPWRC.0
#bit UPWRC_SUSPND=UPWRC.1
#define UCON_SUSPND UPWRC_SUSPND
//See UEPn (0xF70-0xF7F)
#define ENDPT_DISABLED 0x00 //endpoint not used
#define ENDPT_IN_ONLY 0x04 //endpoint supports IN transactions only
#define ENDPT_OUT_ONLY 0x08 //endpoint supports OUT transactions only
#define ENDPT_CONTROL 0x0C //Supports IN, OUT and CONTROL transactions - Only use with EP0
#define ENDPT_NON_CONTROL 0x1C //Supports both IN and OUT transactions
#define __UEP_EPHSK 0x01
//Define the states that the USB interface can be in
enum {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;
#define USTAT_IN_E0 8
#define USTAT_OUT_SETUP_E0 0
#define __USB_UCFG1_UTEYE 0x80
#define __USB_UCFG1_UOEMON 0x40
#define __USB_UCFG2_PUVBUS 0x10 //microchip calls this USB_PULLUP_ENABLE
#define __USB_UCFG2_UTRDIS 0x01 //microchip calls this USB_EXTERNAL_TRANSCEIVER
//#define __UCFG1_VAL_ENABLED__ USB_PING_PONG_MODE
#define __UCFG1_VAL_ENABLED__ USB_PING_PONG_MODE
#define __UCFG2_VAL_ENABLED__ __USB_UCFG2_PUVBUS
#define __UCFG1_VAL_DISABLED__ 0
#define __UCFG2_VAL_DISABLED__ 0
int8 __setup_0_tx_size;
//interrupt handler, specific to PIC24 peripheral only
void usb_handle_interrupt(void);
void usb_isr_rst(void);
void usb_isr_uerr(void);
void usb_isr_sof(void);
void usb_isr_activity(void);
void usb_isr_uidle(void);
void usb_isr_tok_dne(void);
void usb_isr_stall(void);
void usb_init_ep0_setup(void);
//following functions standard part of CCS PIC USB driver, and used by usb.c
unsigned int16 usb_get_packet_buffer(int8 endpoint, int8 *ptr, unsigned int16 max);
static void usb_clear_trn(void);
static void usb_clear_isr_flag(int16 *sfr, int8 bit);
static void usb_clear_isr_reg(int16 *sfr);
//// BEGIN User Functions:
// see usb_hw_layer.h for documentation
int1 usb_kbhit(int8 en)
{
return((UEP(en) != ENDPT_DISABLED) && ((EP_BDxST_O(en) & __BDST_UOWN) == 0));
}
// see usb_hw_layer.h for documentation
int1 usb_tbe(int8 en)
{
return((UEP(en)!=ENDPT_DISABLED) && ((EP_BDxST_I(en) & __BDST_UOWN) == 0));
}
// see usb_hw_layer.h for documentation
void usb_detach(void)
{
UCON = 0; //disable USB hardware
UIE = 0; //disable USB interrupts
usb_clear_isr_reg(&UEIR);
usb_clear_isr_reg(&UIR);
UOTGIE = 0;
UPWRC_USBPWR = 1;
UCFG1 = __UCFG1_VAL_DISABLED__;
UCFG2 = __UCFG2_VAL_DISABLED__;
UCON_PPBRST = 1;
UCON_PPBRST = 0;
//UOTGCON_DPPULUP = 0;
//set_tris_g(get_tris_g() | 0x0C); //set d+/d- pins to input //pin_g2 and pin_g3
usb_state=USB_STATE_DETACHED;
UADDR = 0;
memset(&UEP_SFR
[0], 0x00, sizeof(UEP_SFR
));
memset(&usb_endpoint_control_registers
, 0x00, sizeof(usb_endpoint_control_registers
));
UBDTP1 = &usb_endpoint_control_registers >> 8;
usb_token_reset(); //clear the chapter9 stack
UCON_PKTDIS=0;
//__usb_kbhit_status=0;
/*
UCON = 0; //disable USB hardware
UIE = 0; //disable USB interrupts
usb_state = USB_STATE_DETACHED;
*/
}
// see usb_hw_layer.h for documentation
void usb_init_cs(void)
{
/* microchip
UCON = 0;
UIE = 0;
UEIE = 0;
usb_clear_isr_reg(&UEIR);
usb_clear_isr_reg(&UIR);
UPWRC_USBPWR = 1;
UBDTP1 = &usb_endpoint_control_registers >> 8;
UCON_PPBRST = 1;
UCON_PPBRST = 0;
UADDR = 0;
memset(&UEP_SFR[0], 0x00, sizeof(UEP_SFR));
memset(&usb_endpoint_control_registers, 0x00, sizeof(usb_endpoint_control_registers));
UEP(0) = ENDPT_CONTROL | __UEP_EPHSK;
while (UIR_TRN)
{
usb_clear_trn();
}
UCON_PKTDIS = 0; //enable
usb_state = USB_STATE_ATTACHED; // Defined in usbmmap.c & .h
*/
usb_detach();
/* not sure where this came from
usb_token_reset();
UCON = 0;
UIE = 0; // Mask all USB interrupts
UPWRC_USBPWR = 0;
UCFG1 = __UCFG1_VAL_ENABLED__;
UCFG2 = __UCFG2_VAL_ENABLED__;
//UOTGCON_DPPULUP = 1;
while (!UCON_USBEN) UCON_USBEN = 1; // Enable module & attach to bus
UPWRC_USBPWR = 1;
usb_state = USB_STATE_ATTACHED; // Defined in usbmmap.c & .h
*/
}
// see usb_hw_layer.h for documentation
static void usb_attach(void) {
usb_token_reset();
UCON = 0;
UIE = 0; // Mask all USB interrupts
UCFG1 = __UCFG1_VAL_ENABLED__;
UCFG2 = __UCFG2_VAL_ENABLED__;
while (!UCON_USBEN) {UCON_USBEN = 1;} // Enable module & attach to bus
usb_state = USB_STATE_ATTACHED; // Defined in usbmmap.c & .h
}
// see usb_hw_layer.h for documentation
void usb_task(void) {
if (usb_attached()) {
if (UCON_USBEN==0) {
debug_usb(debug_putc, "\r\n\nUSB TASK: ATTACH");
usb_attach();
//delay_ms(50);
}
}
else {
if (UCON_USBEN==1) {
debug_usb(debug_putc, "\r\n\nUSB TASK: DE-ATTACH");
usb_detach();
}
}
if ((usb_state == USB_STATE_ATTACHED)&&(!UCON_SE0))
{
usb_clear_isr_reg(&UIR);
UIE=0;
enable_interrupts(INT_USB);
enable_interrupts(INTR_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");
}
}
// see usb_hw_layer.h for documentation
void usb_init(void)
{
usb_init_cs();
do
{
usb_task();
} while (usb_state != USB_STATE_POWERED);
}
// see pic24_usb.h for documentation
int1 usb_flush_in(int8 endpoint, unsigned int16 len, USB_DTS_BIT tgl)
{
int16 oldBD, newBD = 0;
debug_usb(debug_putc,"\r\nPUT %X %U %LU %LX", endpoint, tgl, len, EP_BDxST_I(endpoint));
if (usb_tbe(endpoint))
{
newBD = len;
debug_display_ram(len, EP_BDxADR_I(endpoint));
#if USB_IGNORE_TX_DTS
newBD |= __BDST_UOWN;
#else
if (tgl == USB_DTS_TOGGLE)
{
oldBD = EP_BDxST_I(endpoint);
if ((oldBD & __BDST_DTS) == __BDST_DTS) //(bit_test(i,14))
tgl=USB_DTS_DATA0; //was DATA1, goto DATA0
else
tgl=USB_DTS_DATA1; //was DATA0, goto DATA1
}
else if (tgl == USB_DTS_USERX)
{
oldBD = EP_BDxST_O(endpoint);
if ((oldBD & __BDST_DTS) == __BDST_DTS) //(bit_test(i,14))
tgl = USB_DTS_DATA1;
else
tgl = USB_DTS_DATA0;
}
if (tgl == USB_DTS_DATA1)
newBD |= __BDST_UOWN | __BDST_DTS | __BDST_DTSEN; //DATA1, UOWN
else //if (tgl == USB_DTS_DATA0)
newBD |= __BDST_UOWN | __BDST_DTSEN; //DATA0, UOWN
#endif
debug_usb(debug_putc," %X", newBD);
EP_BDxST_I(endpoint) = newBD;//save changes
return(1);
}
else {
debug_usb(debug_putc,"\r\nPUT ERR");
}
return(0);
}
// see usb_hw_layer.h for documentation.
int1 usb_put_packet(int8 endpoint, int8 * ptr, unsigned int16 len, USB_DTS_BIT tgl)
{
int8 * buff_add;
if (usb_tbe(endpoint))
{
buff_add=EP_BDxADR_I(endpoint);
return(usb_flush_in(endpoint, len, tgl));
}
else
{
debug_usb(debug_putc,"\r\nPUT ERR");
}
return(0);
}
/// END User Functions
/// BEGIN Hardware layer functions required by USB.C
// see pic24_usb.h for documentation
void usb_flush_out(int8 endpoint, USB_DTS_BIT tgl)
{
int16 oldBD, newBD;
int16 len;
#if USB_IGNORE_RX_DTS
if (tgl == USB_DTS_STALL)
{
debug_usb(debug_putc, '*');
EP_BDxST_I(endpoint) = __BDST_UOWN | __BDST_BSTALL;
EP_BDxST_O(endpoint) = __BDST_UOWN | __BDST_BSTALL;
return;
}
else
newBD = __BDST_UOWN;
#else
oldBD = EP_BDxST_O(endpoint);
if (tgl == USB_DTS_TOGGLE)
{
if ((oldBD & __BDST_DTS) == __BDST_DTS) //(bit_test(i,14))
tgl = USB_DTS_DATA0; //was DATA1, goto DATA0
else
tgl =USB_DTS_DATA1; //was DATA0, goto DATA1
}
if (tgl == USB_DTS_STALL)
{
newBD = __BDST_UOWN | __BDST_BSTALL;
EP_BDxST_I(endpoint) = __BDST_UOWN | __BDST_BSTALL; //stall both in and out endpoints
}
else if (tgl == USB_DTS_DATA1)
{
newBD = __BDST_UOWN | __BDST_DTS | __BDST_DTSEN; //DATA1, UOWN
}
else //if (tgl == USB_DTS_DATA0)
{
newBD = __BDST_UOWN | __BDST_DTSEN; //DATA0, UOWN
}
#endif
//bit_clear(__usb_kbhit_status,endpoint);
len=usb_ep_rx_size[endpoint];
newBD |= len;
EP_BDxST_O(endpoint) = newBD;
}
// see pic24_usb.h for documentation
unsigned int16 usb_rx_packet_size(int8 endpoint)
{
return(EP_BDxST_O(endpoint) & 0x03FF);
}
/*******************************************************************************
/* 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.
/*
/********************************************************************************/
unsigned int16 usb_get_packet_buffer(int8 endpoint, int8 *ptr, unsigned int16 max)
{
int8 *al;
unsigned int16 i;
al = EP_BDxADR_O(endpoint);
//i = usb_rx_packet_size(endpoint);
i=4;
//printf("\r\nUSB GET PACKET ST:%LX %U I=%LX MAX=%LX %X%X ", EP_BDxST_O(endpoint), endpoint, i, max, al[0], al[1]);
if (i<max) {max=i;}
if (max > 1)
else if (max == 1)
*ptr = *al;
//printf("%X%X\r\n", ptr[0], ptr[1]);
return(max);
}
// see usb_hw_layer.h
unsigned int16 usb_get_packet(int8 endpoint, int8 * ptr, unsigned int16 max)
{
max=usb_get_packet_buffer(endpoint,ptr,max);
usb_flush_out(endpoint, USB_DTS_TOGGLE);
return(max);
}
// see usb_hw_layer.h
void usb_stall_ep(int8 endpoint)
{
int1 direction;
direction=bit_test(endpoint,7);
endpoint&=0x7F;
if (direction)
{
EP_BDxST_I(endpoint) = __BDST_UOWN | __BDST_BSTALL;
}
else
{
EP_BDxST_O(endpoint) = __BDST_UOWN | __BDST_BSTALL;
}
}
// see usb_hw_layer.h for documentation
void usb_unstall_ep(int8 endpoint)
{
int1 direction;
direction=bit_test(endpoint,7);
endpoint&=0x7F;
if (direction) {
#if USB_IGNORE_RX_DTS
EP_BDxST_I(endpoint) = __BDST_UOWN;
#else
EP_BDxST_I(endpoint) = __BDST_UOWN | __BDST_DTSEN;
#endif
}
else {
EP_BDxST_O(endpoint) = 0x00;
}
}
// see usb_hw_layer.h for documentation
int1 usb_endpoint_stalled(int8 endpoint)
{
int1 direction;
int16 st;
direction = bit_test(endpoint,7);
endpoint &= 0x7F;
if (direction)
{
st = EP_BDxST_I(endpoint);
}
else
{
st = EP_BDxST_O(endpoint);
}
return(
((st & __BDST_UOWN) == __BDST_UOWN) &&
((st & __BDST_UOWN) == __BDST_BSTALL)
);
}
// see usb_hw_layer.h for documentation
void usb_set_address(int8 address)
{
UADDR = address;
if (address)
usb_state = USB_STATE_ADDRESS;
else
usb_state = USB_STATE_POWERED;
}
// see usb_hw_layer.h for documentation
void usb_set_configured(int8 config)
{
unsigned int8 en;
unsigned int16 addy;
int8 new_uep;
unsigned int16 len;
int16 newBD;
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 = USB_DATA_BUFFER_LOCATION + (2*USB_MAX_EP0_PACKET_LENGTH); //skip ep0
for (en=1; en<16; en++)
{
usb_disable_endpoint(en);
new_uep = 0;
if (usb_ep_rx_type[en] != USB_ENABLE_DISABLED)
{
new_uep = ENDPT_OUT_ONLY;
len = usb_ep_rx_size[en];
EP_BDxADR_O(en) = addy;
addy += usb_ep_rx_size[en];
#if USB_IGNORE_RX_DTS
newBD = __BDST_UOWN;
#else
newBD = __BDST_UOWN | __BDST_DTSEN;
#endif
newBD |= len;
EP_BDxST_O(en) = newBD;
}
if (usb_ep_tx_type[en] != USB_ENABLE_DISABLED)
{
new_uep |= ENDPT_IN_ONLY;
EP_BDxADR_I(en) = addy;
addy += usb_ep_tx_size[en];
EP_BDxST_I(en) = __BDST_DTS;
}
if (new_uep == (ENDPT_IN_ONLY | ENDPT_OUT_ONLY))
new_uep = ENDPT_NON_CONTROL;
if (usb_ep_tx_type[en] != USB_ENABLE_ISOCHRONOUS)
new_uep |= __UEP_EPHSK;
UEP(en)=new_uep;
}
}
}
/// END Hardware layer functions required by USB.C
/// BEGIN USB Interrupt Service Routine
static void usb_clear_trn(void)
{
usb_clear_isr_flag(&UIR, UIE_BIT_TRN);
delay_cycles(6);
}
/*******************************************************************************
/* 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_usb
void usb_isr(void)
{
int8 TRNAttempts = 0;
debug_putc('.');
if (usb_state==USB_STATE_DETACHED) return; //should never happen, though
if (UIR || UOTGIR)
{
//debug_usb(debug_putc,"\r\n\n[%X%X%U] ",(int8)UIR, (int8)UOTGIR, UCON_SUSPND);
if (UOTGIR_ACTV && UOTGIE_ACTV) {usb_isr_activity();} //activity detected. (only enable after sleep)
if (UCON_SUSPND) return;
if (UIR_STALL && UIE_STALL) {usb_isr_stall();} //a stall handshake was sent
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 go to sleep
if (UIR_SOF && UIE_SOF) {usb_isr_sof();}
//if (UIR_STALL && UIE_STALL) {usb_isr_stall();} //a stall handshake was sent
do
{
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)
else
break;
}
while (TRNAttempts++ < 4);
}
}
//SOF interrupt not handled. user must add this depending on application
void usb_isr_sof(void)
{
debug_usb(debug_putc,"\r\nSOF");
usb_clear_isr_flag(&UIR, UIE_BIT_SOF);
}
// see usb_hw_layer.h for documentation
void usb_disable_endpoint(int8 en)
{
UEP(en)=ENDPT_DISABLED;
EP_BDxST_O(en) = 0; //clear state, deque if necessary
EP_BDxST_I(en) = 0; //clear state, deque if necessary
}
// see usb_hw_layer.h for documentation
void usb_disable_endpoints(void)
{
unsigned int8 i;
for (i=1;i<16;i++)
usb_disable_endpoint(i);
//__usb_kbhit_status=0;
}
/*******************************************************************************
/* usb_isr_rst()
/*
/* Summary: The host (computer) sent us a RESET command. Reset USB device
/* and token handler code to initial state.
/*
/********************************************************************************/
void usb_isr_rst(void) {
debug_usb(debug_putc,"R");
usb_clear_isr_reg(&UEIR);
usb_clear_isr_reg(&UIR);
UEIE = 0x9F;
UIE = STANDARD_INTS;
UADDR=0;
usb_token_reset();
usb_disable_endpoints();
UEP(0) = ENDPT_CONTROL | __UEP_EPHSK;
while (UIR_TRN)
{
usb_clear_trn();
}
UCON_PKTDIS=0; //SIE token and packet processing enabled
usb_init_ep0_setup();
usb_state=USB_STATE_DEFAULT; //put usb mcu into default state
}
/*****************************************************************************
/* usb_init_ep0_setup()
/*
/* Summary: Configure EP0 to receive setup packets
/*
/*****************************************************************************/
void usb_init_ep0_setup(void)
{
int16 newBD;
newBD = USB_MAX_EP0_PACKET_LENGTH;
EP_BDxADR_O(0) = USB_DATA_BUFFER_LOCATION;
#if USB_IGNORE_RX_DTS
newBD |= __BDST_UOWN;
#else
newBD |= __BDST_UOWN | __BDST_DTSEN; //give control to SIE, DATA0, data toggle synch on
#endif
EP_BDxST_O(0) = newBD;
EP_BDxST_I(0) = 0;
EP_BDxADR_I(0) = USB_DATA_BUFFER_LOCATION + (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(void) {
#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_usb(debug_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 ");
ERROR_COUNTER[5]++;
}
#endif
usb_clear_isr_reg(&UEIR);
usb_clear_isr_flag(&UIR, UIE_BIT_UERR);
}
/*******************************************************************************
/* usb_isr_uidle()
/*
/* Summary: USB peripheral detected IDLE. Put the USB peripheral to sleep.
/*
/********************************************************************************/
void usb_isr_uidle(void)
{
debug_usb(debug_putc,"I");
UOTGIE_ACTV=1; //enable activity interrupt flag.
usb_clear_isr_flag(&UIR, UIE_BIT_IDLE);
//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(void)
{
debug_usb(debug_putc,"A");
UCON_SUSPND=0; //turn off low power suspending
UOTGIE_ACTV=0; //clear activity interupt enabling
usb_clear_isr_flag(&UOTGIR, UOTGIE_BIT_ACTV);
}
/*******************************************************************************
/* usb_isr_stall()
/*
/* Summary: Stall handshake detected.
/*
/********************************************************************************/
void usb_isr_stall(void)
{
debug_usb(debug_putc,"S");
if (bit_test(UEP(0),1)) {
usb_init_ep0_setup();
bit_clear(UEP(0),1);
}
usb_clear_isr_flag(&UIR, UIE_BIT_STALL);
}
/*******************************************************************************
/* 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(void)
{
int8 en;
en=USTAT>>4;
debug_usb(debug_putc,"T ");
debug_usb(debug_putc,"%X ", USTAT);
if ((USTAT & 0x00F8) == USTAT_OUT_SETUP_E0)
{
//new out or setup token in the buffer
int16 pidKey;
debug_usb(debug_putc,"%LX ", EP_BDxST_O(0));
pidKey = EP_BDxST_O(0) & (int16)0x3C00; //save PID
pidKey >>= 10;
EP_BDxST_O(0) &= (int16)0x43FF; //clear pid, prevent bdstal/pid confusion
usb_clear_trn();
if (pidKey == PID_SETUP)
{
EP_BDxST_I(0)=0; // return the in buffer to us (dequeue any pending requests)
debug_usb(debug_putc,"%LU ", EP_BDxST_O(0) & 0x3FF);
debug_display_ram(EP_BDxST_O(0) & 0x3FF, usb_ep0_rx_buffer);
usb_isr_tok_setup_dne();
UCON_PKTDIS=0; // UCON,PKT_DIS ; Assuming there is nothing to dequeue, clear the packet disable bit
//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 setup 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);
}
//why was this here?
//UCON_PKTDIS=0; // UCON,PKT_DIS ; Assuming there is nothing to dequeue, clear the packet disable bit
}
else if (pidKey == 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 & 0x00F8) == USTAT_IN_E0)
{
//pic -> host transfer completed
EP_BDxST_I(0) = EP_BDxST_I(0) & 0x4300; //clear up any BDSTAL confusion
usb_clear_trn();
__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, 3))
{
EP_BDxST_O(en) = EP_BDxST_O(en) & 0x43FF; //clear up any BDSTAL confusion
usb_clear_trn();
usb_isr_tok_out_dne(en);
}
else
{
EP_BDxST_I(en) = EP_BDxST_I(en) & 0x4300; //clear up any BDSTAL confusion
usb_clear_trn();
usb_isr_tok_in_dne(en);
}
}
}
// see usb_hw_layer.h for documentation
void usb_request_send_response(unsigned int8 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
static void usb_clear_isr_flag(int16 *sfr, int8 bit)
{
*sfr = (int16)1 << bit;
}
static void usb_clear_isr_reg(int16 *sfr)
{
*sfr = 0xFFFF;
}
#ENDIF