USB Endpoint call

Hi,

I modified USB memory example from Keil and I can enumerate. But I was trying to trace back how are the USB_Endpoint() functions called.
For example usbuser.c file has EndPoint definitions that look like this:

/*
 *  USB Endpoint 1 Event Callback
 *   Called automatically on USB Endpoint 1 Event
 *    Parameter:       event
 */

void USB_EndPoint1 (u32 event) {
        // BulkIn
}


/*
 *  USB Endpoint 2 Event Callback
 *   Called automatically on USB Endpoint 2 Event
 *    Parameter:       event
 */

void USB_EndPoint2 (u32 event) {
  USB_EP_Bulkout();     // Handle data that arrived on this Endpoint
}

I use Endpoint 1(IN) and Endpoint 2(OUT). But when I tried to search for these functions to see where they are called I came up empty.
Is this done in a interrupt routine someplace? IS this function name assembled someplace?
I assumed that as soon as the host sends data to the device it goes to the OUT endpoint and my device executes my function USB_EP_Bulkout().
But I couldn't find out where this UEB_EndPoint2() is called.

Any help is appreciated.
Thanks

Parents
  • wario,
    you will find a reference to these functions in a sructure that contains pointers to functions (don't remember in which c file...). these pointers are used upon the occurance of a usb interrupt.

  • "I modified USB memory example from Keil"

    Which one?
    We can see these MSD (Mass Storage Device) examples on Keil web site.

    "ARM Download Files"
    http://www.keil.com/download/list/arm.htm

    1) LPC2148 USB Mass Storage Device Example
    2) LPC2368 / LPC2378 USB Mass Storage Device Example
    3) STM32 USB Mass Storage Device Example
    4) STR750 / STR751 USB Mass Storage Device Example

    These examples derive from single code base, but the details are, of course, depending on the chip and the board.


    "But when I tried to search for these functions to see where they are called I came up empty."

    In addition to Tamir,

    On the LPC2148 (MCB2140) example,
    USB_EndPointN() routines (N=0..15) are called through this function-pointer table.

    usbcfg.h
    #define USB_EP_EVENT        0x0005
    
    usbuser.c
    #define P_EP(n) ((USB_EP_EVENT & (1 << (n))) ? USB_EndPoint##n : NULL)
    
    /* USB Endpoint Events Callback Pointers */
    void (* const USB_P_EP[16]) (DWORD event) = {
      P_EP(0),
      P_EP(1),
      P_EP(2),
      P_EP(3),
      P_EP(4),
      P_EP(5),
      P_EP(6),
      P_EP(7),
      P_EP(8),
      P_EP(9),
      P_EP(10),
      P_EP(11),
      P_EP(12),
      P_EP(13),
      P_EP(14),
      P_EP(15),
    };
    

    Maybe you missed what the P_EP(n) macro does.
    The preprocessor operator '##' concatenates 'USB_EndPoint' string and the number N, it makes up a single token, like USB_EndPoint1 or USB_EndPoint2.
    Then, each P_EP(N) on the table is replaced with USB_EndPointN or NULL, depending on the bit of USB_EP_EVENT.

    The function-pointer table, USB_P_EP is referred in the USB ISR. Then, USB_EndPointN routines are called from the USB ISR, if it is enabled by the bit on USB_EP_EVENT, and when the endpoint puts an interrupt.

    usbhw.c
    /*
     *  USB Interrupt Service Routine
     */
    
    void USB_ISR (void) __irq {
      ...
      ...
      /* Endpoint's Slow Interrupt */
      if (disr & EP_SLOW_INT) {
    
        while (EP_INT_STAT) {                   /* Endpoint Interrupt Status */
    
          for (n = 0; n < USB_EP_NUM; n++) {    /* Check All Endpoints */
            if (EP_INT_STAT & (1 << n)) {
              m = n >> 1;
    
              EP_INT_CLR = 1 << n;
              while ((DEV_INT_STAT & CDFULL_INT) == 0);
              val = CMD_DATA;
    
              if ((n & 1) == 0) {               /* OUT Endpoint */
                if (n == 0) {                   /* Control OUT Endpoint */
                  if (val & EP_SEL_STP) {       /* Setup Packet */
                    if (USB_P_EP[0]) {
                      USB_P_EP[0](USB_EVT_SETUP);
                      continue;
                    }
                  }
                }
                if (USB_P_EP[m]) {
                  USB_P_EP[m](USB_EVT_OUT);
                }
              } else {                          /* IN Endpoint */
                if (USB_P_EP[m]) {
                  USB_P_EP[m](USB_EVT_IN);
                }
              }
            }
          }
        }
      }
      ...
    

    Tsuneo

Reply
  • "I modified USB memory example from Keil"

    Which one?
    We can see these MSD (Mass Storage Device) examples on Keil web site.

    "ARM Download Files"
    http://www.keil.com/download/list/arm.htm

    1) LPC2148 USB Mass Storage Device Example
    2) LPC2368 / LPC2378 USB Mass Storage Device Example
    3) STM32 USB Mass Storage Device Example
    4) STR750 / STR751 USB Mass Storage Device Example

    These examples derive from single code base, but the details are, of course, depending on the chip and the board.


    "But when I tried to search for these functions to see where they are called I came up empty."

    In addition to Tamir,

    On the LPC2148 (MCB2140) example,
    USB_EndPointN() routines (N=0..15) are called through this function-pointer table.

    usbcfg.h
    #define USB_EP_EVENT        0x0005
    
    usbuser.c
    #define P_EP(n) ((USB_EP_EVENT & (1 << (n))) ? USB_EndPoint##n : NULL)
    
    /* USB Endpoint Events Callback Pointers */
    void (* const USB_P_EP[16]) (DWORD event) = {
      P_EP(0),
      P_EP(1),
      P_EP(2),
      P_EP(3),
      P_EP(4),
      P_EP(5),
      P_EP(6),
      P_EP(7),
      P_EP(8),
      P_EP(9),
      P_EP(10),
      P_EP(11),
      P_EP(12),
      P_EP(13),
      P_EP(14),
      P_EP(15),
    };
    

    Maybe you missed what the P_EP(n) macro does.
    The preprocessor operator '##' concatenates 'USB_EndPoint' string and the number N, it makes up a single token, like USB_EndPoint1 or USB_EndPoint2.
    Then, each P_EP(N) on the table is replaced with USB_EndPointN or NULL, depending on the bit of USB_EP_EVENT.

    The function-pointer table, USB_P_EP is referred in the USB ISR. Then, USB_EndPointN routines are called from the USB ISR, if it is enabled by the bit on USB_EP_EVENT, and when the endpoint puts an interrupt.

    usbhw.c
    /*
     *  USB Interrupt Service Routine
     */
    
    void USB_ISR (void) __irq {
      ...
      ...
      /* Endpoint's Slow Interrupt */
      if (disr & EP_SLOW_INT) {
    
        while (EP_INT_STAT) {                   /* Endpoint Interrupt Status */
    
          for (n = 0; n < USB_EP_NUM; n++) {    /* Check All Endpoints */
            if (EP_INT_STAT & (1 << n)) {
              m = n >> 1;
    
              EP_INT_CLR = 1 << n;
              while ((DEV_INT_STAT & CDFULL_INT) == 0);
              val = CMD_DATA;
    
              if ((n & 1) == 0) {               /* OUT Endpoint */
                if (n == 0) {                   /* Control OUT Endpoint */
                  if (val & EP_SEL_STP) {       /* Setup Packet */
                    if (USB_P_EP[0]) {
                      USB_P_EP[0](USB_EVT_SETUP);
                      continue;
                    }
                  }
                }
                if (USB_P_EP[m]) {
                  USB_P_EP[m](USB_EVT_OUT);
                }
              } else {                          /* IN Endpoint */
                if (USB_P_EP[m]) {
                  USB_P_EP[m](USB_EVT_IN);
                }
              }
            }
          }
        }
      }
      ...
    

    Tsuneo

Children
More questions in this forum