Hi,
we have a serious communication problem using the usb_bulk_driver library: Receiving information from the host works very well but the transmit function ceases to work from time to time. This may happen after a system uptime of five minutes, three hours or even 40 hours.
Our firmware is based on the bulk device demo software package with a little modification. Our transmit function is called "static uint32_t SendStringToHost(uint8_t *pui8Info, uint_fast32_t ui32NumBytes)". This function starts a new transmission only if the old transmission is completely finished. For this purpose, we set a global flag "USB_TXR" in the TX interrupt function "uint32_t TxHandler(void *pvCBData, uint32_t ui32Event, uint32_t ui32MsgValue, void *pvMsgData)". Even a 50 µs delay inside the TxHandler does not solve the problem.
NB: "g_ui32USBTXTimer" is being incremented every 1 ms inside the SysTick procedure.
Please find the source code below:
//*****************************************************************************
//
// Handles bulk driver notifications related to the transmit channel (data to
// the USB host).
//
// \param pvCBData is the client-supplied callback pointer for this channel.
// \param ulEvent identifies the event we are being notified about.
// \param ulMsgValue is an event-specific value.
// \param pvMsgData is an event-specific pointer.
//
// This function is called by the bulk driver to notify us of any events
// related to operation of the transmit data channel (the IN channel carrying
// data to the USB host).
//
// \return The return value is event-specific.
//
//*****************************************************************************
uint32_t
TxHandler(void *pvCBData, uint32_t ui32Event, uint32_t ui32MsgValue,
void *pvMsgData)
{
//
// We are not required to do anything in response to any transmit event.
// All we do is update our transmit counter.
//
if (ui32Event == USB_EVENT_TX_COMPLETE)
{
g_ui32TxCount += ui32MsgValue;
/*
//
// wait a little bit...
// NB: character time is about 8 µs
// ... does not solve the problem
//
delay_us(50);
*/
//
// set USB TX ready flag
//
USB_TXR = true;
}
return(0);
}
static uint32_t
SendStringToHost(uint8_t *pui8Info, uint_fast32_t ui32NumBytes)
{
uint_fast32_t ui32Loop, ui32Count;
uint_fast32_t ui32ReadIndex;
uint_fast32_t ui32WriteIndex;
tUSBRingBufObject sTxRing;
bool bWriteTimeout, bUSBRingBufEmpty;
//
// initialize TX timeout counter
//
g_ui32USBTXTimer = 0;
//
// ui32NumBytes characters to process;
// wait until transmit buffer is completely empty
//
do
{
//
// Get the current buffer information to allow us to write directly to
// the transmit buffer (we already have enough information from the
// parameters to access the receive buffer directly).
//
// Copy the current ring buffer settings to the clients storage.
//
/*
USBBufferInfoGet(&g_sTxBuffer, &sTxRing);
bUSBRingBufEmpty = USBRingBufEmpty(&sTxRing);
*/
//
// replacement for "USBBufferInfoGet(&g_sTxBuffer, &sTxRing)" without any function calls
//
(&sTxRing)->pui8Buf = (&g_sTxBuffer)->sPrivateData.sRingBuf.pui8Buf;
(&sTxRing)->ui32ReadIndex = (&g_sTxBuffer)->sPrivateData.sRingBuf.ui32ReadIndex;
(&sTxRing)->ui32Size = (&g_sTxBuffer)->sPrivateData.sRingBuf.ui32ReadIndex;
(&sTxRing)->ui32WriteIndex = (&g_sTxBuffer)->sPrivateData.sRingBuf.ui32WriteIndex;
//
// replacement for "USBRingBufEmpty(&sTxRing)" without any function calls
//
ui32WriteIndex = (&sTxRing)->ui32WriteIndex;
ui32ReadIndex = (&sTxRing)->ui32ReadIndex;
bUSBRingBufEmpty = (ui32WriteIndex == ui32ReadIndex) ? true : false;
//
// calculate timeout condition
//
bWriteTimeout = (g_ui32USBTXTimer > 20);
} while (!(bUSBRingBufEmpty && USB_TXR) && !bWriteTimeout);
//
// check for USB TX timeout
//
if (bWriteTimeout)
{
//
// flush TX buffer and discard input string because transmission is not possible at the moment
//
USBBufferInfoGet(&g_sTxBuffer, &sTxRing);
USBRingBufFlush(&sTxRing);
USB_TXR = true;
ui32Count = 0;
}
else
{
//
// prepare transmission: clear USB TX ready flag
//
USB_TXR = false;
//
// How many characters can we process this time round?
// Calculation is no more necessary because we write when buffer is free.
//
//ui32Loop = (ui32Space < ui32NumBytes) ? ui32Space : ui32NumBytes;
//ui32Count = ui32Loop;
ui32Count = ui32Loop = ui32NumBytes;
//
// Set up to process the characters by directly accessing the USB buffers.
//
ui32ReadIndex = 0;
ui32WriteIndex = sTxRing.ui32WriteIndex;
while (ui32Loop)
{
//
// copy string to the transmit buffer
//
g_pui8USBTxBuffer[ui32WriteIndex] = pui8Info[ui32ReadIndex];
//
// Move to the next character taking care to adjust the pointer for
// the buffer wrap if necessary.
//
ui32WriteIndex++;
ui32WriteIndex = (ui32WriteIndex == BULK_BUFFER_SIZE) ? 0 : ui32WriteIndex;
ui32ReadIndex++;
ui32ReadIndex = ((ui32ReadIndex == BULK_BUFFER_SIZE) ? 0 : ui32ReadIndex);
ui32Loop--;
}
//
// We've processed the data in place so now send the processed data
// to the host.
//
USBBufferDataWritten(&g_sTxBuffer, ui32Count);
}
//
// We processed as much data as we can directly from the receive buffer so
// we need to return the number of bytes to allow the lower layer to
// update its read pointer appropriately.
//
return (ui32Count);
}
Thanks,
Juergen