Good Afternoon.
I would like to stream data at audio frequencies from a control computer to an instrument that I am building. I would like to use the usbdaudio driver and TIRTOS for the TMS1294 processor.
The device shows up as a USB audio device and, under Linux, I can open a screen to ‘test audio’ to the interface, however the buffer completion callback routine that is sent as the fourth parameter of the “USBAudioBufferOut” function is never being called.
I see counters increment on various events, but not on the bufferCallback event. I see that the code reaches breakpoints in the ‘HandleEndpoints’ function at about line 550 of usbdaudio.c, and that it gets to the receive interrupt pending routines at about line 580. However the test to see that the DMA has competed at about line 600 is never passed, hence the DMA completion event is never executed.
If do not make the call toe “USBAudioBufferOut” the data stream, from The Linux host appears to play the data stream correctly as long as I do not call the “USBAudioBufferOut” function. However, this function is necessary to get data from the USB interface. When the USBAudioBufferOut call is made, the USB bus on the Linux computer “locks up” forcing a reboot of the system.
I used the code from chapter 2.3, of the TivaWare USB Library User Guide as starting point.
My goal is to see the end of buffer completion events, in particular the “bufferCallback” function being called, and the associated counter incremented with new incoming packets. This is near line 204 of the included file.
My suspicion is that the USB DMA engine is not being properly initialized. Unfortunately, I do not have a working example to follow.
Thank you very much for your help with this.
Douglas Todd.
// USB_Composite.c // Audio and serial communication classes. /* XDCtools Header files */ #include <xdc/std.h> #include <xdc/runtime/Error.h> #include <xdc/runtime/System.h> /* BIOS Header files */ #include <ti/sysbios/BIOS.h> #include <ti/sysbios/gates/GateMutex.h> #include <ti/sysbios/hal/Hwi.h> #include <ti/sysbios/knl/Semaphore.h> #include <ti/sysbios/knl/Task.h> #include <stdbool.h> #include <stdint.h> /* driverlib Header files */ #include <inc/hw_ints.h> #include <inc/hw_types.h> #include <inc/hw_memmap.h> #include <driverlib/usb.h> #include <ti/drivers/GPIO.h> /* usblib Header files */ #include <usblib/usb-ids.h> #include <usblib/usblib.h> #include <usblib/usbcdc.h> #include <usblib/usblibpriv.h> #include <usblib/device/usbdevice.h> #include <usblib/device/usbdcomp.h> #include <usblib/device/usbdcdc.h> #include <usblib/device/usbdaudio.h> #include "Board.h" // Handlers for Audio messages. static unsigned cbAudioHandler(void *cbData, unsigned event,unsigned eventMsg, void *eventMsgPtr); /* Device Strings */ static const unsigned char g_pui8LangDescriptor[] = { 4, USB_DTYPE_STRING, USBShort(USB_LANG_EN_US) }; /* The manufacturer string. */ static const unsigned char g_pui8ManufacturerString[] = { (18 + 1) * 2, USB_DTYPE_STRING, 'M',0,'a',0,'n',0,'u',0,'f',0,'a',0,'c',0,'t',0, 'u',0,'r',0,'e',0,'r',0,'S',0,'t',0,'r',0,'i',0, 'n',0,'g',0 }; static const unsigned char g_pui8ProductString[] = { ( 17+1)*2, USB_DTYPE_STRING, // Audio and Communications port 'A',0,'u',0,'d',0,'i',0,'o',0,' ',0,'a',0,'n',0, 'd',0,' ',0,'C',0,'o',0,'m',0,'p',0,'o',0,'r',0, 't',0 }; /* The serial number string. */ static const unsigned char g_pui8SerialNumberString[] = { (8 + 1) * 2, USB_DTYPE_STRING, '1', 0, '2', 0, '3', 0, '4', 0, '5', 0, '6', 0, '7', 0, '8', 0 }; //***************************************************************************** static const unsigned char g_pui8HIDInterfaceString[] = { (15 + 1) * 2, USB_DTYPE_STRING, 'A', 0, 'u', 0, 'd', 0, 'i', 0, 'o', 0, ' ', 0, 'I', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0 }; const uint8_t g_pui8ConfigString[] = { (20 + 1) * 2, USB_DTYPE_STRING, 'A', 0, 'u', 0, 'd', 0, 'i', 0, 'o', 0, ' ' , 0, ' ', 0, 'C', 0, 'o', 0, 'n', 0, 'f', 0, 'i', 0, 'g', 0, 'u', 0, 'r', 0, 'a', 0, 't', 0, 'i', 0, 'o', 0, 'n', 0 }; const uint8_t * const g_ppui8StringDescriptors[] ={ g_pui8LangDescriptor, g_pui8ManufacturerString, g_pui8ProductString, g_pui8SerialNumberString, g_pui8HIDInterfaceString, g_pui8ConfigString }; #define NUM_STRING_DESCRIPTORS (sizeof(g_ppui8StringDescriptors) / sizeof(uint8_t *)) static tUSBDAudioDevice g_sAudioDevice = { USB_VID_TI_1CBE, USB_PID_AUDIO, "Hello ", // 8 byte vendor string "World ", "9876", 0, USB_CONF_ATTR_SELF_PWR, cbAudioHandler, g_ppui8StringDescriptors, NUM_STRING_DESCRIPTORS, 0x100, // Max Volume. 0x000, // Min volume 0x014, // Step Volume }; // Instance address returned by the USB audio functions. static void * pvAudioDevice ; unsigned bufferCount = 0; #define ISOC_OUT_EP_MAX_SIZE ((48000*4)/1000) uint16_t audioBufferA [ISOC_OUT_EP_MAX_SIZE/2]; uint16_t audioBufferB [ISOC_OUT_EP_MAX_SIZE/2]; static int supplyBuffer (void); void bufferCallback ( void * pvBuffer , uint32_t ui32Param , uint32_t ui32Event ) ; int counters[16] = {0}; Semaphore_Handle semForground; GateMutex_Handle gateForground; static unsigned cbAudioHandler ( void * cbData, unsigned event, unsigned eventMsg, void * eventMsgPtr){ int retf; switch (event ){ case USB_EVENT_CONNECTED: // 0 counters[0] ++; break; case USB_EVENT_DISCONNECTED: //1 counters[1] ++; break; case USB_EVENT_TX_COMPLETE: // 5 counters[2] ++; break; case USBD_AUDIO_EVENT_IDLE: // C000 counters[3] ++; break; case USBD_AUDIO_EVENT_ACTIVE: // C001 counters[4] ++; supplyBuffer (); break; // Not reached... case USBD_AUDIO_EVENT_DATAOUT: //C002 counters[5] ++; //Semaphore_post ( semForground ); // eventMsg Ptr has data, eventMsg has the length. //supplyBuffer(); break; case USBD_AUDIO_EVENT_MUTE: // C005 counters[6] ++; break; case USBD_AUDIO_EVENT_VOLUME: // C004 counters[7] ++; break; default: counters[8] ++; break; } return 0; } static Void USB_hwiHandler(UArg arg0) { counters[9] ++; USB0DeviceIntHandler(); } /* * Function that _should_ be called when the interface needs another buffer. */ void bufferCallback ( void * pvBuffer , uint32_t ui32Param , uint32_t ui32Event ) { counters[10] ++; supplyBuffer(); } /* * Maintain two buffers, and operate them in ping-pong style. */ static int supplyBuffer() { int retv = 0; void * pBuffer = (void*) (bufferCount ++ & 1 ? audioBufferA : audioBufferB) ; retv = USBAudioBufferOut( pvAudioDevice, pBuffer, ISOC_OUT_EP_MAX_SIZE, bufferCallback ); return retv; } /* Stub task for now. * */ static void taskUsbForground ( unsigned arg0, unsigned arg1 ){ // int isInvalid; while (1 ) { Task_sleep(1000); //Semaphore_pend( semForground , BIOS_WAIT_FOREVER ); counters[11] ++; } } /* Initialization routines * */ void USB_init(void ) { Hwi_Handle hwi; Error_Block eb; Task_Handle taskHandle; Error_init(&eb); Semaphore_Params semParams; Semaphore_Params_init( &semParams); semParams.mode = Semaphore_Mode_BINARY; // Task_Params taskHandle = Task_create (&taskUsbForground, NULL, NULL); /* Install interrupt handler */ hwi = Hwi_create(INT_USB0, USB_hwiHandler, NULL, &eb); if (hwi == NULL) { System_abort("Can't create USB Hwi"); } semForground = Semaphore_create (0, &semParams, &eb) ; if ( semForground == NULL ){ System_abort ("Could not create forground semaphore"); } USBStackModeSet(0, eUSBModeDevice, 0); pvAudioDevice = USBDAudioInit(0, &g_sAudioDevice); // Provision the audio device with the first buffer. // Note that this will cause the USB bus to crash. We don't see received data. supplyBuffer(); } /* * ======== main ======== */ int main(void){ Task_Params taskParams; /* Call board init functions */ Board_initGeneral(); Board_initGPIO(); Board_initUSB(Board_USBDEVICE); USB_init(); /* Turn on user LED */ GPIO_write(Board_LED0, Board_LED_ON); System_printf("Starting USB SimpleAudio\n"); System_flush(); BIOS_start(); return (0); }