Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Writing USB Joystick for PIC18F using MikroC

Status
Not open for further replies.
I'm using PIC18F2458 as USB Joystick HID. The program works, but I have few problems.

Right now, The USB is not detected If I write less than 5 values ( Throttle, X,Y, 4 buttons). The current problem is If I'm using an analog sensor for the throttle, other axis x,y getting read too, because they are going to be read from analog input and of course there is noise, so whenever I use a rotary resistor on the throttle usb input, I get other axis written too.

How can I fix that issue ?

second issue how would I add two throttle for the usb descriptor ?

Here is the current code:
Code:
unsigned int average(int channel)
{
 int samples = 16;
 unsigned int sum = 0;
 int i;
 for (i = 0; i < samples; i++)
 {
 
     sum+=(Adc_Read(channel)>>2)-128;
 }
 sum = sum/16;
 return sum;
}

void analogo() {

    usb[0] = average(1);   // Get 10-bit results of AD conversion
    usb[1] = average(9);
    usb[2] = average(8);
}

void main(void){
                              // Disable comparators

 ADCON1  = 0x05;                         // Configure all ports with analog function as digital
 TRISA.RA1 =1;
 TRISB.RB2=1;
 TRISB.RB3 =1;
 
 HID_Enable(&readbuff,&writebuff);       // Enable HID communication

 //vl6180x_configure();

  while(1){
  analogo();
  USB_Polling_Proc();

    writebuff[0]=usb[0];         // throttle
    writebuff[1]=usb[1];        // X axis
    writebuff[2]=usb[2];        // Y  axis
    writebuff[3]=0xFF;        //button  0xFF
    writebuff[4]=0xFF;        //button POV 0xFF



    HID_Write(&writebuff,5);


   }

}



and the Descriptor

Code:
const struct {
  char report[USB_HID_RPT_SIZE];
}
hid_rpt_desc =

     {0x05, 0x01, // USAGE_PAGE (Generic Desktop)
     0x15, 0x00, // LOGICAL_MINIMUM (0)
     0x09, 0x04, // USAGE (Joystick)
     0xA1, 0x01, // COLLECTION (Application)
     0x05, 0x02, // USAGE_PAGE (Simulation Controls)
     0x09, 0xBB, // USAGE (Throttle)
     0x15, 0x00, // LOGICAL_MINIMUM (0)
     0x26, 0xFF, 0x00, // LOGICAL_MAXIMUM (255)
     0x75, 0x08, // REPORT_SIZE (8)
     0x95, 0x01, // REPORT_COUNT (1)
     0x81, 0x02, // INPUT (Data Var Abs)
     0x05, 0x01, // USAGE_PAGE (Generic Desktop)
     0x09, 0x01, // USAGE (Pointer)
     0xA1, 0x00, // COLLECTION (Physical)
     0x09, 0x30, // USAGE (X)
     0x09, 0x31, // USAGE (Y)
     0x95, 0x02, // REPORT_COUNT (2)
     0x81, 0x02, // INPUT (Data Var Abs)}
     0xC0, // END_COLLECTION
     0x09, 0x39, // USAGE (Hat switch)
     0x15, 0x00, // LOGICAL_MINIMUM (0)
     0x25, 0x03, // LOGICAL_MAXIMUM (3)
     0x35, 0x00, // PHYSICAL_MINIMUM (0)
     0x46, 0x0E, 0x01, // PHYSICAL_MAXIMUM (270)
     0x65, 0x14, // UNIT (Eng Rot:Angular Pos)
     0x75, 0x04, // REPORT_SIZE (4)
     0x95, 0x01, // REPORT_COUNT (1)
     0x81, 0x02, // INPUT (Data Var Abs)
     0x05, 0x09, // USAGE_PAGE (Button)
     0x19, 0x01, // USAGE_MINIMUM (Button 1)
     0x29, 0x0A, // USAGE_MAXIMUM (Button 10)
      0x15, 0x00, // LOGICAL_MINIMUM (0)
      0x25, 0x01, // LOGICAL_MAXIMUM (1)
      0x75, 0x01, // REPORT_SIZE (1)
      0x95, 0x0C, // REPORT_COUNT (12) 2 bits added to switch report count
                  // so bytes are even. Bytes must be even.
      0x55, 0x00, // UNIT_EXPONENT (0)
      0x65, 0x00, // UNIT (None)
      0x81, 0x02, // INPUT (Data Var Abs)
0xC0 // END_COLLECTION
  };

