A simple joystick (help)

General discussions about V-USB, our firmware-only implementation of a low speed USB device on Atmel's AVR microcontrollers
Post Reply
badfrogg
Posts: 2
Joined: Tue Jan 04, 2011 1:43 am

A simple joystick (help)

Post by badfrogg » Tue Jan 04, 2011 3:14 am

I am looking for some help writing the code for a basic joystick.
At this point I have built a circuit (atmega88), setup avrstudio and winavr, started a project based on the mouse example and modified the report to be a joystick with 1 analog axis and 8 buttons.
The project compiles and after uploading to the circuit it is recognized by the PC as such.

The problem I have now is that I am not an experienced programmer and I am not able to decipher the API to understand how to get the hardware to send the data to the PC.

Please see my main.c file and assume nothing about my programming knowledge. I am self taught and my understanding is very patchy and broken.

If I could get a lesson an reading the ADC and the IO of the micro and get that data to the PC it would be helpful.

Code: Select all

/* Name: main.c

*/

#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>  /* for sei() */
#include <util/delay.h>     /* for _delay_ms() */

#include <avr/pgmspace.h>   /* required by usbdrv.h */
#include "usbdrv/usbdrv.h"


/* ------------------------------------------------------------------------- */
/* ----------------------------- USB interface ----------------------------- */
/* ------------------------------------------------------------------------- */

PROGMEM char usbHidReportDescriptor[37] = { /* USB report descriptor, size must match usbconfig.h */
    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
    0x09, 0x04,                    // USAGE (Joystick)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x05, 0x09,                    //     USAGE_PAGE (Button)
    0x19, 0x01,                    //     USAGE_MINIMUM (Button 1)
    0x29, 0x08,                    //     USAGE_MAXIMUM (Button 8)
    0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //     LOGICAL_MAXIMUM (1)
    0x95, 0x08,                    //     REPORT_COUNT (8)
    0x75, 0x01,                    //     REPORT_SIZE (1)
    0x81, 0x02,                    //     INPUT (Data,Var,Abs)
    0x05, 0x01,                    //     USAGE_PAGE (Generic Desktop)
    0x09, 0x30,                    //     USAGE (X)
    0x15, 0x81,                    //     LOGICAL_MINIMUM (-127)
    0x25, 0x7f,                    //     LOGICAL_MAXIMUM (127)
    0x95, 0x01,                    //     REPORT_COUNT (1)
    0x75, 0x08,                    //     REPORT_SIZE (8)
    0x81, 0x02,                    //     INPUT (Data,Var,Abs)
    0xc0                           // END_COLLECTION
};


typedef struct
{
    uint8_t buttons;
    int8_t axis_x;
}
report_t;

static report_t reportBuffer;
static uint8_t    idleRate;


/* ------------------------------------------------------------------------- */

usbMsgLen_t usbFunctionSetup(uint8_t data[8])
{
   usbRequest_t    *rq = (void *)data;

    /* The following requests are never used. But since they are required by
     * the specification, we implement them in this example.
     */
    if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS)    /* class request type */
   {
        if(rq->bRequest == USBRQ_HID_GET_REPORT)    /* wValue: ReportType (highbyte), ReportID (lowbyte) */
      {
            /* we only have one report type, so don't look at wValue */
            usbMsgPtr = (void *)&reportBuffer;
            return sizeof(reportBuffer);
        }
      else if(rq->bRequest == USBRQ_HID_GET_IDLE)
      {
            usbMsgPtr = &idleRate;
            return 1;
        }
      else if(rq->bRequest == USBRQ_HID_SET_IDLE)
      {
            idleRate = rq->wValue.bytes[1];
        }
    }
   else
   {
        /* no vendor specific requests implemented */
    }
    return 0;   /* default for not implemented requests: return no data back to host */
}

/* ------------------------------------------------------------------------- */

int main(void)
{
   uint8_t   i;

    wdt_enable(WDTO_1S);
    /* Even if you don't use the watchdog, turn it off here. On newer devices,
     * the status of the watchdog (on/off, period) is PRESERVED OVER RESET!
     */
    /* RESET status: all port bits are inputs without pull-up.
     * That's the way we need D+ and D-. Therefore we don't need any
     * additional hardware initialization.
     */
    usbInit();
    usbDeviceDisconnect();  /* enforce re-enumeration, do this while interrupts are disabled! */
    i = 0;
    while(--i)             /* fake USB disconnect for > 250 ms */
   {
        wdt_reset();
        _delay_ms(1);
    }
    usbDeviceConnect();
    sei();
    for(;;)
   {                /* main event loop */
        wdt_reset();
        usbPoll();
        if(usbInterruptIsReady())
      {
            /* called after every poll of the interrupt endpoint */
            usbSetInterrupt((void *)&reportBuffer, sizeof(reportBuffer));
        }
    }
}

/* ------------------------------------------------------------------------- */

ulao
Rank 4
Rank 4
Posts: 481
Joined: Mon Aug 25, 2008 8:45 pm

Re: A simple joystick (help)

Post by ulao » Fri Jan 07, 2011 4:44 am

Ok lets start here.

number one, you talk to the hardware via the usb device. The hardware does not communicate with the PC per-say. So the first step is get your device to read the hardware and set the reportBuffer with the right data. If this is over the top for you, your not asking in the right place. I;d suggest AVRFreeks or something.

It looks to me like you never build the reportBuffer array with data, so there is nothing to report.

badfrogg
Posts: 2
Joined: Tue Jan 04, 2011 1:43 am

