/**************************************************************************//** * Copyright (c) 2015 by Silicon Laboratories Inc. All rights reserved. * * http://developer.silabs.com/legal/version/v11/Silicon_Labs_Software_License_Agreement.txt *****************************************************************************/ #include "si_toolchain.h" #include "efm8_usb.h" #include #include extern SI_SEGMENT_VARIABLE(myUsbDevice, USBD_Device_TypeDef, MEM_MODEL_SEG); // ----------------------------------------------------------------------------- // Function Prototypes // ------------------------------- // Memory-specific FIFO access functions #ifdef SI_GPTR static void USB_ReadFIFO_Idata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_IDATA), uint8_t fifoNum); static void USB_WriteFIFO_Idata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_IDATA)); static void USB_ReadFIFO_Xdata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_XDATA), uint8_t fifoNum); static void USB_WriteFIFO_Xdata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_XDATA)); #if SI_GPTR_MTYPE_PDATA != SI_GPTR_MTYPE_XDATA static void USB_ReadFIFO_Pdata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_PDATA), uint8_t fifoNum); static void USB_WriteFIFO_Pdata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_PDATA)); #endif #if SI_GPTR_MTYPE_DATA != SI_GPTR_MTYPE_IDATA static void USB_ReadFIFO_Data(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_DATA), uint8_t fifoNum); static void USB_WriteFIFO_Data(uint8_t numBytes, uint8_t SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_DATA)); #endif static void USB_WriteFIFO_Code(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_CODE)); #else // ------------------------------- // Generic FIFO access functions static void USB_ReadFIFO_Generic(uint8_t numBytes, uint8_t *dat, uint8_t fifoNum); static void USB_WriteFIFO_Generic(uint8_t numBytes, uint8_t *dat); #endif // #ifdef SI_GPTR // ----------------------------------------------------------------------------- // Functions /***************************************************************************//** * @brief Reads Isochronous data from the Endpoint FIFO * @param fifoNum * USB Endpoint FIFO to read * @param numBytes * Number of bytes to read from the FIFO * @param dat * Pointer to buffer to hold data read from the FIFO ******************************************************************************/ #if (SLAB_USB_EP3OUT_USED && (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC) && (SLAB_USB_EP3OUT_MAX_PACKET_SIZE > 255)) // ---------------------------------------------------------------------------- // If Isochronous mode is enabled and the max packet size is greater than 255, // break the FIFO reads up into multiple reads of 255 or less bytes. // ---------------------------------------------------------------------------- void USB_ReadFIFOIso(uint8_t fifoNum, uint16_t numBytes, uint8_t *dat) { uint8_t numBytesRead; // USB_ReadFIFO() accepts a maximum of 255 bytes. If the number of bytes to // send is greated than 255, call USB_ReadFIFO() multiple times. while (numBytes > 0) { numBytesRead = (numBytes > 255) ? 255 : numBytes; USB_ReadFIFO(fifoNum, numBytesRead, dat); numBytes -= numBytesRead; dat += numBytesRead; } } #else #define USB_ReadFIFOIso(a, b, c) USB_ReadFIFO(a, b, c) #endif /***************************************************************************//** * @brief Writes Isochronous data to the Endpoint FIFO * @param fifoNum * USB Endpoint FIFO to write * @param numBytes * Number of bytes to write to the FIFO * @param dat * Pointer to buffer hoding data to write to the FIFO ******************************************************************************/ #if (SLAB_USB_EP3IN_USED && (SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_ISOC) && (SLAB_USB_EP3IN_MAX_PACKET_SIZE > 255)) // ---------------------------------------------------------------------------- // If Isochronous mode is enabled and the max packet size is greater than 255, // break the FIFO writes up into multiple writes of 255 or less bytes. // ---------------------------------------------------------------------------- void USB_WriteFIFOIso(uint8_t fifoNum, uint16_t numBytes, uint8_t *dat) { uint8_t numBytesWrite; // USB_WriteFIFO() accepts a maximum of 255 bytes. If the number of bytes to // send is greated than 255, call USB_WriteFIFO() multiple times. while (numBytes > 0) { numBytesWrite = (numBytes > 255) ? 255 : numBytes; numBytes -= numBytesWrite; USB_WriteFIFO(fifoNum, numBytesWrite, dat, (numBytes == 0)); dat += numBytesWrite; } } #else #define USB_WriteFIFOIso(a, b, c) USB_WriteFIFO(a, b, c, true) #endif #if SLAB_USB_EP1IN_USED /***************************************************************************//** * @brief Handle Endpoint 1 IN transfer interrupt * @note This function takes no parameters, but it uses the EP1IN status * variables stored in @ref myUsbDevice.ep1in. ******************************************************************************/ void handleUsbIn1Int(void) { uint8_t xferred; bool callback; USB_SetIndex(1); if (USB_EpnInGetSentStall()) { USB_EpnInClearSentStall(); } else if (myUsbDevice.ep1in.state == D_EP_TRANSMITTING) { xferred = (myUsbDevice.ep1in.remaining > SLAB_USB_EP1IN_MAX_PACKET_SIZE) ? SLAB_USB_EP1IN_MAX_PACKET_SIZE : myUsbDevice.ep1in.remaining; myUsbDevice.ep1in.remaining -= xferred; myUsbDevice.ep1in.buf += xferred; callback = myUsbDevice.ep1in.misc.bits.callback; // Load more data if (myUsbDevice.ep1in.remaining > 0) { USB_WriteFIFO(1, (myUsbDevice.ep1in.remaining > SLAB_USB_EP1IN_MAX_PACKET_SIZE) ? SLAB_USB_EP1IN_MAX_PACKET_SIZE : myUsbDevice.ep1in.remaining, myUsbDevice.ep1in.buf, true); } else { myUsbDevice.ep1in.misc.bits.callback = false; myUsbDevice.ep1in.state = D_EP_IDLE; } if (callback == true) { USBD_XferCompleteCb(EP1IN, USB_STATUS_OK, xferred, myUsbDevice.ep1in.remaining); } } } #endif // SLAB_USB_EP1IN_USED #if SLAB_USB_EP2IN_USED /***************************************************************************//** * @brief Handle Endpoint 2 IN transfer interrupt * @note This function takes no parameters, but it uses the EP2IN status * variables stored in @ref myUsbDevice.ep2in. ******************************************************************************/ void handleUsbIn2Int(void) { uint8_t xferred; bool callback; USB_SetIndex(2); if (USB_EpnInGetSentStall()) { USB_EpnInClearSentStall(); } else if (myUsbDevice.ep2in.state == D_EP_TRANSMITTING) { xferred = (myUsbDevice.ep2in.remaining > SLAB_USB_EP2IN_MAX_PACKET_SIZE) ? SLAB_USB_EP2IN_MAX_PACKET_SIZE : myUsbDevice.ep2in.remaining; myUsbDevice.ep2in.remaining -= xferred; myUsbDevice.ep2in.buf += xferred; callback = myUsbDevice.ep2in.misc.bits.callback; // Load more data if (myUsbDevice.ep2in.remaining > 0) { USB_WriteFIFO(2, (myUsbDevice.ep2in.remaining > SLAB_USB_EP2IN_MAX_PACKET_SIZE) ? SLAB_USB_EP2IN_MAX_PACKET_SIZE : myUsbDevice.ep2in.remaining, myUsbDevice.ep2in.buf, true); } else { myUsbDevice.ep2in.misc.bits.callback = false; myUsbDevice.ep2in.state = D_EP_IDLE; } if (callback == true) { USBD_XferCompleteCb(EP2IN, USB_STATUS_OK, xferred, myUsbDevice.ep2in.remaining); } } } #endif // SLAB_USB_EP2IN_USED #if SLAB_USB_EP3IN_USED /***************************************************************************//** * @brief Handle Endpoint 3 IN transfer interrupt * @details Endpoint 3 IN is the only IN endpoint that supports isochronous * transfers. * @note This function takes no parameters, but it uses the EP3IN status * variables stored in @ref myUsbDevice.ep3in. ******************************************************************************/ void handleUsbIn3Int(void) { #if SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_ISOC uint16_t xferred, nextIdx; #else uint8_t xferred; bool callback; #endif USB_SetIndex(3); if (USB_EpnInGetSentStall()) { USB_EpnInClearSentStall(); } else if (myUsbDevice.ep3in.state == D_EP_TRANSMITTING) { #if ((SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_BULK) || (SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_INTR)) xferred = (myUsbDevice.ep3in.remaining > SLAB_USB_EP3IN_MAX_PACKET_SIZE) ? SLAB_USB_EP3IN_MAX_PACKET_SIZE : myUsbDevice.ep3in.remaining; myUsbDevice.ep3in.remaining -= xferred; myUsbDevice.ep3in.buf += xferred; #endif #if ((SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_BULK) || (SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_INTR)) callback = myUsbDevice.ep3in.misc.bits.callback; #elif (SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_ISOC) if (myUsbDevice.ep3in.misc.bits.callback == true) { // In Isochronous mode, the meaning of the USBD_XferCompleteCb parameters changes: // xferred is ignored // remaining is the current index into the circular buffer // the return value is the number of bytes to transmit in the next packet xferred = USBD_XferCompleteCb(EP3IN, USB_STATUS_OK, 0, myUsbDevice.ep3inIsoIdx); if (xferred == 0) { myUsbDevice.ep3in.misc.bits.inPacketPending = true; return; } } #endif // Load more data #if ((SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_BULK) || (SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_INTR)) if (myUsbDevice.ep3in.remaining > 0) { USB_WriteFIFO(3, (myUsbDevice.ep3in.remaining > SLAB_USB_EP3IN_MAX_PACKET_SIZE) ? SLAB_USB_EP3IN_MAX_PACKET_SIZE : myUsbDevice.ep3in.remaining, myUsbDevice.ep3in.buf, true); } else { myUsbDevice.ep3in.misc.bits.callback = false; myUsbDevice.ep3in.state = D_EP_IDLE; } if (callback == true) { USBD_XferCompleteCb(EP3IN, USB_STATUS_OK, xferred, myUsbDevice.ep3in.remaining); } #elif (SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_ISOC) nextIdx = xferred + myUsbDevice.ep3inIsoIdx; myUsbDevice.ep3in.misc.bits.inPacketPending = false; // Check if the next index is past the end of the circular buffer. // If so, break the write up into two calls to USB_WriteFIFOIso() if (nextIdx > myUsbDevice.ep3in.remaining) { USB_WriteFIFOIso(3, myUsbDevice.ep3in.remaining - myUsbDevice.ep3inIsoIdx, &myUsbDevice.ep3in.buf[myUsbDevice.ep3inIsoIdx]); myUsbDevice.ep3inIsoIdx = nextIdx - myUsbDevice.ep3in.remaining; USB_WriteFIFOIso(3, myUsbDevice.ep3inIsoIdx, myUsbDevice.ep3in.buf); } else { USB_WriteFIFOIso(3, xferred, &myUsbDevice.ep3in.buf[myUsbDevice.ep3inIsoIdx]); myUsbDevice.ep3inIsoIdx = nextIdx; } #endif // ( ( SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_BULK ) || ( SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_INTR ) ) } } #endif // SLAB_USB_EP3IN_USED #if SLAB_USB_EP1OUT_USED /***************************************************************************//** * @brief Handle Endpoint 1 OUT transfer interrupt * @note This function takes no parameters, but it uses the EP1OUT status * variables stored in @ref myUsbDevice.ep1out. ******************************************************************************/ void handleUsbOut1Int(void) { uint8_t count; USB_Status_TypeDef status; bool xferComplete = false; USB_SetIndex(1); if (USB_EpnOutGetSentStall()) { USB_EpnOutClearSentStall(); } else if (USB_EpnGetOutPacketReady()) { count = USB_EpOutGetCount(); // If USBD_Read() has not been called, return an error if (myUsbDevice.ep1out.state != D_EP_RECEIVING) { myUsbDevice.ep1out.misc.bits.outPacketPending = true; status = USB_STATUS_EP_ERROR; } // Check for overrun of user buffer else if (myUsbDevice.ep1out.remaining < count) { myUsbDevice.ep1out.state = D_EP_IDLE; myUsbDevice.ep1out.misc.bits.outPacketPending = true; status = USB_STATUS_EP_RX_BUFFER_OVERRUN; } else { USB_ReadFIFO(1, count, myUsbDevice.ep1out.buf); myUsbDevice.ep1out.misc.bits.outPacketPending = false; myUsbDevice.ep1out.remaining -= count; myUsbDevice.ep1out.buf += count; if ((myUsbDevice.ep1out.remaining == 0) || (count != SLAB_USB_EP1OUT_MAX_PACKET_SIZE)) { myUsbDevice.ep1out.state = D_EP_IDLE; xferComplete = true; } status = USB_STATUS_OK; USB_EpnClearOutPacketReady(); } if (myUsbDevice.ep1out.misc.bits.callback == true) { if (xferComplete == true) { myUsbDevice.ep1out.misc.bits.callback = false; } USBD_XferCompleteCb(EP1OUT, status, count, myUsbDevice.ep1out.remaining); } } } #endif // EP1OUT_USED #if SLAB_USB_EP2OUT_USED /***************************************************************************//** * @brief Handle Endpoint 2 OUT transfer interrupt * @note This function takes no parameters, but it uses the EP2OUT status * variables stored in @ref myUsbDevice.ep2out. ******************************************************************************/ void handleUsbOut2Int(void) { uint8_t count; USB_Status_TypeDef status; bool xferComplete = false; USB_SetIndex(2); if (USB_EpnOutGetSentStall()) { USB_EpnOutClearSentStall(); } else if (USB_EpnGetOutPacketReady()) { count = USB_EpOutGetCount(); // If USBD_Read() has not been called, return an error if (myUsbDevice.ep2out.state != D_EP_RECEIVING) { myUsbDevice.ep2out.misc.bits.outPacketPending = true; status = USB_STATUS_EP_ERROR; } // Check for overrun of user buffer else if (myUsbDevice.ep2out.remaining < count) { myUsbDevice.ep2out.state = D_EP_IDLE; myUsbDevice.ep2out.misc.bits.outPacketPending = true; status = USB_STATUS_EP_RX_BUFFER_OVERRUN; } else { USB_ReadFIFO(2, count, myUsbDevice.ep2out.buf); myUsbDevice.ep2out.misc.bits.outPacketPending = false; myUsbDevice.ep2out.remaining -= count; myUsbDevice.ep2out.buf += count; if ((myUsbDevice.ep2out.remaining == 0) || (count != SLAB_USB_EP2OUT_MAX_PACKET_SIZE)) { myUsbDevice.ep2out.state = D_EP_IDLE; xferComplete = true; } status = USB_STATUS_OK; USB_EpnClearOutPacketReady(); } if (myUsbDevice.ep2out.misc.bits.callback == true) { if (xferComplete == true) { myUsbDevice.ep2out.misc.bits.callback = false; } USBD_XferCompleteCb(EP2OUT, status, count, myUsbDevice.ep2out.remaining); } } } #endif // EP2OUT_USED #if SLAB_USB_EP3OUT_USED /***************************************************************************//** * @brief Handle Endpoint 3 OUT transfer interrupt * @details Endpoint 3 OUT is the only OUT endpoint that supports * isochronous transfers. * @note This function takes no parameters, but it uses the EP3OUT status * variables stored in @ref myUsbDevice.ep3out. ******************************************************************************/ void handleUsbOut3Int(void) { #if (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC) uint16_t nextIdx; #if (SLAB_USB_EP3OUT_MAX_PACKET_SIZE > 255) uint16_t count; #else uint8_t count; #endif // ( SLAB_USB_EP3OUT_MAX_PACKET_SIZE > 255 ) #else uint8_t count; #endif // ( SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC ) USB_Status_TypeDef status; bool xferComplete = false; USB_SetIndex(3); if (USB_EpnOutGetSentStall()) { USB_EpnOutClearSentStall(); } else if (USB_EpnGetOutPacketReady()) { count = USB_EpOutGetCount(); // If USBD_Read() has not been called, return an error if (myUsbDevice.ep3out.state != D_EP_RECEIVING) { myUsbDevice.ep3out.misc.bits.outPacketPending = true; status = USB_STATUS_EP_ERROR; } #if ((SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_BULK) || (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_INTR)) // Check for overrun of user buffer else if (myUsbDevice.ep3out.remaining < count) { myUsbDevice.ep3out.state = D_EP_IDLE; myUsbDevice.ep3out.misc.bits.outPacketPending = true; status = USB_STATUS_EP_RX_BUFFER_OVERRUN; } #endif else { #if ((SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_BULK) || (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_INTR)) USB_ReadFIFO(3, count, myUsbDevice.ep3out.buf); myUsbDevice.ep3out.remaining -= count; myUsbDevice.ep3out.buf += count; if ((myUsbDevice.ep3out.remaining == 0) || (count != SLAB_USB_EP3OUT_MAX_PACKET_SIZE)) { myUsbDevice.ep3out.state = D_EP_IDLE; xferComplete = true; } #elif (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC) nextIdx = count + myUsbDevice.ep3outIsoIdx; // In isochronous mode, a circular buffer is used to hold the data // If the next index into the circular buffer passes the end of the // buffer, make two calls to USB_ReadFIFOIso() if (nextIdx > myUsbDevice.ep3out.remaining) { USB_ReadFIFOIso(3, myUsbDevice.ep3out.remaining - myUsbDevice.ep3outIsoIdx, &myUsbDevice.ep3out.buf[myUsbDevice.ep3outIsoIdx]); myUsbDevice.ep3outIsoIdx = nextIdx - myUsbDevice.ep3out.remaining; USB_ReadFIFOIso(3, myUsbDevice.ep3outIsoIdx, myUsbDevice.ep3out.buf); } else { USB_ReadFIFOIso(3, count, &myUsbDevice.ep3out.buf[myUsbDevice.ep3outIsoIdx]); myUsbDevice.ep3outIsoIdx = nextIdx; } #endif // ( ( SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_BULK ) || ( SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_INTR ) ) myUsbDevice.ep3out.misc.bits.outPacketPending = false; status = USB_STATUS_OK; USB_EpnClearOutPacketReady(); } if (myUsbDevice.ep3out.misc.bits.callback == true) { if (xferComplete == true) { myUsbDevice.ep3out.misc.bits.callback = false; } #if ((SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_BULK) || (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_INTR)) USBD_XferCompleteCb(EP3OUT, status, count, myUsbDevice.ep3out.remaining); #elif (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC) // In Isochronous mode, the meaning of the USBD_XferCompleteCb parameters changes: // xferred is the number of bytes received in the last packet // remaining is the current index into the circular buffer USBD_XferCompleteCb(EP3OUT, status, count, myUsbDevice.ep3outIsoIdx); #endif } } } #endif // EP3OUT_USED /***************************************************************************//** * @brief Reads data from the USB FIFO * @param fifoNum * USB Endpoint FIFO to read * @param numBytes * Number of bytes to read from the FIFO * @param dat * Pointer to buffer to hold data read from the FIFO ******************************************************************************/ void USB_ReadFIFO(uint8_t fifoNum, uint8_t numBytes, uint8_t *dat) { if (numBytes > 0) { USB_EnableReadFIFO(fifoNum); // Convert generic pointer to memory-specific pointer and call the // the corresponding memory-specific function, if possible. // The memory-specific functions are much faster than the generic functions. #ifdef SI_GPTR switch (((SI_GEN_PTR_t *)&dat)->gptr.memtype) { case SI_GPTR_MTYPE_IDATA: USB_ReadFIFO_Idata(numBytes, dat, fifoNum); break; // For some compilers, IDATA and DATA are treated the same. // Only call the USB_ReadFIFO_Data() if the compiler differentiates // between DATA and IDATA. #if (SI_GPTR_MTYPE_DATA != SI_GPTR_MTYPE_IDATA) case SI_GPTR_MTYPE_DATA: USB_ReadFIFO_Data(numBytes, dat, fifoNum); break; #endif case SI_GPTR_MTYPE_XDATA: USB_ReadFIFO_Xdata(numBytes, dat, fifoNum); break; // For some compilers, XDATA and PDATA are treated the same. // Only call the USB_ReadFIFO_Pdata() if the compiler differentiates // between XDATA and PDATA. #if (SI_GPTR_MTYPE_PDATA != SI_GPTR_MTYPE_XDATA) case SI_GPTR_MTYPE_PDATA: USB_ReadFIFO_Pdata(numBytes, dat, fifoNum); break; #endif default: break; } #else USB_ReadFIFO_Generic(numBytes, dat, fifoNum); #endif // #ifdef SI_GPTR USB_DisableReadFIFO(fifoNum); } } /***************************************************************************//** * @brief Writes data to the USB FIFO * @param fifoNum * USB Endpoint FIFO to write * @param numBytes * Number of bytes to write to the FIFO * @param dat * Pointer to buffer hoding data to write to the FIFO * @param txPacket * If TRUE, the packet will be sent immediately after loading the * FIFO * If FALSE, the packet will be stored in the FIFO and the * transmission must be started at a later time ******************************************************************************/ void USB_WriteFIFO(uint8_t fifoNum, uint8_t numBytes, uint8_t *dat, bool txPacket) { USB_EnableWriteFIFO(fifoNum); // Convert generic pointer to memory-specific pointer and call the // the corresponding memory-specific function, if possible. // The memory-specific functions are much faster than the generic functions. #ifdef SI_GPTR switch (((SI_GEN_PTR_t *)&dat)->gptr.memtype) { case SI_GPTR_MTYPE_IDATA: USB_WriteFIFO_Idata(numBytes, dat); break; // For some compilers, IDATA and DATA are treated the same. // Only call the USB_WriteFIFO_Data() if the compiler differentiates between // DATA and IDATA. #if (SI_GPTR_MTYPE_DATA != SI_GPTR_MTYPE_IDATA) case SI_GPTR_MTYPE_DATA: USB_WriteFIFO_Data(numBytes, dat); break; #endif case SI_GPTR_MTYPE_XDATA: USB_WriteFIFO_Xdata(numBytes, dat); break; // For some compilers, XDATA and PDATA are treated the same. // Only call the USB_WriteFIFO_Pdata() if the compiler differentiates // between XDATA and PDATA. #if (SI_GPTR_MTYPE_PDATA != SI_GPTR_MTYPE_XDATA) case SI_GPTR_MTYPE_PDATA: USB_WriteFIFO_Pdata(numBytes, dat); break; #endif case SI_GPTR_MTYPE_CODE: USB_WriteFIFO_Code(numBytes, dat); break; default: break; } #else USB_WriteFIFO_Generic(numBytes, dat); #endif // #ifdef SI_GPTR USB_DisableWriteFIFO(fifoNum); if ((txPacket == true) && (fifoNum > 0)) { USB_SetIndex(fifoNum); USB_EpnSetInPacketReady(); } } // ----------------------------------------------------------------------------- // Memory-Specific FIFO Access Functions // // Memory-specific functions are much faster (more than 2x) than generic // generic functions, so we will use memory-specific functions if possible. // ----------------------------------------------------------------------------- #ifdef SI_GPTR /***************************************************************************//** * @brief Reads data from the USB FIFO to a buffer in IRAM * @param numBytes * Number of bytes to read from the FIFO * @param dat * Pointer to IDATA buffer to hold data read from the FIFO * @param fifoNum * USB FIFO to read ******************************************************************************/ static void USB_ReadFIFO_Idata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_IDATA), uint8_t fifoNum) { while (--numBytes) { USB_GetFIFOByte(dat); dat++; } USB_GetLastFIFOByte(dat, fifoNum); } /***************************************************************************//** * @brief Writes data held in IRAM to the USB FIFO * @details The FIFO to write must be set before calling the function with * @ref USB_EnableWriteFIFO(). * @param numBytes * Number of bytes to write to the FIFO * @param dat * Pointer to IDATA buffer holding data to write to the FIFO ******************************************************************************/ static void USB_WriteFIFO_Idata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_IDATA)) { while (numBytes--) { USB_SetFIFOByte(*dat); dat++; } } /***************************************************************************//** * @brief Reads data from the USB FIFO to a buffer in XRAM * @param numBytes * Number of bytes to read from the FIFO * @param dat * Pointer to XDATA buffer to hold data read from the FIFO * @param fifoNum * USB FIFO to read ******************************************************************************/ static void USB_ReadFIFO_Xdata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_XDATA), uint8_t fifoNum) { while (--numBytes) { USB_GetFIFOByte(dat); dat++; } USB_GetLastFIFOByte(dat, fifoNum); } /***************************************************************************//** * @brief Writes data held in XRAM to the USB FIFO * @details The FIFO to write must be set before calling the function with * @ref USB_EnableWriteFIFO(). * @param numBytes * Number of bytes to write to the FIFO * @param dat * Pointer to XDATA buffer holding data to write to the FIFO ******************************************************************************/ static void USB_WriteFIFO_Xdata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_XDATA)) { while (numBytes--) { USB_SetFIFOByte(*dat); dat++; } } #if SI_GPTR_MTYPE_PDATA != SI_GPTR_MTYPE_XDATA /***************************************************************************//** * @brief Reads data from the USB FIFO to a buffer in paged XRAM * @param numBytes * Number of bytes to read from the FIFO * @param dat * Pointer to PDATA buffer to hold data read from the FIFO * @param fifoNum * USB FIFO to read ******************************************************************************/ static void USB_ReadFIFO_Pdata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_PDATA), uint8_t fifoNum) { while (--numBytes) { USB_GetFIFOByte(dat); dat++; } USB_GetLastFIFOByte(dat, fifoNum); } /***************************************************************************//** * @brief Writes data held in paged XRAM to the USB FIFO * @details The FIFO to write must be set before calling the function with * @ref USB_EnableWriteFIFO(). * @param numBytes * Number of bytes to write to the FIFO * @param dat * Pointer to PDATA buffer holding data to write to the FIFO ******************************************************************************/ static void USB_WriteFIFO_Pdata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_PDATA)) { while (numBytes--) { USB_SetFIFOByte(*dat); dat++; } } #endif #if SI_GPTR_MTYPE_DATA != SI_GPTR_MTYPE_IDATA /***************************************************************************//** * @brief Reads data from the USB FIFO to a buffer in DRAM * @param numBytes * Number of bytes to read from the FIFO * @param dat * Pointer to DATA buffer to hold data read from the FIFO * @param fifoNum * USB FIFO to read ******************************************************************************/ static void USB_ReadFIFO_Data(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_DATA), uint8_t fifoNum) { while (--numBytes) { USB_GetFIFOByte(*dat); dat++; } USB_GetLastFIFOByte(*dat, fifoNum); } /***************************************************************************//** * @brief Writes data held in DRAM to the USB FIFO * @details The FIFO to write must be set before calling the function with * @ref USB_EnableWriteFIFO(). * @param numBytes * Number of bytes to write to the FIFO * @param dat * Pointer to DATA buffer to hold data read from the FIFO ******************************************************************************/ static void USB_WriteFIFO_Data(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_DATA)) { while (numBytes--) { USB_SetFIFOByte(*dat); dat++; } } #endif /***************************************************************************//** * @brief Writes data held in code space to the USB FIFO * @details The FIFO to write must be set before calling the function with * @ref USB_EnableWriteFIFO(). * @param numBytes * Number of bytes to write to the FIFO * @param dat * Pointer to CODE buffer holding data to write to the FIFO ******************************************************************************/ static void USB_WriteFIFO_Code(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_CODE)) { while (numBytes--) { USB_SetFIFOByte(*dat); dat++; } } #else /***************************************************************************//** * @brief Reads data from the USB FIFO to a buffer in generic memory space * @param numBytes * Number of bytes to read from the FIFO * @param dat * Pointer to generic buffer to hold data read from the FIFO * @param fifoNum * USB FIFO to read ******************************************************************************/ static void USB_ReadFIFO_Generic(uint8_t numBytes, uint8_t *dat, uint8_t fifoNum) { while (--numBytes) { USB_GetFIFOByte(*dat); dat++; } USB_GetLastFIFOByte(*dat, fifoNum); } /***************************************************************************//** * @brief Writes data held in generic memory space to the USB FIFO * @details The FIFO to write must be set before calling the function with * @ref USB_EnableWriteFIFO(). * @param numBytes * Number of bytes to write to the FIFO * @param dat * Pointer to generic buffer holding data to write to the FIFO ******************************************************************************/ static void USB_WriteFIFO_Generic(uint8_t numBytes, uint8_t *dat) { while (numBytes--) { USB_SetFIFOByte(*dat); dat++; } } #endif // #ifdef SI_GPTR