Flow control with double buffered endpoints.
Company  
ST Home | Microcontrollers

Index  »  USB  »  Flow control with double buffered endpoints.
     
   Flow control with double buffered endpoints.
 Moderated by :   »  aNt  -  AnisAS  -  AnisAS

Author
beginning argument    ( Replies received: 5 )
daniel2   Posted 12-10-2008 at 07:43   



Registered on :
12-13-2009

Messages : 37

 OFF-Line

What registers do I need to check (when setup as a double buffered endpoint) to make sure that I don't call things before the previous transfer is done? I've tried checking for NAKs on the endpoint, but that does not seem to work with the double buffered endpoints (it works for when they are configured as single ended). The only thing that I've managed to make it work with is specifically adding a delay to insure that the transfer is complete, but that is not optimal.
I've tried trapping things at the end of the interrupt for the endpoint, but it returns much sooner than the transfer, and I can corrupt my buffer.
Waiting for EP_CTR_TX does not seem to be too helpful either.

I should add this is setup as a vcom device. Any suggestions would be appreciated. Thanks.






 Profile   Quote  
rgreenthal   Posted 13-10-2008 at 20:09   



Registered on :
02-07-2009

Messages : 43

 OFF-Line

Here is how I did it for EP2 for Receive
I can't get EP1 to work for Transmit, it kills the Host/PC side
I initialized it by doing

// ***********************************************
// Initialize Endpoint 2 OUT
// Immediate Command Receive End Point 2
// Setup for USB Rx Double Buffered in PMA memory
// ***********************************************
_SetEPAddress(ENDP2, 2);
// setup USB_EP2R
_SetEPType(ENDP2, EP_BULK);
// Set up USB_Counter2, do Rx for Double Buffered
// set Double Buffer register for larger packets
SetEPDoubleBuff(ENDP2); // Double buffer endpoint
SetEPDblBuffAddr(ENDP2, ENDP2_RXADDR1, ENDP2_RXADDR2);
SetEPDblBuffCount(ENDP2, EP_DBUF_OUT, USBRXEP2BUFFER_SIZE); // Set Count & BLsize
_ClearDTOG_RX(ENDP2);
_ClearDTOG_TX(ENDP2);
_ToggleDTOG_TX(ENDP2);
_SetEPRxStatus(ENDP2, EP_RX_VALID);
_SetEPTxStatus(ENDP2, EP_TX_DIS);






void EP2_isr(void)
{
unsigned char *pbVal;
unsigned short wCopyCount;
unsigned short wEndPointCount;
u32 Endpoint_DTOG_Status;

// set bytes moved to bRxImdBuffer to Zero
wCopyCount = 0;

// ***********************************
// Check to do Double Buffering
// Ping-Pong between the two Buffers
// ***********************************
Endpoint_DTOG_Status = GetENDPOINT(ENDP2) & EP_DTOG_RX;
if (Endpoint_DTOG_Status)
{
// Read from buffer 0
// Get USB the size of the Data being received from Host/PC in this Buffer
wEndPointCount = GetEPDblBuf0Count(ENDP2);
// Gets the Address of Endpoint Count register value They are 0x80 (128) bytes
pbVal = (unsigned char *)(PMAAddr + ENDP2_RXADDR1);
}
else
{
// Read from buffer 1
// Get USB the size of the Data being received from Host/PC in this Buffer
wEndPointCount = GetEPDblBuf1Count(ENDP2);
// Gets the Address of Endpoint Count register value They are 0x80 (128) bytes
pbVal = (unsigned char *)(PMAAddr + ENDP2_RXADDR2);
}
// Get ALL data bytes from USB buffer (pbVal) and
// store in bRxImdBuffer
while (wCopyCount < wEndPointCount)
{
// Read USB Data into bRxImdBuffer, don't worry if it's for US yet.
// Can't us PMAToUserBufferCopy() because of sRxSeqHead & its circular
bRxImdBuffer[sRxImdHead++] = *pbVal++;
wCopyCount++;

// Test for end of circular buffer
if (sRxImdHead >= IMD_BUFFER_SIZE)
sRxImdHead = 0;
}
FreeUserBuffer(ENDP2, EP_DBUF_OUT); // Toggle DTOG Status to next Buffer

if (Endpoint_DTOG_Status)
{
// Reset buffer 0
SetEPDblBuf0Count(ENDP2, EP_DBUF_OUT, USBRXEP2BUFFER_SIZE);
_SetEPRxStatus(ENDP2, EP_RX_VALID);
}
else
{
// Reset buffer 1
SetEPDblBuf1Count(ENDP2, EP_DBUF_OUT, USBRXEP2BUFFER_SIZE);
_SetEPTxStatus(ENDP2, EP_TX_VALID);
}
} // End of Function "EP2_isr()"










 Profile   Quote  