sometimes I want to hook up an analog sensor into the box, and want to read it, so I want to make a more robust analog sensor box, if there is an input read it, don't send dummy values if there are no sensors connected.
 
Does the Adc_read function have the required acquisition time?

Mike.
 
Pommie

I didn't get what you mean, I'm not sure if the ADC_READ have that timing, it's a library in MikroC.
But how is that related to my problem ?
I think I have a problem because other ADC values are read and there are no sensors input, and I'm sending them as a packet... by USB
 
If you're getting cross talk between ADC channels then it's normally due to too short an acquisition time.

Mike.
 
Doing it right now, changing to write bare metal registers

unsigned int ADC_read_implementation(int channel){

unsigned int adval = 0;
ADCON2.B7 = 1; //results right justified
ADCON2.B0 = 0; //conversion speed = 4*Tosc
ADCON2.B1 = 0;
ADCON2.B2 = 1;
ADCON0.CHS0 = channel;
ADCON0.B0 = 1; //turn on ADC
Delay_ms(1);
ADCON0.GO_DONE = 1;
while(ADCON0.GO_DONE == 1);
adval = (ADRESH << 8) + ADRESL;
return
}
 
Pommie
When I use Delay_ms(1), the USB is not initialized, but when I use us delay it is initialzed (simulator)


Code:
unsigned int ADC_read_implementation(int channel){

    unsigned int adval = 0;
    ADCON2.B7 = 1; //results right justified
    ADCON2.B0 = 0; //conversion speed = 4*Tosc
    ADCON2.B1 = 0;
    ADCON2.B2 = 1;
    ADCON0.CHS0 = channel;
    ADCON0.B0 = 1; //turn on ADC
    Delay_us(50);
    ADCON0.GO_DONE = 1;
    while(ADCON0.GO_DONE == 1);
    adval = (ADRESH << 8) + ADRESL;
    return adval;
}

void analogo() {

     usb[0] = (char)ADC_read_implementation(1);
     usb[1] = (char)ADC_read_implementation(8);
     usb[2] = (char)ADC_read_implementation(9);


}

void main(void){

 TRISA.RA1 =1;
 TRISB.RB2=1;
 TRISB.RB3 =1;

 HID_Enable(&readbuff,&writebuff);       // Enable HID communication

 //vl6180x_configure();

  while(1){
  analogo();



  USB_Polling_Proc();
 

    writebuff[0]=usb[0];         // throttle
    writebuff[1]=usb[1];        // X axis
    writebuff[2]=usb[2];        // Y  axis
    writebuff[3]=0xFF;        //button  0xFF
    writebuff[4]=0xFF;        //button POV 0xFF



    HID_Write(&writebuff,5);
   }

}
 
Without proper comments or reading the datasheet, I've still no idea if the acquisition time is adequate. What is your acquisition time?

Mike.
 
1607438432035.png



I have used the following configuration according the data sheet

FOSC/32, 12 TAD

I still get cross talk

