HID USB data rate

28 Dec 2011

Hello,

I need to send to the Mbed 528bytes 25 times per second.

So I used HID USB on mbed and HIDAPI on my computer (with Qt). I make messages from 63bytes (and I add a "0x00" Report ID) to send a complete transfert to the mbed.

It works great but the data rate transfert is really bad (8kB/s to send the 528bytes...) I don't see how I can improve this rate. Can you help me?

Thanks a lot!

08 Aug 2012

Vincent Donnefort wrote:

Hello,

I need to send to the Mbed 528bytes 25 times per second.

So I used HID USB on mbed and HIDAPI on my computer (with Qt). I make messages from 63bytes (and I add a "0x00" Report ID) to send a complete transfert to the mbed.

It works great but the data rate transfert is really bad (8kB/s to send the 528bytes...) I don't see how I can improve this rate. Can you help me?

Thanks a lot!

Dear Vincent,

could you find any solution for improve the data rate?

Selim.

08 Aug 2012

Hi,

Concerning the HID usb interface, you can send up to 64bytes each millisecond (64 kBytes/s). For that you have to use:

USBHID hid(64, 64);

send_report.length = 64;
for (int i = 0; i < send_report.length; i++) {
    send_report.data[i] = rand() & 0xff;
}

//Send the report
hid.send(&send_report);

Hope that helps

Sam

09 Aug 2012

Hi Samuel,

Thanks for reply.

