<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="https://community.arm.com/utility/feedstylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Keil usb audio questions</title><link>https://community.arm.com/developer/tools-software/tools/f/keil-forum/27264/keil-usb-audio-questions</link><description> 
Hi 

 
if studied the keil usb-audio example: and there are two things I
didn&amp;#39;t understand. Maybe someone of you could give me some hints /
explanations to these two code lines 

 
DataIn &amp;amp;= B_S - 1; /* Adjust Data In Index */
if (((DataIn - DataOut</description><dc:language>en-US</dc:language><generator>Telligent Community 10</generator><item><title>RE: Keil usb audio questions</title><link>https://community.arm.com/thread/126558?ContentTypeID=1</link><pubDate>Wed, 22 Dec 2010 05:48:59 GMT</pubDate><guid isPermaLink="false">dd9e70c8-6d3c-4c71-b136-2456382a7b5c:4a968ed0-9e19-40a4-97ec-5c13fa18fabd</guid><dc:creator>Chinzei Tsuneo</dc:creator><description>&lt;p&gt;&lt;p&gt;
&lt;i&gt;&amp;gt; Do you know which steps I have to include to use double
buffer algorithm instead of ring-buffer algorithm?&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;
You can&amp;#39;t replace the ring buffer with double buffers, because the
purpose of buffering doesn&amp;#39;t match.&lt;br /&gt;
On this example, the ring buffer is used for sampling rate
adjustment. Double buffer, which is always enabled on bulk and isoc
EPs of LPC17xx, is used to separate the buffer access from firmware
and SIE.&lt;/p&gt;

&lt;p&gt;
I&amp;#39;ll explain about the sampling rate adjustment on this
example.&lt;/p&gt;

&lt;p&gt;
Keil audio example doesn&amp;#39;t define synchronization type on the
endpoint descriptor (no synchronization), which is out of the USB
audio spec. Audio isoc endpoint should have one of synchronization
type, Asynchronous, Synchronous or Adaptive.&lt;/p&gt;

&lt;pre&gt;
&lt;b&gt;usb.h&lt;/b&gt;

#define USB_ENDPOINT_TYPE_ISOCHRONOUS          0x01

&lt;b&gt;usbdesc.c&lt;/b&gt;

const BYTE USB_ConfigDescriptor[] = {
  ...
/* Endpoint - Standard Descriptor */
  AUDIO_STANDARD_ENDPOINT_DESC_SIZE,    /* bLength */
  USB_ENDPOINT_DESCRIPTOR_TYPE,         /* bDescriptorType */
  USB_ENDPOINT_OUT(3),                  /* bEndpointAddress */
  USB_ENDPOINT_TYPE_ISOCHRONOUS,        /* bmAttributes */  &amp;lt;--------- should add synchronization type
  WBVAL(64),                            /* wMaxPacketSize */
  0x01,                                 /* bInterval */
  0x00,                                 /* bRefresh */
  0x00,                                 /* bSynchAddress */
&lt;/pre&gt;

&lt;p&gt;
No synchronization isoc EP is handled as a Synchronous EP on
Windows audio class driver.&lt;br /&gt;
For Synchronous OUT EP, the data is provided to the EP, sampled by
bus clock. Usually bus clock derives from a crystal on PC, whose
frequency slightly differs from the crystal on the device. Therefore,
re-sample is required to play back the data on the device DAC.&lt;/p&gt;

&lt;p&gt;
Audio source ---(re-sample)---&amp;gt; USB bus clock
---(re-sample)---&amp;gt; Device local clock&lt;/p&gt;

&lt;p&gt;
On this example, this re-sample is done in TIMER0_IRQHandler() on
the DataBuf[].&lt;br /&gt;
This process adjust the sampling rate by skipping a sample, or by
re-using the same sample again, according to the difference of
sampling rate. It is tuned by increment of read-out index, DataOut,
as follows.&lt;/p&gt;

&lt;pre&gt;
&lt;b&gt;usbmain.c&lt;/b&gt;

void TIMER0_IRQHandler(void)
{
  long  val;
  uint32_t cnt;

  if (DataRun) {                            /* Data Stream is running */
    val = DataBuf[DataOut];                 /* Get Audio Sample */
    cnt = (DataIn - DataOut) &amp;amp; (B_S - 1);   /* Buffer Data Count */
    if (cnt == (B_S - P_C*P_S)) {           /* Too much Data in Buffer */
      DataOut++;                            /* Skip one Sample */
    }
    if (cnt &amp;gt; (P_C*P_S)) {                  /* Still enough Data in Buffer */
      DataOut++;                            /* Update Data Out Index */
    }
    DataOut &amp;amp;= B_S - 1;                     /* Adjust Buffer Out Index */
    ...
&lt;/pre&gt;

&lt;p&gt;
The size of ring buffer is set to 4 times greater than the packet
(or DMA chunk)&lt;/p&gt;

&lt;pre&gt;
&lt;b&gt;usbaudio.h&lt;/b&gt;

/* Audio Definitions */
#define DATA_FREQ 32000                 /* Audio Data Frequency */
#define P_S       32                    /* Packet Size */
#if USB_DMA
#define P_C       4                     /* Packet Count */
#else
#define P_C       1                     /* Packet Count */
#endif
#define B_S       (8*P_C*P_S)           /* Buffer Size */  // &amp;lt;---- in bytes. Count in 2 bytes (16bits) / sample
&lt;/pre&gt;

&lt;p&gt;
&lt;br /&gt;
As you see in above posts, the firmware pre-buffers up to the half of
the DataBuf[].&lt;br /&gt;
TIMER0_IRQHandler() tunes the consumption of data samples at the
threashold of 1/4 or 3/4 of the buffer size.&lt;/p&gt;

&lt;p&gt;
This process is simple, but the sound quality is not so good.&lt;br /&gt;
Better way is tuning the DAC sampling rate so that it synchronize to
the bus clock.&lt;/p&gt;

&lt;p&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;&amp;gt; I couldn&amp;#39;t find the information in the datasheet of the
LPC17xx controllers where the usb memory for the endpoints will be
allocated.&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;
EP_RAM, the 4K SRAM dedicated for USB.&lt;br /&gt;
See 11.6.3 Endpoint RAM (EP_RAM) on the LPC17xx User manual&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;&amp;gt; But is it correct, that the DataBuf (located at 0x20080000)
is already the buffer in the SRAM not the EP_Buf from the
endpoint?&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;
11.6.5 DMA engine and bus master interface&lt;br /&gt;
&lt;i&gt;When enabled for an endpoint, the DMA Engine transfers data
between &lt;b&gt;RAM on the AHB bus&lt;/b&gt; and the endpoint&amp;#39;s buffer in
EP_RAM.&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;&amp;gt; Moreover if I have two different endpoints using dma to tx
data from the host to the LPC controller. How do I have to init the
DD.BufAdr for both buffers?&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;
Each endpoint has an independent DMA Descriptors linked list.&lt;br /&gt;
See Fig 30. UDCA Head register and DMA Descriptors&lt;/p&gt;

&lt;p&gt;
Tsuneo&lt;/p&gt;
&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Keil usb audio questions</title><link>https://community.arm.com/thread/116176?ContentTypeID=1</link><pubDate>Mon, 20 Dec 2010 07:09:50 GMT</pubDate><guid isPermaLink="false">dd9e70c8-6d3c-4c71-b136-2456382a7b5c:a5417818-9393-4c7e-8281-3c3079bbd2bc</guid><dc:creator>Harald Goverlayne</dc:creator><description>&lt;p&gt;&lt;p&gt;
One small additional question to the audio example from keil&lt;/p&gt;

&lt;pre&gt;
void USB_EndPoint3 (uint32_t event) {
#if USB_DMA
  USB_DMA_DESCRIPTOR DD;

  if (event &amp;amp; USB_EVT_OUT_DMA_EOT) {
    /* End of Transfer */
    if (USB_DMA_BufAdr(0x03) != ((uint32_t)DataBuf + 2*DataIn)) {
      /* Data Available */
      DataIn += P_C*P_S;                    /* Update Data In Index */
      DataIn &amp;amp;= B_S - 1;                    /* Adjust Data In Index */
      if (((DataIn - DataOut) &amp;amp; (B_S - 1)) == (B_S/2)) {
        DataRun = 1;                        /* Data Stream running */
      }
    } else {
      /* No Data */
      DataRun = 0;                          /* Data Stream not running */
      DataOut = DataIn;                     /* Initialize Data Indexes */
    }
  }
  if (event &amp;amp; (USB_EVT_OUT_DMA_EOT) | (USB_EVT_OUT_DMA_NDR)) {
    /* End of Transfer or New Descriptor Request */
    DD.BufAdr  = (uint32_t)DataBuf + 2*DataIn; /* DMA Buffer Address */
    DD.BufLen  = P_C;                       /* DMA Packet Count */
    DD.MaxSize = 0;                         /* Must be 0 for Iso Transfer */
    DD.InfoAdr = (uint32_t)InfoBuf;            /* Packet Info Buffer Address */
    DD.Cfg.Val = 0;                         /* Initial DMA Configuration */
    DD.Cfg.Type.IsoEP = 1;                  /* Iso Endpoint */
    USB_DMA_Setup (0x03, &amp;amp;DD);              /* Setup DMA */
    USB_DMA_Enable(0x03);                   /* Enable DMA */
  }
#else
  event = event;
#endif
}

&lt;/pre&gt;

&lt;p&gt;
&amp;quot;Since DMA is used for ISO communication, the USB RAM&lt;br /&gt;
is allocated for DMA purposes. A scatter file, dma.sct, is&lt;br /&gt;
used in the Keil project file.&amp;quot;&lt;/p&gt;

&lt;p&gt;
I couldn&amp;#39;t find the information in the datasheet of the LPC17xx
controllers where the usb memory for the endpoints will be allocated.
But is it correct, that the DataBuf (located at 0x20080000) is
already the buffer in the SRAM not the EP_Buf from the endpoint?&lt;/p&gt;

&lt;p&gt;
Moreover if I have two different endpoints using dma to tx data
from the host to the LPC controller. How do I have to init the
DD.BufAdr for both buffers? Because if I will use the same
initialization as above, each endpoint will be overwritten by the
other endpoint.&lt;/p&gt;

&lt;p&gt;
best regards&lt;br /&gt;
Jan&lt;/p&gt;
&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Keil usb audio questions</title><link>https://community.arm.com/thread/102363?ContentTypeID=1</link><pubDate>Sun, 19 Dec 2010 11:31:19 GMT</pubDate><guid isPermaLink="false">dd9e70c8-6d3c-4c71-b136-2456382a7b5c:0e71b80d-885a-4c86-be0c-787e8a69ac28</guid><dc:creator>Jan Keller</dc:creator><description>&lt;p&gt;&lt;p&gt;
ok if I&amp;#39;m right, using double buffer is according to the
performance very good, but you have only two 64byte buffers per
endpoint. If the whole packet involves more than 64byte data, you
have to use a ring-buffer, too.&lt;/p&gt;

&lt;p&gt;
If a whole usb-packet contain 500bytes - how big do I have to size
the ring buffer?&lt;/p&gt;
&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Keil usb audio questions</title><link>https://community.arm.com/thread/78887?ContentTypeID=1</link><pubDate>Sun, 19 Dec 2010 04:36:29 GMT</pubDate><guid isPermaLink="false">dd9e70c8-6d3c-4c71-b136-2456382a7b5c:99add8f3-cd65-42dd-920d-aaa34a36e564</guid><dc:creator>Jan Keller</dc:creator><description>&lt;p&gt;&lt;p&gt;
thanks Per for your explanations. Now I understand the whole Keil
example programm.&lt;/p&gt;

&lt;p&gt;
Do you know which steps I have to include to use double buffer
algorithm instead of ring-buffer algorithm?&lt;/p&gt;
&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Keil usb audio questions</title><link>https://community.arm.com/thread/66110?ContentTypeID=1</link><pubDate>Sat, 18 Dec 2010 12:56:26 GMT</pubDate><guid isPermaLink="false">dd9e70c8-6d3c-4c71-b136-2456382a7b5c:5ff5c110-d537-475e-aaba-16c7b6aa89ba</guid><dc:creator>ImPer Westermark</dc:creator><description>&lt;p&gt;&lt;p&gt;
When you have a ring buffer that is 2^n large, you can perform
some tricks.&lt;/p&gt;

&lt;p&gt;
The &amp;quot;normal&amp;quot; way to step the insertion index for a ring buffer
is:&lt;/p&gt;

&lt;pre&gt;
buffer[in] = data;
if (++in &amp;gt;= BUF_SIZE) in = 0;
&lt;/pre&gt;

&lt;p&gt;
&lt;br /&gt;
or maybe&lt;/p&gt;

&lt;pre&gt;
buffer[in] = data;
in = ++in % BUF_SIZE;
&lt;/pre&gt;

&lt;p&gt;
But as a special case, when BUF_SIZE is 2^n, you can do:&lt;/p&gt;

&lt;pre&gt;
buffer[in++ &amp;amp; (BUF_SIZE-1)] = data;
&lt;/pre&gt;

&lt;p&gt;
Most probably, the USB code is letting the read and write indices
just tick up and instead perform an and operation with (BUF_SIZE-1)
whenever they need to index into the buffer.&lt;/p&gt;

&lt;p&gt;
This would mean that:&lt;/p&gt;

&lt;pre&gt;
DataIn &amp;amp;= B_S - 1;                    /* Adjust Data In Index */
&lt;/pre&gt;

&lt;p&gt;
&lt;br /&gt;
is just a way to normalize DataIn as 0 &amp;lt;= DataIn &amp;lt; B_S before
the code compares the input index with the output index.&lt;/p&gt;

&lt;p&gt;
The second line probably just waits until you have buffered a bit
of code before starting the transmission. Then you have 50% of the
buffer size as safety margin to handle jitter.&lt;/p&gt;

&lt;p&gt;
Think about normal CD music. The sample rate is 44100Hz. So the CD
player will emit the data at this speed on a coaxial or optical
output. But what happens if the DAC in the amplifier runs at a
slightly different frequency? If the amplifier waits 50% of a buffer
size before starting to play the music, it has 50% margin to accept
more data in case the CD is slightly faster. And it has 50% buffer
margin to play from the buffer in case the CD is slightly slower.&lt;/p&gt;

&lt;p&gt;
Of course, I might be wrong about the 50% issue, since I haven&amp;#39;t
seen the full code.&lt;br /&gt;
if (((DataIn - DataOut) &amp;amp; (B_S - 1)) == (B_S/2)) { DataRun = 1;
/* Data Stream running */&lt;br /&gt;
}&lt;/p&gt;
&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item></channel></rss>