rgreenthal   Posted 14-10-2008 at 21:58   



Registered on :
02-07-2009

Messages : 43

 OFF-Line

Note: from Freescale website

* The Mass-Storage class uses Bulk transfers to transport data to and from
* the Mass-Storage device. Bulk transfers are handshaked transfers with 64
* byte max payload sizes. There can be more then 1 transfer per frame,
* with a maximum of 19 transfer per frame for a total max transfer speed
* of 1216 bytes / millisecond or 1216000 bytes / second.

But we would have to Double buffer 608 bytes to get that thru put
I think we can do 1024 per millisec to give 1024000 bytes per second
This is just shy of the spec
Now if I could get Double Buffering working on Transmit
we could do 608 bytes per Double buffer and get the proper transfer rates



 Profile   Quote  
daniel2   Posted 15-10-2008 at 17:00   



Registered on :
12-13-2009

Messages : 37

 OFF-Line

I don't think you'll be able to get 608 bytes through. I have my transmit (IN endpoints) working double buffered. I am not using the interrupt endpoint routines because by the time they hit, the frame has ended, so you could set the next frame up, but not another packet for the current frame.

From my calculations, given that the PMA memory is 512 bytes in size, it would be possible to get 512 bytes every ms, so a maximum of 512kb/sec theoretically.

The issue I had was when composing strings and sending it out, i would call my transmit routine faster than 1ms several times, and it would corrupt the data output. I figured out how to wait for it.

In my case, ENDP1 is my TX endpoint

here is my setup:

SetEPType(ENDP1, EP_BULK);
SetEPDoubleBuff(ENDP1); //double buffer endpoint
SetEPDblBuffAddr(ENDP1,ENDP1_BUFF0ADDR,ENDP1_BUFF1ADDR);
ClearDTOG_RX(ENDP1);
ClearDTOG_TX(ENDP1);
ToggleDTOG_TX(ENDP1);
SetEPTxStatus(ENDP1, EP_TX_VALID);
SetEPRxStatus(ENDP1, EP_RX_DIS);
SetEPTxStatus(ENDP1, EP_TX_NAK);