Re: A simple joystick (help)

Post by badfrogg » Sat Jan 08, 2011 1:57 am

Well yeah, I haven’t because im not really sure how.

Over the years I have tried to reach out for help on forums but I always seem to get the same kind of response, “Your not qualified to be apart of this community. Go away.”

Its not easy learning when the only person teaching you is yourself and could be mentors would rather not.

ulao
Rank 4
Rank 4
Posts: 481
Joined: Mon Aug 25, 2008 8:45 pm

Re: A simple joystick (help)

Post by ulao » Sat Jan 08, 2011 7:40 pm

Na, your just looking at it one sided. I was just like you, and I got CRAP! I was told the same thing and ridiculed left and right. Now, I'm on the other side of the fence and I get it. Add it up your self... !) Its free support + 2) its open source stuff + 3) all the info you need to know you can look up your self + 4) read the damn docs. No-one is going to help you unless your try to help yourself.

But hey I dont mind helping you out, but your way at the bottom. My advice is to start from scratch and ask as you go up, none of this here is X code what is wrong, because the answer is "too much". Your just blasting some code ( none of which your wrote ) on a form and asking whats wrong with it. In simple terms, its just lazy.

That being said, I'll retort on the above. Here is an example of one of my reports.

Code: Select all

reportBuffer[1]=0;//joystick id
reportBuffer[1]=128;//X-Axis ( main stick )
reportBuffer[2]=128;//Y-Axis
reportBuffer[3]=128;//Z-Axis
reportBuffer[4]=128;//X-rotate
reportBuffer[5]=128;//Y-rotate
reportBuffer[6]=128;//Z-rotate
reportBuffer[7]=128;//slider( right trig )
reportBuffer[8]=128;//dial ( left trig )
reportBuffer[9] =0;//buttons 1
reportBuffer[10]=0;//buttons 2

now send it.
while (!usbInterruptIsReady()) usbPoll();   usbSetInterrupt((void *)&reportBuffer);



The above is the default centered joystick and all buttons off. Keep in mind this is my report, it may not match yours. If I want to press button one I would do this:
reportBuffer[9] =0x01;
for two this : reportBuffer[9] =0x02;
Now remember this is a hex value so it's like a binary grid so to speak. This is one byte ( or 8 bits ) like so 00000000. If I want to turn on button 5 (0000x000) I would do this. reportBuffer[9] =0x10; Because 10 in hex is the 5th bit in binary.

Hope that helps. Ask anything you like, but ask it on your level so you know what your asking. None of this, why does X code not work, when you didnt even wright it ;)

I think your report would look like this, but its just a guess. ( I dont have time to figure it out for you )

reportBuffer[0]=128;//X-Axis ( main stick )
reportBuffer[1]=128;//Y-Axis
reportBuffer[2]=0;//buttons

BackWoodsBrewer
Posts: 6
Joined: Mon Dec 20, 2010 11:33 pm

Re: A simple joystick (help)

Post by BackWoodsBrewer » Sat Jan 08, 2011 9:06 pm

Hello all,

I am also interested in building a HID joystick. I really only need one potentiometer to be used. I am currently trying an old project called mjoy. I have tried several revisions of code and schematics but it appears the mjoy project has problems being recognized by different host pc's (someone even said it couldn't be recognized by any dual core processor).

Anyway, V-USB seems to be a very clean and elegant project. I don't see any existing projects making a simple HID joystick, and I am a complete noob so coding it myself is not an option (currently). I am learning all I can but if anyone has a working project of a HID joystick they could share in layman's terms I would be greatly appreciative! :D

ulao
Rank 4
Rank 4
Posts: 481
Joined: Mon Aug 25, 2008 8:45 pm

Re: A simple joystick (help)

Post by ulao » Sun Jan 09, 2011 2:08 am

Have you guys looked at the project examples page. There are at least 5 HID usb projects. This guy is IMO one of the most knowledgeable people around ( dont go spamming his in box, he wont respond ;) )

http://www.raphnet.net/electronique/electronique_en.php

He has a lot of examples. Once you guys get to the point where your interfacing with pots and switches ( aka joysticks ) report back and ask away. I have interfaced with a veterex controller. I use a atmega168 and the Analog to digital reading pins. X and Y are both pots and it works very nice. I can help you with that but my projects is 17 files so it wont help you much to have the entire thing. Here is some sample code

Code: Select all

#define ADC_VREF_TYPE 0x40
static int read_adc(unsigned char adc_input)
{
   ADMUX=adc_input|ADC_VREF_TYPE;
    _delay_us(150);
    ADCSRA|=0x40; // Start the AD conversion
    while ((ADCSRA & 0x10)==0);// Wait for complete
    ADCSRA|=0x10;
    return ADCW;
}

Code: Select all

   reportBuffer[2]= (read_adc(1)/3 + 200)*-1;//pc1
      reportBuffer[1]= (read_adc(0)/3 + 200);//pc1
Did a little math to correct the values.

BackWoodsBrewer
Posts: 6
Joined: Mon Dec 20, 2010 11:33 pm

Re: A simple joystick (help)

Post by BackWoodsBrewer » Sun Jan 09, 2011 11:51 pm

Thank you so much for the link and the advice. Us noobs can get a little overwhelmed sometimes by the abundance of different info out there. :?

I will definitely do some homework and try to limit my posts to more specific/less noobish topics :)

_frank26080115

Re: A simple joystick (help)

Post by _frank26080115 » Fri Jan 14, 2011 8:13 am


Post Reply