This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

usb asynchronous

How do I set the usb audio code up for usb asynchronous transfers.

Do I just have to change bmAttributes

USB_ENDPOINT_TYPE_ISOCHRONOUS,

to

USB_ENDPOINT_SYNC_ASYNCHRONOUS

or is it more complexed than that.

Parents Reply Children
  • Here is a descriptor readout of a typical Async Sink device (Ayre QB9),
    taken from list.voyage.hk/.../013449.html

    Compare it with the example's

    lsusb -v
    
    Bus 001 Device 004: ID 21b4:0130
    Device Descriptor:
      bLength                18
      bDescriptorType         1
      bcdUSB               1.00
      bDeviceClass            0 (Defined at Interface level)
      bDeviceSubClass         0
      bDeviceProtocol         0
      bMaxPacketSize0        64
      idVendor           0x21b4
      idProduct          0x0130
      bcdDevice            1.71
      iManufacturer           1
      iProduct                2
      iSerial                 3
      bNumConfigurations      1
      Configuration Descriptor:
        bLength                 9
        bDescriptorType         2
        wTotalLength          134
        bNumInterfaces          3
        bConfigurationValue     1
        iConfiguration          0
        bmAttributes         0x80
          (Bus Powered)
        MaxPower              500mA
        Interface Descriptor:
          bLength                 9
          bDescriptorType         4
          bInterfaceNumber        0
          bAlternateSetting       0
          bNumEndpoints           0
          bInterfaceClass         1 Audio
          bInterfaceSubClass      1 Control Device
          bInterfaceProtocol      0
          iInterface              7
          AudioControl Interface Descriptor:
            bLength                 9
            bDescriptorType        36
            bDescriptorSubtype      1 (HEADER)
            bcdADC               1.00
            wTotalLength           30
            bInCollection           1
            baInterfaceNr( 0)       1
          AudioControl Interface Descriptor:
            bLength                12
            bDescriptorType        36
            bDescriptorSubtype      2 (INPUT_TERMINAL)
            bTerminalID             1
            wTerminalType      0x0101 USB Streaming
            bAssocTerminal          0
            bNrChannels             2
            wChannelConfig     0x0003
              Left Front (L)
              Right Front (R)
            iChannelNames           0
            iTerminal               0
          AudioControl Interface Descriptor:
            bLength                 9
            bDescriptorType        36
            bDescriptorSubtype      3 (OUTPUT_TERMINAL)
            bTerminalID             6
            wTerminalType      0x0301 Speaker
            bAssocTerminal          0
            bSourceID               1
            iTerminal               0
        Interface Descriptor:
          bLength                 9
          bDescriptorType         4
          bInterfaceNumber        1
          bAlternateSetting       0
          bNumEndpoints           0
          bInterfaceClass         1 Audio
          bInterfaceSubClass      2 Streaming
          bInterfaceProtocol      0
          iInterface              9
        Interface Descriptor:
          bLength                 9
          bDescriptorType         4
          bInterfaceNumber        1
          bAlternateSetting       1
          bNumEndpoints           2
          bInterfaceClass         1 Audio
          bInterfaceSubClass      2 Streaming
          bInterfaceProtocol      0
          iInterface              8
          AudioStreaming Interface Descriptor:
            bLength                 7
            bDescriptorType        36
            bDescriptorSubtype      1 (AS_GENERAL)
            bTerminalLink           1
            bDelay                  1 frames
            wFormatTag              1 PCM
          AudioStreaming Interface Descriptor:
            bLength                20
            bDescriptorType        36
            bDescriptorSubtype      2 (FORMAT_TYPE)
            bFormatType             1 (FORMAT_TYPE_I)
            bNrChannels             2
            bSubframeSize           3
            bBitResolution         24
            bSamFreqType            4 Discrete
            tSamFreq[ 0]        44100
            tSamFreq[ 1]        48000
            tSamFreq[ 2]        88200
            tSamFreq[ 3]        96000
          Endpoint Descriptor:
            bLength                 9
            bDescriptorType         5
            bEndpointAddress     0x01  EP 1 OUT
            bmAttributes            5
              Transfer Type            Isochronous
              Synch Type               Asynchronous
              Usage Type               Data
            wMaxPacketSize     0x0246  1x 582 bytes
            bInterval               1
            bRefresh                0
            bSynchAddress         129
            AudioControl Endpoint Descriptor:
              bLength                 7
              bDescriptorType        37
              bDescriptorSubtype      1 (EP_GENERAL)
              bmAttributes         0x01
                Sampling Frequency
              bLockDelayUnits         2 Decoded PCM samples
              wLockDelay              0 Decoded PCM samples
          Endpoint Descriptor:
            bLength                 9
            bDescriptorType         5
            bEndpointAddress     0x81  EP 1 IN
            bmAttributes            1
              Transfer Type            Isochronous
              Synch Type               None
              Usage Type               Data
            wMaxPacketSize     0x0003  1x 3 bytes
            bInterval               1
            bRefresh                1
            bSynchAddress           0
        Interface Descriptor:
          bLength                 9
          bDescriptorType         4
          bInterfaceNumber        2
          bAlternateSetting       0
          bNumEndpoints           0
          bInterfaceClass       254 Application Specific Interface
          bInterfaceSubClass      1 Device Firmware Update
          bInterfaceProtocol      0
          iInterface             14
          Device Firmware Upgrade Interface Descriptor:
            bLength                             7
            bDescriptorType                    33
            bmAttributes                        7
              Will Not Detach
              Manifestation Tolerant
              Upload Supported
              Download Supported
            wDetachTimeout                    250 milliseconds
            wTransferSize                      64 bytes
    

    Tsuneo

  • The terms, Asynchronous / Synchronous / Adaptive on USB audio class mean the synchronization type.
    It suggests the place where the original sampling clock sits on.

    - Asynchronous: the sampling clock is generated on the device side.
    - Synchronous: the clock derives from USB SOF by PLL
    - Adaptive: the clock is generated on the host side.

    For Asynchronous Sink (output) device, like a speaker,
    the device has to notify to host on its sampling clock, to synchronize the host. For this purpose, a feedback endpoint (isoc IN) is associated to the isoc OUT endpoint of the audio stream, like above QB9

    For Asynchronous Source (input) device, like a microphone,
    The sampling rate on the device is shown as the number of the samples in each isoc packet on the audio stream. The number is relative to the SOF frequency. Therefore, any feedback endpoint is not required.

    Tsuneo

  • I have changed it to

    * Endpoint - Standard Descriptor */
      AUDIO_STANDARD_ENDPOINT_DESC_SIZE,    /* bLength */
      USB_ENDPOINT_DESCRIPTOR_TYPE,         /* bDescriptorType */
      USB_ENDPOINT_OUT(3),                  /* bEndpointAddress */
      //USB_ENDPOINT_TYPE_ISOCHRONOUS,        /* bmAttributes */
      0x05,
      WBVAL(64),                            /* wMaxPacketSize */
      0x01,                                 /* bInterval */
      0x00,                                 /* bRefresh */
      0x00,                                 /* bSynchAddress */
    

    and it worked, I don't understand who ever wrote the bmAttributes in Endpoint Descriptor expected it to be wrote?

    /* bmAttributes in Endpoint Descriptor */
    #define USB_ENDPOINT_TYPE_MASK                 0x03
    #define USB_ENDPOINT_TYPE_CONTROL              0x00
    #define USB_ENDPOINT_TYPE_ISOCHRONOUS          0x01
    #define USB_ENDPOINT_TYPE_BULK                 0x02
    #define USB_ENDPOINT_TYPE_INTERRUPT            0x03
    #define USB_ENDPOINT_SYNC_MASK                 0x0C
    #define USB_ENDPOINT_SYNC_NO_SYNCHRONIZATION   0x00
    #define USB_ENDPOINT_SYNC_ASYNCHRONOUS         0x04
    #define USB_ENDPOINT_SYNC_ADAPTIVE             0x08
    #define USB_ENDPOINT_SYNC_SYNCHRONOUS          0x0C
    #define USB_ENDPOINT_USAGE_MASK                0x30
    #define USB_ENDPOINT_USAGE_DATA                0x00
    #define USB_ENDPOINT_USAGE_FEEDBACK            0x10
    #define USB_ENDPOINT_USAGE_IMPLICIT_FEEDBACK   0x20
    #define USB_ENDPOINT_USAGE_RESERVED            0x30
    

    of the keil code working

    0 bLength 1 09h
    1 bDescriptorType 1 05h Endpoint
    2 bEndpointAddress 1 03h 3 Out
    3 bmAttributes 1 05h Isochronous, Asynchronous, Data
     1..0: Transfer Type  ......01  Isochronous
     3..2: Sync Type  ....01..  Asynchronous
     5..4: Usage Type  ..00....  Data
     7..6: Reserved  00......
    4 wMaxPacketSize 2 0040h 64 bytes
    6 bInterval 1 01h 1 ms
    7 bRefresh 1 00h
    8 bSynchAddress 1 00h
    

    Because of stuff like the above, I can not figure out how to change the isoch transfer size,bytes buffer, bytes data. I can not understand the code of the person who wrote it.

  • > I have changed it to ... and it worked,

    Did you add an isoc IN endpoint for feedback?
    Windows and MacOSX ignore Asynchronous bits on the bmAttributes, if the streaming OUT endpoint isn't associated with a feedback IN endpoint. Without any feedback EP, these audio drivers "work" the device as a Synchronous one.

    Here is an outline of the feedback endpoint of Async Sink.

                               Host side <---- | ----> Device side
                                                                                    Counter
                              +---------- synch IN EP <------ shift to    <-------- gated by SOF
                              |                               10.10 format               ^
                              |                                                          |
                              |                                                      Base clock
                           Feedback                                                      |
                              |                                                       Divider
                              |                                                          |
                              V                                                          V
    Audio Source ===(rate conversion)===> isoc OUT EP =============> buffer ==========> DAC ===> Speaker
    

    For the details, refer to this chapter on the USB2.0 spec (usb_20.pdf, in www.usb.org/.../usb_20_071411.zip )
    5.12.4.2 Feedback



    > I can not figure out how to change the isoch transfer size,bytes buffer, bytes data.

    The format of the streaming packet is defined on the descriptor on your device.
    Above QB-9 declares these descriptors on the streaming interface.

          AudioStreaming Interface Descriptor:
            bLength                 7
            bDescriptorType        36
            bDescriptorSubtype      1 (AS_GENERAL)
            bTerminalLink           1
            bDelay                  1 frames
            wFormatTag              1 PCM
          AudioStreaming Interface Descriptor:
            bLength                20
            bDescriptorType        36
            bDescriptorSubtype      2 (FORMAT_TYPE)
            bFormatType             1 (FORMAT_TYPE_I)
            bNrChannels             2
            bSubframeSize           3
            bBitResolution         24
            bSamFreqType            4 Discrete
            tSamFreq[ 0]        44100
            tSamFreq[ 1]        48000
            tSamFreq[ 2]        88200
            tSamFreq[ 3]        96000
    

    This descriptors declare,
    - Type I PCM (wFormatTag / bFormatType)
    - 2ch (L/R) (bNrChannels)
    - 3 bytes, 24bits (bSubframeSize / bBitResolution)
    - 44.1, 48, 88.2, 96 kHz (tSamFreq[])

    For 96 kHz, every isoc OUT packet has the size, 3 bytes * 2 ch * 96 samples = 576 bytes, primarily.
    However, the sampling frequency of the device is not exactly 96 times of the SOF frequency.
    The crystal which sources 96 kHz has some tolerance. Also, USB spec defines the tolerance of Frame interval as 1.000 ms +/-500 ns

    Therefore, actual packet size may have plus/minus by one sample
    3 bytes * 2 ch * (96 + 1) samples = 582 bytes
    In this reason, above QB-9 example sets wMaxPacketSize to 582

    Tsuneo

  • >Did you add an isoc IN endpoint for feedback?

    I believe so yes?

    /* Audio Input Terminal */
      AUDIO_INPUT_TERMINAL_DESC_SIZE,       /* bLength */
      AUDIO_INTERFACE_DESCRIPTOR_TYPE,      /* bDescriptorType */
      AUDIO_CONTROL_INPUT_TERMINAL,         /* bDescriptorSubtype */
      0x01,                                 /* bTerminalID */
      WBVAL(AUDIO_TERMINAL_USB_STREAMING),  /* wTerminalType */
      0x00,                                 /* bAssocTerminal */
      0x01,                                 /* bNrChannels */
      WBVAL(AUDIO_CHANNEL_M),               /* wChannelConfig */
      0x00,                                 /* iChannelNames */
      0x00,                                 /* iTerminal */
    /* Audio Feature Unit */
      AUDIO_FEATURE_UNIT_DESC_SZ(1,1),      /* bLength */
      AUDIO_INTERFACE_DESCRIPTOR_TYPE,      /* bDescriptorType */
      AUDIO_CONTROL_FEATURE_UNIT,           /* bDescriptorSubtype */
      0x02,                                 /* bUnitID */
      0x01,                                 /* bSourceID */
      0x01,                                 /* bControlSize */
      AUDIO_CONTROL_MUTE |
      AUDIO_CONTROL_VOLUME,                 /* bmaControls(0) */
      0x00,                                 /* bmaControls(1) */
      0x00,                                 /* iTerminal */
    /* Audio Output Terminal */
      AUDIO_OUTPUT_TERMINAL_DESC_SIZE,      /* bLength */
      AUDIO_INTERFACE_DESCRIPTOR_TYPE,      /* bDescriptorType */
      AUDIO_CONTROL_OUTPUT_TERMINAL,        /* bDescriptorSubtype */
      0x03,                                 /* bTerminalID */
      WBVAL(AUDIO_TERMINAL_SPEAKER),        /* wTerminalType */
      0x00,                                 /* bAssocTerminal */
      0x02,                                 /* bSourceID */
      0x00,                                 /* iTerminal */
    /* Interface 1, Alternate Setting 0, Audio Streaming - Zero Bandwith */
      USB_INTERFACE_DESC_SIZE,              /* bLength */
      USB_INTERFACE_DESCRIPTOR_TYPE,        /* bDescriptorType */
      0x01,                                 /* bInterfaceNumber */
      0x00,                                 /* bAlternateSetting */
      0x00,                                 /* bNumEndpoints */
      USB_DEVICE_CLASS_AUDIO,               /* bInterfaceClass */
      AUDIO_SUBCLASS_AUDIOSTREAMING,        /* bInterfaceSubClass */
      AUDIO_PROTOCOL_UNDEFINED,             /* bInterfaceProtocol */
      0x00,                                 /* iInterface */
    /* Interface 1, Alternate Setting 1, Audio Streaming - Operational */
      USB_INTERFACE_DESC_SIZE,              /* bLength */
      USB_INTERFACE_DESCRIPTOR_TYPE,        /* bDescriptorType */
      0x01,                                 /* bInterfaceNumber */
      0x01,                                 /* bAlternateSetting */
      0x01,                                 /* bNumEndpoints */
      USB_DEVICE_CLASS_AUDIO,               /* bInterfaceClass */
      AUDIO_SUBCLASS_AUDIOSTREAMING,        /* bInterfaceSubClass */
      AUDIO_PROTOCOL_UNDEFINED,             /* bInterfaceProtocol */
      0x00,                                 /* iInterface */
    /* Audio Streaming Interface */
      AUDIO_STREAMING_INTERFACE_DESC_SIZE,  /* bLength */
      AUDIO_INTERFACE_DESCRIPTOR_TYPE,      /* bDescriptorType */
      AUDIO_STREAMING_GENERAL,              /* bDescriptorSubtype */
      0x01,                                 /* bTerminalLink */
      0x01,                                 /* bDelay */
      WBVAL(AUDIO_FORMAT_PCM),              /* wFormatTag */
    /* Audio Type I Format */
      AUDIO_FORMAT_TYPE_I_DESC_SZ(1),       /* bLength */
      AUDIO_INTERFACE_DESCRIPTOR_TYPE,      /* bDescriptorType */
      AUDIO_STREAMING_FORMAT_TYPE,          /* bDescriptorSubtype */
      AUDIO_FORMAT_TYPE_I,                  /* bFormatType */
      0x01,                                 /* bNrChannels */
      0x02,                                 /* bSubFrameSize */
      16,                                   /* bBitResolution */
      0x01,                                 /* bSamFreqType */
      B3VAL(32000),                         /* tSamFreq */
    /* Endpoint - Standard Descriptor */
      AUDIO_STANDARD_ENDPOINT_DESC_SIZE,    /* bLength */
      USB_ENDPOINT_DESCRIPTOR_TYPE,         /* bDescriptorType */
      USB_ENDPOINT_OUT(3),                  /* bEndpointAddress */
      //USB_ENDPOINT_TYPE_ISOCHRONOUS,        /* bmAttributes */
      0x05,
      WBVAL(64),                            /* wMaxPacketSize */
      0x04,                                 /* bInterval */
      0x00,                                 /* bRefresh */
      0x00,                                 /* bSynchAddress */
    

    I still am not sure how to change the isoch transfer with the keil code.

    But I think it is 10 * 64 = 640. I did change WBVAL(64), to WBVAL(128), but it is still only 640

    Interface 1 / Alt 1     Audio, 1 pipe
    Endpoint 03h    3 Out, Isochronous 128 bytes
    
    Endpoint 03h    3 Out, Isochronous
    
    Bytes to Transfer       280h (640)
    
    

  • >> Did you add an isoc IN endpoint for feedback?
    > I believe so yes?

    Not yet.
    Add a descriptor of the feedback EP,
    Modify the standard / class-specific EP descriptors.
    Your Type I descriptor declares PCM of 2 bytes (16bits), single channel, 32kHz sampling.
    Therefore, wMaxPacketSize of the isoc OUT EP is 66 bytes.
    2 bytes * 1 ch * (32 + 1) samples = 66 bytes

    /* Endpoint - Standard Descriptor */
      AUDIO_STANDARD_ENDPOINT_DESC_SIZE,    /* bLength */
      USB_ENDPOINT_DESCRIPTOR_TYPE,         /* bDescriptorType */
      USB_ENDPOINT_OUT(3),                  /* bEndpointAddress */
      //USB_ENDPOINT_TYPE_ISOCHRONOUS,        /* bmAttributes */
      0x05,                    // <----- USB_ENDPOINT_TYPE_ISOCHRONOUS | USB_ENDPOINT_SYNC_ASYNCHRONOUS
      WBVAL(64),                            /* wMaxPacketSize */ // <----- WBVAL(66)
      0x04,                                 /* bInterval */      // <----- 0x01 (every 1ms)
      0x00,                                 /* bRefresh */
      0x00,                                 /* bSynchAddress */  // <----- 0x83 (IN 3)
    
    /* Endpoint - Audio Streaming */
      AUDIO_STREAMING_ENDPOINT_DESC_SIZE,   /* bLength */
      AUDIO_ENDPOINT_DESCRIPTOR_TYPE,       /* bDescriptorType */
      AUDIO_ENDPOINT_GENERAL,               /* bDescriptor */
      0x00,                                 /* bmAttributes */
      0x00,                                 /* bLockDelayUnits */ // <----- 0x02 (Decoded PCM samples)
      WBVAL(0x0000),                        /* wLockDelay */
    
    /* Endpoint - Standard Descriptor */                       // <-------- additional feedback EP
      AUDIO_STANDARD_ENDPOINT_DESC_SIZE,    /* bLength */
      USB_ENDPOINT_DESCRIPTOR_TYPE,         /* bDescriptorType */
      USB_ENDPOINT_IN(3),                   /* bEndpointAddress */
      USB_ENDPOINT_TYPE_ISOCHRONOUS,        /* bmAttributes */
      WBVAL(3),                             /* wMaxPacketSize */
      0x01,                                 /* bInterval */
      0x01,                                 /* bRefresh, every 2ms */
      0x00,                                 /* bSynchAddress */
    
    /* Terminator */
      0                                     /* bLength */
    };
    

    With this addition of the feedback EP, the wTotalLength on the Config descriptor is modified, as follows

    /* Configuration 1 */
      USB_CONFIGUARTION_DESC_SIZE,          /* bLength */
      USB_CONFIGURATION_DESCRIPTOR_TYPE,    /* bDescriptorType */
      WBVAL(                                /* wTotalLength */
        USB_CONFIGUARTION_DESC_SIZE         +
        USB_INTERFACE_DESC_SIZE             +
        AUDIO_CONTROL_INTERFACE_DESC_SZ(1)  +
        AUDIO_INPUT_TERMINAL_DESC_SIZE      +
        AUDIO_FEATURE_UNIT_DESC_SZ(1,1)     +
        AUDIO_OUTPUT_TERMINAL_DESC_SIZE     +
        USB_INTERFACE_DESC_SIZE             +
        USB_INTERFACE_DESC_SIZE             +
        AUDIO_STREAMING_INTERFACE_DESC_SIZE +
        AUDIO_FORMAT_TYPE_I_DESC_SZ(1)      +
        AUDIO_STANDARD_ENDPOINT_DESC_SIZE   +
        AUDIO_STREAMING_ENDPOINT_DESC_SIZE  +              // <----------
        AUDIO_STANDARD_ENDPOINT_DESC_SIZE                  // <----------
      ),
    

    The feedback endpoint is supplied with the frequency ratio (master sampling / SOF frequency) in 10.10 fixed-point format on 3 bytes (left-justified, ie. 10.14 format).

    In this example, 32kHz master clock derives from PCLK, divided by (VPB_CLOCK/DATA_FREQ) at Timer0.
    To generate feedback value,
    - Run another timer on PCLK in free run
    - At USB_SOF_Event() (usbuser.c),
    - - read this timer count.
    - - Calculate this value
    ((current_timer_count - last_timer_count) << 14) / (VPB_CLOCK / DATA_FREQ)
    - - Write the LSB 3 bytes of this calculated value (LSB first) into the IN 3 EP, using USB_WriteEP()
    - - Save current_timer_count into last_timer_count

    Tsuneo

  • >- Run another timer on PCLK in free run

    Is this what you mean by free run, just leaving it blank? What is this (VPB_CLOCK) you talk of.

    void TIMER1_IRQHandler(void)
    {
    
    LPC_TIM1->IR = 1;                         /* Clear Interrupt Flag */
    
    
    
    
    LPC_SC->PCONP |= 1 << 2;     // Power on Timer'
    
      LPC_TIM1->MR0 = pclk/DATA_FREQ - 1;   /* TC0 Match Value 0 */
      LPC_TIM1->MCR = 3;                                    /* TCO Interrupt and Reset on MR0 */
      LPC_TIM1->TCR = 1;                                    /* TC0 Enable */
      NVIC_EnableIRQ(TIMER0_IRQn);
    
    
       }
    

  • >- At USB_SOF_Event() (usbuser.c),
    > - - read this timer count.
    > - - Calculate this value

    I have been goolge but have not found out how to do this yet, I had a go at it.

    uint32_t current_timer_count

    uint32_t last_timer_count

    #if USB_SOF_EVENT
    void USB_SOF_Event (void) {
    #if TIMER1_IRQHandler > 0
    current_timer_count = TIMER1
    else if
    current_timer_count = TIMER1
    TIMER1 = last_timer_count
    
    #if USB_SOF_EVENT
    void USB_SOF_Event (void) {
    #if TIMER1_IRQHandler > 0
    current_timer_count = TIMER1
    else if
    #if TIMER1_IRQHandler < 1000
    TIMER1 = last_timer_count
    
    LPC_TIM1->MR0 =  1000;
    

  • Unsure about LSB but is this close or not

    #if USB_SOF_EVENT
    void USB_SOF_Event (void) {
    #if USB_DMA == 1
    
    
    >Calculate this value, Write the LSB 3 bytes of this calculated value (LSB first) into the IN 3 EP, using USB_WriteEP()
    if (USB_WriteEP(0x83,((current_timer_count - last_timer_count) << 14) / pclk/DATA_FREQ - 1;
    
    > - - Save current_timer_count into last_timer_count
    
    current_timer_count = last_timer_count
    
    
    LPC_USB->USBDMARSet = 1 << EPAdr(0x83);
    

  • I put timer counter in main.c like this

    void TIMER1_IRQHandler(void)
    {
    
    if TIMER1_IRQHandler > 0
    current_timer_count = TIMER1
    else if TIMER1_IRQHandler < 1000
    TIMER1 = last_timer_count
    
    
    LPC_TIM1->IR = 1;                         /* Clear Interrupt Flag */
    
    
    
    
      LPC_SC->PCONP |= 1 << 2;     // Power on Timer'
    
      LPC_TIM1->MR0 =  1000; // 1us
    
    
      LPC_TIM1->MCR = 3;                                    /* TCO Interrupt and Reset on MR0 */
      LPC_TIM1->TCR = 1;                                    /* TC0 Enable */
      NVIC_EnableIRQ(TIMER0_IRQn);
    
    

  • In above post, I've missed to pick up this mods to the streaming interface descriptor.

    /* Interface 1, Alternate Setting 1, Audio Streaming - Operational */
      USB_INTERFACE_DESC_SIZE,              /* bLength */
      USB_INTERFACE_DESCRIPTOR_TYPE,        /* bDescriptorType */
      0x01,                                 /* bInterfaceNumber */
      0x01,                                 /* bAlternateSetting */
      0x01,                                 /* bNumEndpoints */    <----- 0x02 (plus one, for the feedback EP)
      USB_DEVICE_CLASS_AUDIO,               /* bInterfaceClass */
      AUDIO_SUBCLASS_AUDIOSTREAMING,        /* bInterfaceSubClass */
      AUDIO_PROTOCOL_UNDEFINED,             /* bInterfaceProtocol */
      0x00,                                 /* iInterface */
    

    >> - Run another timer on PCLK in free run
    > Is this what you mean by free run, just leaving it blank? What is this (VPB_CLOCK) you talk of.

    Just enable the Timer1 on the default setting. No interrupt is required for the Timer1

    current_timer_count is a readout of Timer1 register (T1TC), at the entry of USB_SOF_Event() callback.
    It represents the SOF timing measured on the PCLK, which is also the master sampling clock for DAC.
    Unfortunately, USB engines on LPC family don't have hardware SOF trigger to Timers. As a workaround, the timer value at the SOF timing is captured by the firmware at SOF (FRAME) interrupt.

    > if (USB_WriteEP(0x83,((current_timer_count - last_timer_count) << 14) / pclk/DATA_FREQ - 1;

    "- 1" is not required.
    The example sets up Timer0 match register with "VPB_CLOCK/DATA_FREQ - 1"

    demo.c
    int main(void)
    {
      ...
      /* Setup Timer Counter 0: Periodic Timer with Interrupt at DATA_FREQ Rate */
      T0MR0 = VPB_CLOCK/DATA_FREQ - 1;          /* TC0 Match Value 0 */
    


    It's because the full-count of the timer is less than the total count by one
    For the calculation of feedback value, the total count (VPB_CLOCK/DATA_FREQ) is applied.
    Also, round bracket is recommended around (pclk/DATA_FREQ), to control the calculation order.

    Tsuneo

  • Ah, the second parameter of USB_WriteEP() takes a buffer, not a value.

    uint32_t feedback_value;
    feedback_value = ((current_timer_count - last_timer_count) << 14) / (VPB_CLOCK/DATA_FREQ);
    USB_WriteEP( 0x83, &feedback_value, 3 );

    Tsuneo

  • >current_timer_count - last_timer_count

    You have not explain why you have wrote this, I not sure how to read Timer and the examples don't have any values like the above, so if you could explain more it would help. Was the main.c I wrote correct of wrong?

  • On the startup section of the main(), just enable Timer1 on the default setting.

    demo.c
    
    /* Main Program */
    
    int main (void) {
      ...
      ...
      /* Setup Timer Counter 0 Interrupt */
      VICVectAddr4 = (unsigned long)tc0_isr;    /* TC0 Interrupt -> Vector 4   */
      VICVectCntl4 = 0x02;                      /* TC0 Interrupt -> Priority 2 */
      VICIntEnable = 1 << 4;                    /* Enable TC0 Interrupt */
    
      /* Setup Timer1 for rate feedback */
      T1TCR = 1;                                /* TC1 Enable */
    
      lcd_init();
      ...
    

    Here is mods for USB_SOF_Event(). For rate feedback, the extra code (in red) is inserted

    usbuser.c
    
    /*
     *  USB Start of Frame Event Callback
     *   Called automatically on USB Start of Frame Event
     */
    
    DWORD last_timer_count;
    
    #if USB_SOF_EVENT
    void USB_SOF_Event (void) {
      DWORD current_timer_count;
      DWORD feedback_value;
                                                    // feedback
      current_timer_count = T1TC;                   // capture current SOF timing on the Timer1
      if ( USB_AltSetting[1] == 1 ) {               // When interface 1 / alt 1 is enabled,
                                                    // calculate master/SOF frequency ratio in 10.10 (10.14) format
        feedback_value = ((current_timer_count - last_timer_count) << 14) / (VPB_CLOCK/DATA_FREQ);
                                                    // and send it to the feedback IN EP
        USB_WriteEP( 0x83, (BYTE*)&feedback_value, 3 );
      }
      last_timer_count = current_timer_count;       // update the last SOF timing
    
    #if USB_DMA == 0
      ...
    

    > current_timer_count - last_timer_count

    This subtraction calculates SOF interval, on the tick of PCLK

    Tsuneo

  • My friend come down and we test with his board, but the code is different.

    So we make modifaction to his code, it's working but I am not sure if I have done it yet.

    Was I supposed to change the Timer to 1 here

    /*
     * Timer Counter 0 Interrupt Service Routine
     *   executed each 31.25us (32kHz frequency)
     */
    
    void TIMER1_IRQHandler(void){
    
    if (DataRun) {                            /* Data Stream is running */
        val = DataBuf[DataOut];                 /* Get Audio Sample */
        cnt = (DataIn - DataOut) & (B_S - 1);   /* Buffer Data Count */
        if (cnt == (B_S - P_C*P_S)) {           /* Too much Data in Buffer */
          DataOut++;                            /* Skip one Sample */
    

    Unsure about if current_timer_count = LPC_TIM1->TCR timer control register is right or not? or should it be LPC_TIM1->CCR the capture control register?

    uint32_t last_timer_count;
    
    #if USB_SOF_EVENT
    void USB_SOF_Event (void) {
    uint32_t current_timer_count;
      uint32_t feedback_value;
      uint32_t pclk;
                                                    // feedback
      current_timer_count = LPC_TIM1->TCR;                   // capture current SOF timing on the Timer1
      if ( USB_AltSetting[1] == 1 ) {               // When interface 1 / alt 1 is enabled,
                                                    // calculate master/SOF frequency ratio in 10.10 (10.14) format
        feedback_value = ((current_timer_count - last_timer_count) << 14) / (pclk/DATA_FREQ);
                                                    // and send it to the feedback IN EP
        USB_WriteEP( 0x83, (uint8_t *)&feedback_value, 3 );
      }
      last_timer_count = current_timer_count;       // update the last SOF timing
    #if USB_DMA == 0
    
    
    LPC_TIM1->MR0 = pclk/DATA_FREQ;   /* TC0 Match Value 0 */
      LPC_TIM1->MCR = 3;                                    /* TCO Interrupt and Reset on MR0 */
      LPC_TIM1->TCR = 1;                                    /* TC0 Enable */
      NVIC_EnableIRQ(TIMER1_IRQn);
    
    /* Setup Timer1 for rate feedback */
      //T1TCR = 1;                                /* TC1 Enable */
      LPC_SC->PCONP |= 1 << 2;     // Power on Timer'
      //LPC_TIM1->TCR = 1;
    

    Ok thanks for any help as I say code is different to my board.