This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

DMA ADC USB, speed improve

Hello every one, When I combine ping pong DMA and the ADC (2MSPS) with USB to send this data to my PC I was able to achieve 3.2 Mbps aprox, But I would like to ask for some recomendations to improve the speed, In my case, I send from the host a 64 Bytes message, and in response I get from the MCU 576 Bytes containing ADC Data. I dont know how I can get more speed (if it is possible). 

I believe that the MCU is the one who limits the speed, in my computer the delays caused from storing the data that comes from the MCU are irrelevant, here is the code (the principal part), to pass the 12 bit ADC data to the 8 bit USB buffer I have to split it, may be there is a better and fastest option?? :

//*****************************************************************************
#ifdef DEBUG
void
__error__(char *pcFilename, uint32_t ui32Line)
{
}
#endif
//*****************************************************************************
void uDMAErrorHandler(void)
{
    uint32_t ui32Status;

    ui32Status = uDMAErrorStatusGet();	// Check for uDMA error bit
    if(ui32Status)						// If there is a uDMA error
    {
        uDMAErrorStatusClear();			//Clear the error status
    }

}
//*****************************************************************************
void ADCseq0Handler()

{

	uint32_t ui32Status = ADCIntStatus(ADC0_BASE, 0, false);
    uint32_t ui32Mode;
    ROM_ADCIntClear(ADC0_BASE, 0);						//se puede eliminar
    ADCIntClearEx(ADC0_BASE, ADC_INT_DMA_SS0);
    ui32Mode = uDMAChannelModeGet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT);
    if(ui32Mode == UDMA_MODE_STOP)
    {

    	w = 0; p = 0;
        uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT,
                                   UDMA_MODE_PINGPONG,
                                   (void *)(ADC0_BASE + (ADC_O_SSFIFO0)),
                                   g_ui8RxBufA, MEM_BUFFER_SIZE);

        g_pui8USBTxBuffer[p]  = g_ui8RxBufA[w] & 0x00FF;p++;
        g_pui8USBTxBuffer[p]  = ((g_ui8RxBufA[w] & 0x0F00) >> 8) | ((g_ui8RxBufA[w+1] & 0x000F) << 4);p++;
        g_pui8USBTxBuffer[p]  = (g_ui8RxBufA[w+1] & 0x0FF0) >> 4;p++;

		for (w = 2; w < 384; w=w+2)
		{
			g_pui8USBTxBuffer[p++]  = g_ui8RxBufA[w] & 0x00FF;
			g_pui8USBTxBuffer[p++]  = ((g_ui8RxBufA[w] & 0x0F00) >> 8) | ((g_ui8RxBufA[w+1] & 0x000F) << 4);
			g_pui8USBTxBuffer[p++]  = (g_ui8RxBufA[w+1] & 0x0FF0) >> 4;
		}
	jeje = 1;
    }
    ui32Mode = uDMAChannelModeGet(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT);
    if(ui32Mode == UDMA_MODE_STOP)

    {

    	w = 0; p = 0;
        uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT,
                                    UDMA_MODE_PINGPONG,
                                    (void *)(ADC0_BASE + (ADC_O_SSFIFO0)),
                                    g_ui8RxBufB, MEM_BUFFER_SIZE);

        g_pui8USBTxBuffer[p]  = g_ui8RxBufB[w] & 0x00FF;p++;
        g_pui8USBTxBuffer[p]  = ((g_ui8RxBufB[w] & 0x0F00) >> 8) | ((g_ui8RxBufB[w+1] & 0x000F) << 4);p++;
        g_pui8USBTxBuffer[p]  = (g_ui8RxBufB[w+1] & 0x0FF0) >> 4;p++;

		for (w = 2; w < 384; w=w+2)
		{
			g_pui8USBTxBuffer[p++]  = g_ui8RxBufB[w] & 0x00FF;
			g_pui8USBTxBuffer[p++]  = ((g_ui8RxBufB[w] & 0x0F00) >> 8) | ((g_ui8RxBufB[w+1] & 0x000F) << 4);
			g_pui8USBTxBuffer[p++]  = (g_ui8RxBufB[w+1] & 0x0FF0) >> 4;
		}
       jeje = 2;
    }
    uDMAChannelEnable(UDMA_CHANNEL_ADC0);
}

