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.
> Only want 16 bit resolution and mono.
Increase the sampling frequency from 32kHz to 48kHz. And then, you'll get transfer size of 960 bytes.
Set the sampling frequency - tSamFreq field of the Type I Format descriptor - DATA_FREQ macro (demo.h)
As the packet size increases, you have to touch to these parameters, too. - wMaxPacketSize of the endpoint descriptor - P_S macro (demo.h)
usbdesc.c /* 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 */ // <----- B3VAL(48000) /* Endpoint - Standard Descriptor */ AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength */ USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ USB_ENDPOINT_OUT(3), /* bEndpointAddress */ //USB_ENDPOINT_TYPE_ISOCHRONOUS, /* bmAttributes */ USB_ENDPOINT_TYPE_ISOCHRONOUS | USB_ENDPOINT_SYNC_ASYNCHRONOUS, WBVAL(66), /* wMaxPacketSize */ // <----- WBVAL(98) 0x01, /* bInterval */ 0x00, /* bRefresh */ 0x83, /* bSynchAddress */
demo.h /* Audio Definitions */ #define DATA_FREQ 32000 /* Audio Data Frequency */ // <--- 48000 #define P_S 32 /* Packet Size */ // <--- 48
Tsuneo
We did what you say and it no work?
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype */ AUDIO_FORMAT_TYPE_I, /* bFormatType */ 0x01, /* bNrChannels */ 0x02, /* bSubFrameSize */ 16, /* bBitResolution */ 0x01, /* bSamFreqType */ B3VAL(48000), /* 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(98), /* wMaxPacketSize */ 0x01, /* bInterval */ 0x00, /* bRefresh */ 0x83, /* bSynchAddress */
/* Audio Definitions */ #define DATA_FREQ 48000 /* Audio Data Frequency */ #define P_S 48 /* 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 */
> We did what you say and it no work?
Hmmm.. I tested it on my MCB2300, and surely the board doesn't play any sound. But on a Hardware USB analyzer, everything works fine. - The device enumerates successfully - 96 bytes isoc OUT transactions on every frame, - 3 bytes feedback, which holds around 96 in 10.14 format (ex. 0x0C0041) on every 8 frames
Maybe the buffering and DAC part of the code require more retouch. I'm busy today, so it takes for a while to look into the problem. Meanwhile, check these code on your side, too.
we seem to be getting some unsuccessful tranfers as well, do you know how to fix.
URB Isoch Transfer failed Device Object 0000008e Driver Object usbccgp URB Function URB_FUNCTION_ISOCH_TRANSFER URB Status USBD_STATUS_ISOCH_REQUEST_FAILED Endpoint 83h 3 In, Isochronous Start Frame 4598208 Number of Packets 1 Error Count 1
Found it.
The buffering part of the code expects the buffer size, B_S (ie. P_S), as a number of power of 2, like 2, 4, 8, 16, 32, 64, ... The code abuses "mask" method to keep the buffer indices (DataIn/DataOut) within the array range. For example,
DataIn += P_S; /* Update Data In Index */ DataIn &= B_S - 1; /* Adjust Data In Index */
As we sets P_S to 48, not a number of power of 2, this method failed. Rewrite the buffering code, so that it accept ANY number.
usbuser.c void USB_SOF_Event (void) { DWORD cnt; ... ... #if USB_DMA == 0 if (USB_ReadEP(0x03, (BYTE *)&DataBuf[DataIn])) { /* Data Available */ DataIn += P_S; /* Update Data In Index */ // DataIn &= B_S - 1; /* Adjust Data In Index */ if ( DataIn >= B_S ) { DataIn -= B_S; } // if (((DataIn - DataOut) & (B_S - 1)) == (B_S/2)) { if ( DataIn >= DataOut ) { cnt = DataIn - DataOut; } else { cnt = B_S + DataIn - DataOut; } if ( cnt == (B_S/2)) { DataRun = 1; /* Data Stream running */ } } else { /* No Data */ DataRun = 0; /* Data Stream not running */ DataOut = DataIn; /* Initialize Data Indexes */ } #endif } #endif void USB_EndPoint3 (DWORD event) { #if USB_DMA USB_DMA_DESCRIPTOR DD; DWORD cnt; if (event & USB_EVT_OUT_DMA_EOT) { /* End of Transfer */ if (USB_DMA_BufAdr(0x03) != ((DWORD)DataBuf + 2*DataIn)) { /* Data Available */ DataIn += P_C*P_S; /* Update Data In Index */ // DataIn &= B_S - 1; /* Adjust Data In Index */ if ( DataIn >= B_S ) { DataIn -= B_S; } // if (((DataIn - DataOut) & (B_S - 1)) == (B_S/2)) { if ( DataIn >= DataOut ) { cnt = DataIn - DataOut; } else { cnt = B_S + DataIn - DataOut; } if ( cnt == (B_S/2)) { DataRun = 1; /* Data Stream running */ } } else { /* No Data */ DataRun = 0; /* Data Stream not running */ DataOut = DataIn; /* Initialize Data Indexes */ } }
demo.c void tc0_isr (void) __irq { long val; DWORD cnt; if (DataRun) { /* Data Stream is running */ val = DataBuf[DataOut]; /* Get Audio Sample */ // cnt = (DataIn - DataOut) & (B_S - 1); /* Buffer Data Count */ if ( DataIn >= DataOut ) { /* Buffer Data Count */ cnt = DataIn - DataOut; } else { cnt = B_S + DataIn - DataOut; } if (cnt == (B_S - P_C*P_S)) { /* Too much Data in Buffer */ DataOut++; /* Skip one Sample */ } if (cnt > (P_C*P_S)) { /* Still enough Data in Buffer */ DataOut++; /* Update Data Out Index */ } // DataOut &= B_S - 1; /* Adjust Buffer Out Index */ if ( DataOut >= B_S ) /* Adjust Buffer Out Index */ DataOut -= B_S;
Ok great it worked, but I still have this problem with the code I am writing. I am writing code much like a reverse effects guitar pedal. But it is usb sound card as well and plays windows sound in reverse and you can plug guitar in and mix with windows sounds. My problem is with the timer0 at the moment anything above 8000khz and I get skipping audio becuase the timer is ticking too fast for the audio I think. Do you have any ideas as to how I can fix the skipping audio at 32khz and above.
Here is the code.
/* * Timer Counter 0 Interrupt Service Routine * executed each 31.25us (32kHz frequency) */ void TIMER0_IRQHandler(void) { long val; uint32_t cnt; unsigned short PlaySample; if (DataRun) { /* Data Stream is running */ val = DataBuf[DataOut]; /* Get Audio Sample */ // cnt = (DataIn - DataOut) & (B_S - 1); /* Buffer Data Count */ if ( DataIn >= DataOut ) { /* Buffer Data Count */ cnt = DataIn - DataOut; } else { cnt = B_S + DataIn - DataOut; } if (cnt == (B_S - P_C*P_S)) { /* Too much Data in Buffer */ DataOut++; /* Skip one Sample */ } if (cnt > (P_C*P_S)) { /* Still enough Data in Buffer */ DataOut++; /* Update Data Out Index */ } // DataOut &= B_S - 1; if ( DataOut >= B_S ) /* Adjust Buffer Out Index */ DataOut -= B_S; //if (val < 0) VUM -= val; /* Accumulate Neg Value */ //else VUM += val; /* Accumulate Pos Value */ val *= Volume; /* Apply Volume Level */ val >>= 6; /* Adjust Value */ val += 0x8000; /* Add Bias */ val &= 0xFFFF; /* Mask Value */ } else { val = 0x8000; /* DAC Middle Point */ } if (Mute) { val = 0x8000; /* DAC Middle Point */ } //if (Mute){ //semihost_powerdown();} /* ADAMGR: Inserting my May 30th reversing code here!!! */ { static const unsigned int BufferSize = 10 * 1024 ; static unsigned short Buffer[BufferSize]; static int Index = 0; static int Direction = 1; static int Playback = FALSE; static int ChunkSize = BufferSize; unsigned short ReadSample; /* Default PlaySample to the current sample from USB buffer. */ PlaySample = val; /* Read out the sample from the buffer to be played back */ if (Playback) { PlaySample = Buffer[Index]; } /* Obtain current audio sample from the USB buffer. */ ReadSample = (unsigned short)val; /* Record the sample into the buffer right where a space was freed up from the PlaySample read above */ Buffer[Index] = ReadSample; /* Increment the buffer pointer */ Index += Direction; /* Check to see if the chunk has been filled */ if (Index < 0) { /* Now have a chunk to be played back */ Playback = TRUE; /* Reverse the direction of playback and recording */ Direction *= -1;//Direction; Index = 0; } else if (Index >= ChunkSize) { /* Now have a chunk to be played back */ Playback = TRUE; /* Reverse the direction of playback and recording */ Direction *= -1;//Direction; Index = ChunkSize - 1; } } LPC_DAC->DACR = PlaySample & 0xFFC0; /* Set Speaker Output */ //if ((Tick++ & 0x03FF) == 0) { /* On every 1024th Tick */ //get_potval(); /* Get Potenciometer Value */ if (VolCur == 0x8000) { /* Check for Minimum Level */ Volume = 0; /* No Sound */ } else { Volume = VolCur ;//* PotVal; /* Chained Volume Level */ } //val = VUM >> 20; /* Scale Accumulated Value */ //VUM = 0; /* Clear VUM */ //if (val > 7) val = 7; /* Limit Value */ LPC_TIM0->IR = 1; /* Clear Interrupt Flag */ }
Tsuneo,
I don't have debugger or fancy scope or a fancy jitter scope, or a hardware usb analyser, I am just guessing at this problem, I thought increasing the iso transfer might help, only going all the way down to 8000khz does. because the ticker is increased to I don't know above 60 us perhaps
Does anybody have any suggestion of what to do here. I know if I could separate the code and have two timers might work or if I could store the audio in memory
have a timer on the original code and then store this data in a big memory thing and then another timer on the other code that reads the memory.
but then would be more of a delay..
ideas anyone.
I think I got the answer anyway don't want to ruin this thread maybe you should delete the last couple of posts
use a ringbuffer and read and write in opposite directions. DMA can only do one direction AFAIK (counting up) so you need to write a buffer in reverse direction in software and let the DMA do the playback part. You can use two buffers and switch them on the 'end-of-DMA' interrupt for example. You can also use a simple ticker interrupt and read and write a ringbuffer on each 'tick', again with opposite directions.