Here is my code that worked as long as you did not call the function more than once every ms.
void usb_send_data(char *buffer,short length)
{
U32 Endpoint_DTOG_Status = _GetENDPOINT(ENDP1) & EP_DTOG_TX;
//Double buffered send.
if(length) {

SetEPDblBuffCount(ENDP1, EP_DBUF_IN, length);
if (!Endpoint_DTOG_Status)
{
PMA_Write(buffer,ENDP1_BUFF0ADDR, length);
}
else
{
PMA_Write(buffer,ENDP1_BUFF1ADDR, length);
}
FreeUserBuffer(ENDP1, EP_DBUF_IN);
SetEPTxCount(ENDP1,length);
SetEPTxValid(ENDP1);
}

The VCOM example has a variable called count_in, that is zeroed out on the ISR for that endpoint.
By making it volatile in its definition, initializing it and checking once its done, I was able to get the transmission working properly..IE

while(count_in);

Endpoint_DTOG_Status = _GetENDPOINT(ENDP1) & EP_DTOG_TX;
//Double buffered send.
if(length) {
count_in=length;
SetEPDblBuffCount(ENDP1, EP_DBUF_IN, length);
if (!Endpoint_DTOG_Status)
{
PMA_Write(buffer,ENDP1_BUFF0ADDR, length);
}
else
{
PMA_Write(buffer,ENDP1_BUFF1ADDR, length);
}
FreeUserBuffer(ENDP1, EP_DBUF_IN);
SetEPTxCount(ENDP1,length);
SetEPTxValid(ENDP1);

}

It works like a charm. and

void EP1_IN_Callback(void)
{
count_in=0;
}

You should be able to use this code to transmit properly.

Daniel



 Profile   Quote  
milton.godinho   Posted 30-10-2008 at 16:54   



Registered on :
10-08-2009

Messages : 28

 OFF-Line

Hey I am using a similar function to read the data from the PC in my device:


int Xerox_Read()
{
u32 count_in;
if (GetEPRxStatus(ENDP1)==EP_RX_VALID)
{
count_in = GetEPRxCount(ENDP1);
if (count_in)
PMAToUserBufferCopy(Xerox_Buffer_IN, ENDP1_RXADDR, count_in); //PROBLEM IS HERE!!!!!!
else
return 0;
}
else
return 0;

SetEPRxValid(ENDP1);
return 1;
}


But it doesn't work, any idea why?

Thanks for your help!



 Profile   Quote  
milton.godinho   Posted 31-10-2008 at 12:37   



Registered on :
10-08-2009

Messages : 28

 OFF-Line

This is what I did, I have defined two endpoints. EP1 (IN) and EP2 (OUT).

usb_conf.h
...
#define ENDP1_TXADDR (0x300)
#define ENDP2_RXADDR (0x400)
...

and on usb_prop.c on rest I defined:

void Reset()
{
/* Set MOUSE_DEVICE as not configured */
Device_Info.Current_Configuration = 0;
/*correction AS default interface*/
Device_Info.Current_Interface = 0;/*the default Interface*/
SetBTABLE(BTABLE_ADDRESS);
/* Initialize Endpoint 0 */
SetEPType(ENDP0, EP_CONTROL);
SetEPTxStatus(ENDP0, EP_TX_STALL/*EP_TX_NAK*/);
SetEPRxAddr(ENDP0, ENDP0_RXADDR);
SetEPRxCount(ENDP0,0x40/*STD_MAXPACKETSIZE*/);
SetEPTxAddr(ENDP0, ENDP0_TXADDR);
SetEPTxCount(ENDP0,0x40 /* STD_MAXPACKETSIZE*/);
SetEPAddress(ENDP0,0);
Clear_Status_Out(ENDP0);
SetEPRxValid(ENDP0);


// device -> pc
/* Initialize Endpoint 1 */
SetEPType(ENDP1, EP_INTERRUPT);
SetEPTxAddr(ENDP1, ENDP1_TXADDR);
SetEPTxCount(ENDP1,4);
SetEPRxStatus(ENDP1, EP_RX_DIS);
SetEPTxStatus(ENDP1, EP_TX_NAK);
SetEPAddress(ENDP1,1);

//PC -> device
/* Initialize Endpoint 2 */
SetEPType(ENDP2, EP_INTERRUPT);
SetEPTxAddr(ENDP2, ENDP2_TXADDR);
SetEPTxCount(ENDP2,4);
SetEPRxStatus(ENDP2, EP_RX_VALID);
SetEPTxStatus(ENDP2, EP_TX_DIS);
SetEPAddress(ENDP2,1);



/* Set this device to response on default address */
SetDeviceAddress(0);

} /* Reset() */

and finally in the main I just use to read:


int Xerox_Read()
{
u32 count_in;
if (GetEPRxStatus(ENDP2)==EP_RX_VALID)
{
count_in = GetEPRxCount(ENDP2);
if (count_in)
PMAToUserBufferCopy(Xerox_Buffer_IN, ENDP2_RXADDR, count_in); //PROBLEM IS HERE!!!!!!
else
return 0;
}
else
return 2;
SetEPRxValid(ENDP2);
return 1;
}

But I don't get anything. I am using report descriptors to transfer the data.

Any idea why I can't read anything?

Thanks a lot!




 Profile   Quote  
On Top

Search in the forums
 
Jump To