//*****************************************************************************
void ADCconfigure1()
{
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE); 										//Habilita puerto E
    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3|GPIO_PIN_2|GPIO_PIN_1); 					//PE3 PE2 PE1 tipo ADC
    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_ADC0);

    ADCClockConfigSet(ADC0_BASE,ADC_CLOCK_SRC_PIOSC | ADC_CLOCK_RATE_FULL, 1);			//Clock source (Precision Internal Clock)
//  ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL, 30);

    ADCSequenceConfigure(ADC0_BASE, 0 , ADC_TRIGGER_ALWAYS, 3);  // SS0-SS3 priorities must always be different
    ADCSequenceStepConfigure(ADC0_BASE, 0 , 0, ADC_CTL_CH0 & 0xFFF0 );  // ADC_CTL_TS = read temp sensor
    ADCSequenceStepConfigure(ADC0_BASE, 0 , 1, ADC_CTL_CH0 & 0xFFF0 );
    ADCSequenceStepConfigure(ADC0_BASE, 0 , 2, ADC_CTL_CH0 & 0xFFF0 );
    ADCSequenceStepConfigure(ADC0_BASE, 0 , 3, ADC_CTL_CH0 & 0xFFF0 );
    ADCSequenceStepConfigure(ADC0_BASE, 0 , 4, ADC_CTL_CH0 & 0xFFF0 );
    ADCSequenceStepConfigure(ADC0_BASE, 0 , 5, ADC_CTL_CH0 & 0xFFF0 );
    ADCSequenceStepConfigure(ADC0_BASE, 0 , 6, ADC_CTL_CH0 & 0xFFF0 );
    ADCSequenceStepConfigure(ADC0_BASE, 0 , 7, ADC_CTL_CH0 & 0xFFF0 | ADC_CTL_END | ADC_CTL_IE);   // ADC_CTL_IE fires every 8 samples
    ADCSequenceEnable(ADC0_BASE, 0);
    ADCSequenceDMAEnable(ADC0_BASE, 0);
    uDMAChannelAttributeDisable(UDMA_CHANNEL_ADC0,
                                    UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST |
                                    UDMA_ATTR_HIGH_PRIORITY |
                                    UDMA_ATTR_REQMASK);
}
//*****************************************************************************
// uint32_t sysclock
void ADCconfigure2()

{
	uDMAChannelControlSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT,
                            UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 |
							UDMA_ARB_1024);

    uDMAChannelControlSet(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT,
                            UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 |
							UDMA_ARB_1024);
    uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT,
                               UDMA_MODE_PINGPONG,
                               (void *)(ADC0_BASE + (ADC_O_SSFIFO0)),
                               g_ui8RxBufA, MEM_BUFFER_SIZE);

    uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT,
                                UDMA_MODE_PINGPONG,
                                (void *)(ADC0_BASE + (ADC_O_SSFIFO0)),
                                g_ui8RxBufB, MEM_BUFFER_SIZE);
    uDMAChannelEnable(UDMA_CHANNEL_ADC0);
    ADCIntEnableEx(ADC0_BASE, ADC_INT_DMA_SS0);
    IntEnable(INT_ADC0SS0);
}
//*****************************************************************************

void ConfigGP()
{
      SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
//    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);
//    GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_2);
//    GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5);
//    tiempo = 2000000;
}
//*****************************************************************************