Code:
unsigned int ADC_read_implementation(int channel){

    unsigned int adval = 0;
    ADCON2.B7 = 1; //results right justified
    ADCON2.B0 = 0;
    ADCON2.B1 = 1;
    ADCON2.B2 = 1;
  
    ADCON2.B3 = 1;
    ADCON2.B4 = 1;
    ADCON2.B5 = 1;

    ADCON1 = 0x05;
    if ( channel == 1 )
    {
      ADCON0.CHS0 = 0x1;
      ADCON0.CHS2 = 0x0;
      ADCON0.CHS1 = 0x0;
      ADCON0.CHS3 = 0x0;
    }
    else if (channel == 8)
    {
      ADCON0.CHS0 = 0x0;
      ADCON0.CHS2 = 0x0;
      ADCON0.CHS1 = 0x0;
      ADCON0.CHS3 = 0x1;
    }
    else
    {
      ADCON0.CHS0 = 0x1;
      ADCON0.CHS2 = 0x0;
      ADCON0.CHS1 = 0x0;
      ADCON0.CHS3 = 0x1;
    }
    ADCON0.B0 = 1; //turn on ADC
    Delay_ms(10);
    ADCON0.GO_DONE = 1;
    while(ADCON0.GO_DONE == 1);
    adval = (ADRESH << 8) + ADRESL;
    return adval;
}

Crystal used is 4MHz

PIC18F2458/2553/4458/4553 Data Sheet (microchip.com)
Pommie
 
The cross talk happens on the simulator too :S

It's nothing to do with a acquisition time - it's a VERY well known and common 'problem'.

It's simply that when you change analogue channels you have to wait while the capacitor in the sample and hold charges/discharges and settles to the new value. The time this takes is heavily dependent on the source impedance - with the maximum suggested value only 2.5K or so.

So you need to add delays to give that time to occur.
 
Nigel Goodwin
I added a 1 Ms delay after each converstion, still I get cross talk between the analog channgels ; One channel reads, and other channels get read too

What made you thing 1mS is long enough? - and where exactly did you add the delay? - it needs to be after the channel switch, and before the reading. Also, what is the source impedance feeding the analogue inputs?.
 
Nigel Goodwin

I added it as you said here is the code:
Code:
unsigned int ADC_read_implementation(int channel){

    unsigned int adval = 0;
    ADCON2.B7 = 1; //results right justified
    ADCON2.B0 = 1;
    ADCON2.B1 = 0;
    ADCON2.B2 = 1;
    
    ADCON2.B3 = 1;
    ADCON2.B4 = 1;
    ADCON2.B5 = 1;

    ADCON1 = 0x05;
    if ( channel == 1 )
    {
      ADCON0.CHS0 = 0x1;
      ADCON0.CHS2 = 0x0;
      ADCON0.CHS1 = 0x0;
      ADCON0.CHS3 = 0x0;
    }
    else if (channel == 8)
    {
      ADCON0.CHS0 = 0x0;
      ADCON0.CHS2 = 0x0;
      ADCON0.CHS1 = 0x0;
      ADCON0.CHS3 = 0x1;
    }
    else
    {
      ADCON0.CHS0 = 0x1;
      ADCON0.CHS2 = 0x0;
      ADCON0.CHS1 = 0x0;
      ADCON0.CHS3 = 0x1;
    }
    Delay_us(700);
    ADCON0.B0 = 1; //turn on ADC

    ADCON0.GO_DONE = 1;
    while(ADCON0.GO_DONE == 1);
    adval = (ADRESH << 8) + ADRESL;

    return adval;
}

I'm using that sensor HALL Effect as Input

 
By adding it there you're adding the delay every time you read the ADC, including when you haven't actually changed channels - so as you're calling that routine 16 times, you're wasting 15 of the delays. You need to separate the channel selection and the reading routines, so you call the channel selection once, and the reading 16 times.

The datasheet seems pretty vague about the source impedance?. But I'd certainly try far higher delays than 1mS and see what happens.

Or you could measure the output impedance?.

Apply power and ground to the sensor, with nothing on the output - set the sensor to midway, and measure the output voltage - write it down!.

Next connect a 1K resistor between output and ground, and measure the voltage again - presumably it will be lower?. You can then use ohms law to work out the source impedance.
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top