• AVR Freaks

Using USER_USB_CALLBACK_EVENT_HANDLER

Author
PicMeUp
New Member
  • Total Posts : 3
  • Reward points : 0
  • Joined: 2009/11/16 05:43:57
  • Location: 0
  • Status: offline
2009/12/02 04:01:06 (permalink)
0

Using USER_USB_CALLBACK_EVENT_HANDLER

Hi,

I am using bulk transfers on code derived from Jan Axelson's.

I am sending back 4K packets as a response to a request every 100ms.

Once everything is set up my code simply walks through a buffer sending odd and even packets from a modified version of BulkTransferLoopback(), so the code is quite short.

Everything works fine but in order for the code to be responsive I must tight loop in main() calling ProcessIO() which in turn calls BulkTransferLoopback().

What I would like to do is make the system run more from the interrupt path. I initially modified the code in USER_USB_CALLBACK_EVENT_HANDLER() to include the following



switch (event)
{
....
case EVENT_TRANSFER:
if(!((USBDeviceState < CONFIGURED_STATE)||(USBSuspendControl==1)))
BulkTransferLoopback();
break;
....



However the code stopped after one bulk transacton and I found that I needed to call BulkTransferLoopback() outside of the interrupt path get it started again. So I then modifiled BulkTransferLoopback() as follows:



volatile char inBulkTransferLoopback = FALSE;

void BulkTransferLoopback(void)
{
if (!inBulkTransferLoopback)
{
inBulkTransferLoopback = TRUE;
....
....
inBulkTransferLoopback = FALSE;
}

}



And called BulkTransferLoopback() from both ProcessIO() and USER_USB_CALLBACK_EVENT_HANDLER(). Although this worked the system was now unresponsive again depending on execution time of the loop in main().

I have now called BulkTransferLoopback() directly from USER_USB_CALLBACK_EVENT_HANDLER() irrespective of the event that it is dealing with and removed the call from ProcessIO(). The result is that the system is responsive even with a large (6 second) dummy delay in main().


So the question is, I I asking for trouble making this change? is there a better way?

Andy







"Trying is the first step towards failure" H. Simpson
#1

2 Replies Related Threads

    chinzei
    Super Member
    • Total Posts : 2250
    • Reward points : 0
    • Joined: 2003/11/07 12:39:02
    • Location: Tokyo, Japan
    • Status: offline
    RE: Using USER_USB_CALLBACK_EVENT_HANDLER 2009/12/02 08:06:48 (permalink)
    0
    It's better to split IN (write) and OUT (read) transfers on BulkTransferLoopback() into separate tasks.
    BulkTransferLoopback() is coded so that IN and OUT transfers are coupled packet by packet, to handle them in small buffers.
    It isn't good for your purpose - transfer large buffers at a time.


    To transfer a block of data from device to host using interrupt,

    in-1) A main-loop task puts the first portion of the buffer to the USB engine - Start_Block_Write().
    in-2) When this portion is sent to host as a packet, an interrupt occurs.
    in-3) This interrupt is caught by the USER_USB_CALLBACK_EVENT_HANDLER()
    in-4) USER_USB_CALLBACK_EVENT_HANDLER() passes next portion of the buffer to the USB engine.
    in-5) loop to in-2), until the last packet is sent.

    To transfer a block of data from host to device

    out-1) A main-loop task passes an empty buffer to the USB engine - Start_Block_Read().
    out-2) When a packet is sent from host and stored to the portion of the buffer, an interrupt occurs.
    out-3) This interrupt is caught by the USER_USB_CALLBACK_EVENT_HANDLER()
    out-4) USER_USB_CALLBACK_EVENT_HANDLER() passes next portion of the buffer to the USB engine - USBGenRead().
    out-5) loop to out-2), until the last packet is sent.

    Usually, a flag is used to show a block transfer is going, so that any other main-loop task doesn't enter another block transfer to the endpoint. This flag is raised in the starter task, dropped in the ISR when it sees the end of transfer.
    Please note, IN and OUT endpoints work independently, even when they shares the same endpoint address.

    I'll show you a snippet without ping-pong
    When ping-pong is enabled, the code becomes more complicated.

    Tsuneo

    Enable USB_INTERRUPT macro in usb_config.h

    usb_config.h

    //#define USB_POLLING
    #define USB_INTERRUPT

     
     
    //
    // block transfer with endpoint interrupt, no-ping pong
    //

    // constant for USTAT (U1STAT)
    #if defined(__18CXX)
    #define USTAT_EP_SHIFT 3
    #elif defined(__C30__) || defined(__C32__)
    #define USTAT_EP_SHIFT 4
    #else
    #error "unimplemented"
    #endif

    // global variables
    BYTE * bulk_in_buffer;
    WORD bulk_in_to_be_written;
    USB_VOLATILE WORD bulk_in_count;
    USB_VOLATILE BOOL bulk_in_occupied; // semaphor for exclusive access

    BYTE * bulk_out_buffer;
    WORD bulk_out_to_be_read;
    USB_VOLATILE WORD bulk_out_count;
    USB_VOLATILE BOOL bulk_out_occupied; // semaphor for exclusive access


    BOOL Start_Block_Write( BYTE * buffer, WORD block_size )
    {
    if ( bulk_in_occupied ) return FALSE;
    // setup parameters to pass them to ISR
    bulk_in_buffer = buffer;
    bulk_in_to_be_written = block_size;
    bulk_in_count = WINUSB_BULK_IN_EP_SIZE;
    bulk_in_occupied = TRUE;
    // pass the first portion of the buffer to USB engine
    USBWinUsbBulkInHandle = USBGenWrite( WINUSB_BULK_EP, bulk_in_buffer, WINUSB_BULK_IN_EP_SIZE );
    return TRUE;
    }


    BOOL Start_Block_Read( BYTE * buffer, WORD block_size )
    {
    if ( bulk_out_occupied ) return FALSE;
    // setup parameters to pass them to ISR
    bulk_out_buffer = buffer;
    bulk_out_to_be_read = block_size;
    bulk_out_count = WINUSB_BULK_OUT_EP_SIZE;
    bulk_out_occupied = TRUE;
    // pass the first portion of the buffer to USB engine
    USBWinUsbBulkOutHandle = USBGenRead( WINUSB_BULK_EP, bulk_out_buffer, WINUSB_BULK_OUT_EP_SIZE );
    return TRUE;
    }


    void USBCB_Endpoint_ISR( BYTE USTAT_local )
    {
    WORD bulk_bytes_to_send;
    // check endpoint address
    if ( (USTAT_local & ENDPOINT_MASK) != (WINUSB_BULK_EP << USTAT_EP_SHIFT) ) return;

    // dispatch IN and OUT endpoint
    if ( USTAT_local & USTAT_EP0_IN )
    { // IN endpoint
    // end of transfer ?
    if ( bulk_in_count >= bulk_in_to_be_written )
    {
    bulk_in_occupied = FALSE; // release this endpoint from block transfer
    return;
    }
    // calculate next packet size
    bulk_bytes_to_send = bulk_in_to_be_written - bulk_in_count;
    if ( bulk_bytes_to_send > WINUSB_BULK_IN_EP_SIZE )
    bulk_bytes_to_send = WINUSB_BULK_IN_EP_SIZE;
    // pass next portion of the buffer to USB engine
    USBWinUsbBulkInHandle = USBGenWrite( WINUSB_BULK_EP,
    &bulk_in_buffer[ bulk_in_count ],
    (BYTE)bulk_bytes_to_send );
    // update the counter
    bulk_in_count += bulk_bytes_to_send;

    } else { // OUT endpoint
    // count up the length of the block
    bulk_out_count += USBHandleGetLength( USBWinUsbBulkOutHandle );
    // end of transfer ?
    if ( bulk_out_count >= bulk_out_to_be_read )
    {
    bulk_out_occupied = FALSE; // release this endpoint from block transfer
    return;
    }
    // pass next portion of the buffer to USB engine
    USBWinUsbBulkOutHandle = USBGenRead( WINUSB_BULK_EP,
    &bulk_out_buffer[ bulk_out_count ],
    WINUSB_BULK_OUT_EP_SIZE );
    }
    }


    BOOL USER_USB_CALLBACK_EVENT_HANDLER( USB_EVENT event, void *pdata, WORD size )
    {
    switch ( event )
    {
    ....
    case EVENT_TRANSFER: // interrupt comes on an endpoint other than EP0
    USBCB_Endpoint_ISR( *(BYTE *)pdata ); // pass USTAT_copy pointed by pdata
    break;
    ....


    void USBCBInitEP(void)
    {
    USBEnableEndpoint(WINUSB_BULK_EP,USB_IN_ENABLED|USB_OUT_ENABLED | USB_HANDSHAKE_ENABLED|USB_DISALLOW_SETUP);

    // don't pass the out buffer yet at this timing (in Set_Configuration)
    // USBWinUsbBulkOutHandle = USBGenRead(WINUSB_BULK_EP,(BYTE*)&bulk_out_buffer,WINUSB_BULK_OUT_EP_SIZE);

    // initialize global variables
    bulk_in_to_be_written = 0;
    bulk_in_count = 0;
    bulk_in_occupied = FALSE;

    bulk_out_to_be_read = 0;
    bulk_out_count = 0;
    bulk_out_occupied = FALSE;
    }


    post edited by chinzei - 2014/03/08 10:25:19
    #2
    PicMeUp
    New Member
    • Total Posts : 3
    • Reward points : 0
    • Joined: 2009/11/16 05:43:57
    • Location: 0
    • Status: offline
    RE: Using USER_USB_CALLBACK_EVENT_HANDLER 2010/01/13 04:49:42 (permalink)
    0
    Thanks chinzei,

    That is a good explination.

    I just got round to trying this with ping-pong and it works very well.

    Best regards

    Andy

    "Trying is the first step towards failure" H. Simpson
    #3
    Jump to:
    © 2019 APG vNext Commercial Version 4.5