static uint32_t read_USB(tUSBDBulkDevice *psDevice, uint8_t *pi8Data, uint_fast32_t ui32NumBytes)
{

    USBBufferInfoGet(&g_sTxBuffer, &sTxRing);
    ui32Space = USBBufferSpaceAvailable(&g_sTxBuffer);
    ui32Loop = (ui32Space < ui32NumBytes) ? ui32Space : ui32NumBytes;
    ui32Count = ui32Loop;
    g_ui32RxCount += ui32NumBytes;
//  ui32ReadIndex = (uint32_t)(pi8Data - g_pui8USBRxBuffer);
    while(ui32Loop)
    {
        receptor[index_R] = g_pui8USBRxBuffer[ui32ReadIndex];
        index_R++;
        ui32ReadIndex++;
        ui32ReadIndex = ((ui32ReadIndex == BULK_BUFFER_SIZE) ? 0 : ui32ReadIndex);
        ui32Loop--;
    }

//    count++;
    return(ui32Count);

}
//*****************************************************************************
uint32_t TxHandler(void *pvCBData, uint32_t ui32Event, uint32_t ui32MsgValue,
          void *pvMsgData)
{
    if(ui32Event == USB_EVENT_TX_COMPLETE)
    {
        g_ui32TxCount += ui32MsgValue;
    }
    return(0);
}
//*****************************************************************************
uint32_t RxHandler(void *pvCBData, uint32_t ui32Event, uint32_t ui32MsgValue,void *pvMsgData)
{
    switch(ui32Event)
    {
        case USB_EVENT_CONNECTED:
        {
            miFlag = 0;
            g_bUSBConfigured = true;
            g_ui32Flags |= COMMAND_STATUS_UPDATE;

            USBBufferFlush(&g_sTxBuffer);
            USBBufferFlush(&g_sRxBuffer);

            break;
        }

        case USB_EVENT_DISCONNECTED:
        {
            miFlag = 1;
            g_bUSBConfigured = false;
            g_ui32Flags |= COMMAND_STATUS_UPDATE;
            break;
        }

        case USB_EVENT_RX_AVAILABLE:
        {
            miFlag = 2;
            tUSBDBulkDevice *psDevice;
            psDevice = (tUSBDBulkDevice *)pvCBData;
            index_R = 0;
            return(read_USB(psDevice, pvMsgData, ui32MsgValue));
        }

        case USB_EVENT_SUSPEND:
            miFlag = 3;
        case USB_EVENT_RESUME:
            miFlag = 4;
        case USB_EVENT_STALL:
            miFlag = 5;
            break;

        default:
            miFlag = 5;
            break;
    }

    return(0);
}

//*****************************************************************************
int main(void)
{

    uint32_t ui32SysClock;
    uint32_t ui32PLLRate;


    ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
                                           SYSCTL_OSC_MAIN |
                                           SYSCTL_USE_PLL |
                                           SYSCTL_CFG_VCO_480), 120000000);

//    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);    						// Enable the GPIO port that is used for the on-board LED.
//    ROM_GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_0);    					// Enable the GPIO pins for the LED (PN0).
//    ROM_GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_1);    					// Enable the GPIO pins for the LED (PN0).

    PinoutSet(false, true);
    g_bUSBConfigured = false;

    SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UDMA);
    IntMasterEnable();
    IntEnable(INT_UDMAERR);


    USBBufferInit(&g_sTxBuffer);
    USBBufferInit(&g_sRxBuffer);
    SysCtlVCOGet(SYSCTL_XTAL_25MHZ, &ui32PLLRate);
    USBDCDFeatureSet(0, USBLIB_FEATURE_CPUCLK, &ui32SysClock);
    USBDCDFeatureSet(0, USBLIB_FEATURE_USBPLL, &ui32PLLRate);
    USBStackModeSet(0, eUSBModeDevice, 0);
    USBDBulkInit(0, &g_sBulkDevice);
    ADCconfigure1();
    uDMAEnable();
	uDMAControlBaseSet(pui8ControlTable);
//	int yy;
    while(1)
    {
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
//    	for(yy = 0 ; yy < 10000 ; y++)
//    	ConfigGP();
//    	tiempo = 2000000;
        if(miFlag == 2)
        {
            if(receptor[0] == 'h')
            {

				ADCconfigure2();

			    if (jeje == 1){
					USBBufferDataWritten(&g_sTxBuffer, 577);
				}
				if (jeje == 2){
					USBBufferDataWritten(&g_sTxBuffer, 577);
				}

                ADCSequenceDisable(ADC0_BASE, 0);
                ADCSequenceDMADisable(ADC0_BASE, 0);
            }

        miFlag = 0;
        }

        //rcFlag = 0;
    }
}

One more thing, I know that I can use an external PHY to get more speed, I have already buy the USB3300 demo board from WaveShare, but what I need know is to improve the MCU code to make it more efficient, please, I need help to make a more efficient code.

Thanks in advance :D  

  • Hello Josue

    The speed factor is dependent on both the host and the device processing. The maximum theoretical bandwidth cannot be achieved in real applications due to communication and processing overheads on both host and PC. If the requirement is to get better speeds, I would suggest using USBHS PHY.
  • Hi Amit, maybe do you know if it is posible to increase the DMA destiny position in just 12 bits??, also the DMA's channel size, it is possible to make it of 12 bits, I am asking this because the only available options for both are 8, 16 and 32 bits.