I tried as you wrote. It worked fine at 64kb/s. I tried my code after that . It also worked same data rate (I didn't do any changes on my code). But my code is works 8kb/s when I power off and power on the mbed. Why does it happen You think?

Thanks

Selim.

09 Aug 2012

Hi Selim,

Quote:

I tried as you wrote. It worked fine at 64kb/s. I tried my code after that . It also worked same data rate (I didn't do any changes on my code). But my code is works 8kb/s when I power off and power on the mbed. Why does it happen You think?

I didn't understand very well. When you try my code, the rate is 64kBytes/s and when you use your code, the rate is 8kBytes/s ?

Sam

10 Aug 2012

Samuel Mokrani wrote:

Hi Selim,

Quote:

I tried as you wrote. It worked fine at 64kb/s. I tried my code after that . It also worked same data rate (I didn't do any changes on my code). But my code is works 8kb/s when I power off and power on the mbed. Why does it happen You think?

I didn't understand very well. When you try my code, the rate is 64kBytes/s and when you use your code, the rate is 8kBytes/s ?

Sam

Samuel,

Your code works very well at 64 KB/s while mine works at 8 KB/s. But if i test my code after testing yours keeping the usb cable plugged in, my code also works at 64 KB/s. However, if i unplug the usb cable after testing your code and re-plug it (i.e. restart the mbed) my code goes back to work at 8 KB/s.

Selim.

10 Aug 2012

Selim Olcer wrote:

Samuel Mokrani wrote:

Hi Selim,

Quote:

I tried as you wrote. It worked fine at 64kb/s. I tried my code after that . It also worked same data rate (I didn't do any changes on my code). But my code is works 8kb/s when I power off and power on the mbed. Why does it happen You think?

I didn't understand very well. When you try my code, the rate is 64kBytes/s and when you use your code, the rate is 8kBytes/s ?

Sam

Samuel,

Your code works very well at 64 KB/s while mine works at 8 KB/s. But if i test my code after testing yours keeping the usb cable plugged in, my code also works at 64 KB/s. However, if i unplug the usb cable after testing your code and re-plug it (i.e. restart the mbed) my code goes back to work at 8 KB/s.

Selim.

Meanwhile, my usb definitions in my code is same in yours

10 Aug 2012

Hello Selim, are You using ticker in Your code? Can You please post Your code? I am also interested in "what is going on"?

13 Aug 2012

little llumpu wrote:

Hello Selim, are You using ticker in Your code? Can You please post Your code? I am also interested in "what is going on"?

Hello,

No, I don't use ticker but I use adc interrupt. my code is:

#include "mbed.h"
#include "USBHID.h"
#include "stdio.h"
#include "tanimlamalar.h"


void adcInit(uint32_t ADC_Clk );
extern "C" void ADC_IRQHandler (void) __irq ;
uint32_t ADCRead( uint8_t );
void sinyalVer(void);

volatile uint32_t OverRunCounter = 0;
volatile uint32_t ADCIntDone = 0, tumPiksellerOkundu = 0;


void changeRowCol(unsigned char row, unsigned char column);
void changeRowColOwnCode(unsigned char row, unsigned char column);

unsigned int rowBusData[64] = {0,512,64,576,2,514,66,578,256,768,320,832,258,770,322,834,1,513,65,577,3,515,67,579,257,769,321,833,259,771,323,835,128,640,192,704,130,642,194,706,384,896,448,960,386,898,450,962,129,641,193,705,131,643,195,707,385,897,449,961,387,899,451,963};

//We declare a USBHID device. By default input and output reports are 64 bytes long.
//USBHID hid(64,8 ,0x1234,0x0006);
USBHID hid(64, 64);

//This report will contain data to be sent
HID_REPORT send_report;
HID_REPORT recv_report;

//AnalogIn adcCInput(p16);        //Cartesian array i&#65533;in analog giri&#65533;
PwmOut pwm(p21);
DigitalOut adcToggle(p20);      //adc okurken toggle yap&#65533;p kontrol ediyorum sadece
DigitalOut transmitLed(LED1);
DigitalOut receiveLed(LED2);
DigitalOut debugLed(LED3);
DigitalOut donguLed(LED4);
BusInOut cRowBus(p5, p8, p10, p6, p9, p7);      //Cartesian array sat&#65533;r pinleri. s&#65533;ras&#65533; &#65533;nemli
BusInOut cColBus(p25, p26, p29, p27, p28, p30); //Cartesian array s&#65533;tun pinleri

volatile unsigned char mainStateMachine =0, colIndex=0,rowIndex=0,sayac=0,colIndexTemp=0,rowIndexTemp=0 ;
volatile unsigned int pixels[64][64],adcValue,averageCount,tempInteger,tempInteger1;
volatile unsigned long averageValue;
float pwmDutyCycleValue=0.50;
unsigned int pwmPeriodUs=654;
char c=0;


int main() {
    send_report.length = 64;
    cColBus.mode(OpenDrain);
    cColBus.output();
    cRowBus.mode(OpenDrain);
    cRowBus.output();

    pwm.period_us(pwmPeriodUs);
    pwm = pwmDutyCycleValue;

    if (averageCount==0) averageCount=1;
    mainStateMachine=bekle;
    adcInit(13000000);
    ADCRead(1);
    while (1) {
        if (OverRunCounter>0) {
            while (1) {
                donguLed=~donguLed;
                wait_ms(500);
            }
        }
        //try to read a msg
        if (hid.readNB(&recv_report)) {
            receiveLed = !receiveLed;
            switch (recv_report.data[komut]) {
                case sadeceBirPikselOku:
                    rowIndexTemp=recv_report.data[2];           // istenen piksel numaras&#65533;n&#65533; sakl&#65533;yorum.
                    colIndexTemp=recv_report.data[3];
                    //changeRowCol(rowIndex,colIndex);        //uygun kanala gec
                    averageCount=recv_report.data[4]*256;   //Average de&#65533;erini al
                    averageCount+=recv_report.data[5];
                    send_report.data[0]=sadeceBirPikselOku;     //Komut
                    send_report.data[1]=rowIndexTemp;               //Parametre 1
                    send_report.data[2]=colIndexTemp;               //Parametre 2
                    send_report.data[3]=(char)((pixels[rowIndexTemp][colIndexTemp])>>8&0x00FF);     
                    send_report.data[4]=(char)((pixels[rowIndexTemp][colIndexTemp])&0x00FF);        
                    send_report.data[5]=(char)((int)(pwmDutyCycleValue*1000)>>8&0x00ff);       
                    send_report.data[6]=(char)((int)(pwmDutyCycleValue*1000)&0x00ff);
                    send_report.data[7]=(char)((averageCount>>8)&0x00ff);       
                    send_report.data[8]=(char)(averageCount&0x00ff);
                    hid.send(&send_report);
                    transmitLed=!transmitLed;
                    break;
                case averageSayisiYaz:
                    averageCount=recv_report.data[2]*256;
                    averageCount+=recv_report.data[3];
                    break;
               case tumunuToptanGonder:
                    for (rowIndexTemp=0; rowIndexTemp<64; rowIndexTemp++) {
                        for (colIndexTemp=0; colIndexTemp<32; colIndexTemp++) {
                            send_report.data[(colIndexTemp*2)]=(char)(pixels[rowIndexTemp][colIndexTemp] >> 8) & 0x00FF;
                            send_report.data[(colIndexTemp*2)+1]=(char)(pixels[rowIndexTemp][colIndexTemp] & 0x00FF);
                        }
                        hid.send(&send_report);
                        for (colIndexTemp=32; colIndexTemp<64; colIndexTemp++) {
                            send_report.data[(colIndexTemp-32)*2]=(char)(pixels[rowIndexTemp][colIndexTemp] >> 8) & 0x00FF;
                            send_report.data[(colIndexTemp-32)*2+1]=(char)(pixels[rowIndexTemp][colIndexTemp] & 0x00FF);
                        }
                        hid.send(&send_report);
                    }
                    break;
                case pwmPeriyodYaz:
                    tempInteger=recv_report.data[2]*256;       //  pwmFrekans i&#65533;in gelen us cinsinden periyot s&#65533;resi
                    tempInteger+=recv_report.data[3];
                    if (tempInteger>0) {
                        pwm.period_us(tempInteger);
                    }
                    tempInteger=recv_report.data[4]*256;        //  pwmDutyCycle degeri
                    tempInteger+=recv_report.data[5];
                    pwm = (float)tempInteger/1000;
                    pwmDutyCycleValue=pwm.read();
                    break;
            }   // switch recv_report.data
        } //if (hid.readNB(&recv_report))
    }  //while(1)
}   //main


void changeRowCol(unsigned char row, unsigned char column) {
    cRowBus.write(row);
    cColBus.write(column);
}

void adcInit(uint32_t ADC_Clk) {
    uint32_t  pclkdiv, pclk;
    /* Enable CLOCK into ADC controller */
    LPC_SC->PCONP |= (1 << 12);
    /* all the related pins are set to ADC inputs, AD0.0~7 */
    LPC_PINCON->PINSEL1 &= ~0x00030000;     //p0.24 fonksiyonunu s&#65533;f&#65533;rlar
    LPC_PINCON->PINSEL1 |=  0x00010000;     //p0.24'&#65533;n&#65533; ad0.1 fonksiyonuna atar
    /* No pull-up no pull-down (function 10) on these ADC pins. */
    LPC_PINCON->PINMODE1 &= ~0x00030000;      //p0.24 pinmode s&#65533;f&#65533;rlar
    LPC_PINCON->PINMODE1 |=  0x00020000;      //p0.24 pull-up or pull-down yok
    /* By default, the PCLKSELx value is zero, thus, the PCLK for
    all the peripherals is 1/4 of the SystemCoreClock. */
    /* Bit 24~25 is for ADC */
    pclkdiv = (LPC_SC->PCLKSEL0 >> 24) & 0x03;
    switch ( pclkdiv ) {
        case 0x00:
        default:
            pclk = SystemCoreClock/4;
            break;
        case 0x01:
            pclk = SystemCoreClock;
            break;
        case 0x02:
            pclk = SystemCoreClock/2;
            break;
        case 0x03:
            pclk = SystemCoreClock/8;
            break;
    }

    LPC_ADC->ADCR = ( 0x01 << 1 ) |  /* SEL=1,select channel 0~7 on ADC0 */
                    ( ( pclk  / ADC_Clk - 1 ) << 8 ) |  /* CLKDIV = Fpclk / ADC_Clk - 1 */
                    ( 0 << 16 ) |         /* BURST = 0, no BURST, software controlled */
                    ( 0 << 17 ) |          /* CLKS = 0, 11 clocks/10 bits */
                    ( 1 << 21 ) |          /* PDN = 1, normal operation */
                    ( 0 << 24 ) |          /* START = 0 A/D conversion stops */
                    ( 0 << 27 );        /* EDGE = 0 (CAP/MAT singal falling,trigger A/D conversion) */

    /* If POLLING, no need to do the following */

    NVIC_EnableIRQ(ADC_IRQn);
    //LPC_ADC->ADINTEN = 0x1FF;        /* Enable all interrupts */
    LPC_ADC->ADINTEN = 0x102;
    return;
}

extern "C" void ADC_IRQHandler (void) __irq {
    uint32_t regVal;
    volatile uint32_t dummy;
    regVal = LPC_ADC->ADSTAT;        /* Read ADC will clear the interrupt */
    if ( regVal & 0x0000FF00 ) {    /* check OVERRUN error first */
        OverRunCounter++;
        regVal = (regVal & 0x0000FF00) >> 0x08;
        /* if overrun, just read ADDR to clear */
        /* regVal variable has been reused. */
        dummy = LPC_ADC->ADDR0;
        dummy = LPC_ADC->ADDR1;
        dummy = LPC_ADC->ADDR2;
        LPC_ADC->ADCR &= ~((0x7<<24)|(0x1<<16));    /* stop ADC now, turn off BURST bit. */
        ADCIntDone = 1;
        return;
    }
    adcValue = ( LPC_ADC->ADDR1 >> 4 ) & 0xFFF;
    pixels[rowIndex][colIndex]=adcValue;
    if (colIndex<63) {
        colIndex++;
    } else {
        colIndex=0;
        rowIndex++;
        if (rowIndex==64) {
            rowIndex=0;
        }
    }
    changeRowCol(rowIndex,colIndex);
    //  LPC_ADC->ADCR &= ~(0x7<<24);    /* stop ADC now */
    LPC_ADC->ADCR |= (1 << 24) ;        //ADC durmadan devam ediyor.
    ADCIntDone = 1;
    return;
}

/*****************************************************************************
** Function name:        ADCRead
**
** Descriptions:        Read ADC channel
**
** parameters:            Channel number
** Returned value:        Value read, if interrupt driven, return channel #
**
*****************************************************************************/
uint32_t ADCRead( uint8_t channelNum ) {
    //LPC_ADC->ADCR &= 0xFFFFFF00;
    LPC_ADC->ADCR |= (1 << 24) ;//| (1 << channelNum);
    /* switch channel,start A/D convert */
    return ( channelNum );    /* if it's interrupt driven, the ADC reading is
                            done inside the handler. so, return channel number */
}


void sinyalVer(void) {
    debugLed=1;
    wait_ms(100);
    debugLed=0;
    wait_ms(100);
    debugLed=1;
    wait_ms(100);
    debugLed=0;
}