atmega328p + V-USB button box.

Go To Last Post
11 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have been working on making a button box but have run into a small issue I don't quite understand. Currently I am using the code from the V-USB Boxster project located here http://www.fulhack.org/boxster/index.html the only difference is I am using the 328p instead of the atmega88 as shown in the schematic. The project connects to my machine just fine and when I go to the devices list I can open it and press buttons 1 - 18 with no problem. The problem occurs when I try and use the button box with programs. Many programs/games wont pick up button 1 even though it works fine in the windows calibration screen, some games like those using source engin will pick it up, but instead of being Button 1 it picks up as POV_UP? Would someone take a look at the code and see if there is anything apparently wrong with it. Could this be an issue with the buffer on button 1?

#include 
#include 
#include 
#include "usbdrv.h"

#define BOOL	int
#define TRUE	1
#define FALSE	0

// ----------------------- Hardware I/O abstraction ------------------------ 

// Pin assignments:
// PB0	Key 1
// PB1	Key 2
// PB2	Key 3
// PB3	Key 4
// PB4	Key 5
// PB5  Key 6
// PB6  XTAL1
// PB7  XTAL2

// PC0	Key 7
// PC1	Key 8
// PC2	Key 9
// PC3	Key 10
// PC4	Key 11
// PC5	Key 12
// PC6  RESET

// PD0	USB-
// PD1	Key 13
// PD2	USB+ 
// PD3	Key 14
// PD4	Key 15
// PD5	Key 16
// PD6	Key 17
// PD7	Key 18

static void hardwareInit(void)
{
	uchar i = 0;
	uchar j = 0;

    PORTB	= 0xff;   // Activate all pull-ups 
    DDRB	= 0x00;   // All pins input 
    PORTC	= 0xff;   // Activate all pull-ups 
    DDRC	= 0x00;   // All pins input 
    PORTD	= 0xfa;   // 1111 1010 bin: activate pull-ups except on USB lines 
    DDRD	= 0x05;   // 0000 0101 bin: all pins input except USB (-> USB reset) 
	while(--j)
	{     
		// USB Reset by device only required on Watchdog Reset 
		while(--i); // Delay >10ms for USB reset 
	}
    DDRD = 0x00;    // 0000 0000 bin: remove USB reset condition 
    
	// Configure timer 0 for a rate of 16M/(1024 * 256) = 61.04 Hz (~16ms) 
    TCCR0B = 5;      // Timer0 prescaler: 1024 
}


// ------------------------------------------------------------------------- 
// ----------------------------- USB interface ----------------------------- 
// ------------------------------------------------------------------------- 
#define DATABUFSIZE 3
static uchar    reportBuffer[DATABUFSIZE];		// Buffer for HID reports 
static uchar    tempReportBuffer[DATABUFSIZE];	// Buffer for HID reports 
static uchar    idleRate;						// In 4 ms units 

// The report descriptor has been created with usb.org's "HID Descriptor Tool"
// which can be downloaded from http://www.usb.org/developers/hidpage/
PROGMEM const char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = 
{
    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
    0x09, 0x05,                    // USAGE (Game Pad)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x05, 0x09,                    //   USAGE_PAGE (Button)
    0x19, 0x00,                    //   USAGE_MINIMUM (No Buttons Pressed)
    0x29, 0x12,                    //   USAGE_MAXIMUM (Button 18)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
    0x75, 0x01,                    //   REPORT_SIZE (1)
    0x95, 0x12,                    //   REPORT_COUNT (18)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x75, 0x01,                    //   REPORT_SIZE (1)
    0x95, 0x06,                    //   REPORT_COUNT (6)
    0x81, 0x03,                    //   INPUT (Cnst,Var,Abs)
    0xc0                           // END_COLLECTION
};

static void buildReport(BOOL useTempBuffer)
{
	// Use either temp buffer or "real" buffer depending on the inparam
	uchar* bufferToUse = useTempBuffer ? tempReportBuffer : reportBuffer;
	
	// Button 1-8
	bufferToUse[0] =  ~( (PINB & 0x3f) | ((PINC & 0x03) << 6) );
		
	// Button 9-16
	bufferToUse[1] = ~( ((PINC & 0x3c) >> 2) | ((PIND & 0x02) << 3) | ((PIND & 0x38) << 2) );
	
	// Button 17-24 (but only 18 buttons available...bit 19-24 are padding only)
	bufferToUse[2] =  ~((PIND & 0xc0) >> 6);
	}

static BOOL checkForChanges()
{
	buildReport(TRUE);
	for(int i = 0; i < DATABUFSIZE; i++)
	{
		if(tempReportBuffer[i] != reportBuffer[i])
		{
			return TRUE;
		}
	}
	
	return FALSE;
}

uchar usbFunctionSetup(uchar data[8])
{
	usbRequest_t* usbReq = (usbRequest_t *) data;

    usbMsgPtr = reportBuffer;
    if((usbReq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS)
	{    
		// Class request type 
        if(usbReq->bRequest == USBRQ_HID_GET_REPORT)
		{  
			// wValue: ReportType (highbyte), ReportID (lowbyte) 
            // We only have one report type, so don't look at wValue 
            buildReport(FALSE);
            return sizeof(reportBuffer);
        }
		else if(usbReq->bRequest == USBRQ_HID_GET_IDLE)
		{
            usbMsgPtr = &idleRate;
            return 1;
        }
		else if(usbReq->bRequest == USBRQ_HID_SET_IDLE)
		{
            idleRate = usbReq->wValue.bytes[1];
        }
    }
	else
	{
        // No vendor specific requests implemented
    }
	
	return 0;
}

// ------------------------------------------------------------------------- 

int	main(void)
{
	uchar idleCounter = 0;
	BOOL  hasChanges  = FALSE;

	wdt_enable(WDTO_2S);
    hardwareInit();
	usbInit();
	sei();
	
	while(1)
	{	
		wdt_reset();
		usbPoll();
		
		hasChanges = checkForChanges();
		
        if(TIFR0 & (1<<TOV0))
		{   
			// 16 ms timer 
            TIFR0 = 1<<TOV0;
            if(idleRate != 0)
			{
                if(idleCounter > 4)
				{
                    idleCounter -= 5;   // 16 ms in units of 4 ms 
                }
				else
				{
                    idleCounter = idleRate;
                    hasChanges = TRUE;
                }
            }
        }
		
        if(usbInterruptIsReady() && hasChanges)
		{
			hasChanges = FALSE;
            buildReport(FALSE);
            usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
        }
	}
	
	return 0;
}

I have tried shifting the buttons up one as suggested in the original projects source, it does fix the first button but messes up most of the rest.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

found this site http://www.roroid.ro/wiki/pmwiki.php/Main/DebouncingButtonsOnVirtualPorts that gives a little bit of an explanation of virtual ports about half way down, will do some more reading and see if I can figure this out, From what I am reading it may be more an issue with the ports created in the buffer section just inside buildReport.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Welcome to AVRFreaks!

codiahw wrote:
Would someone take a look at the code and see if there is anything apparently wrong with it.
This is just a guess, and I'm no expert on USB HID Report Descriptors, but I'm suspicious of the one used in that project. In particular, this line:

0x19, 0x00,                    //   USAGE_MINIMUM (No Buttons Pressed)

One of my uses of V-USB is to emulate a 12-button joystick (not a gamepad, like you). I've been using this entry with total success:

0x19, 0x01,                    //   USAGE_MINIMUM (Button 1)

You might want to give that a try. I'll keep my fingers crossed. :) Please let us know if that works or not.

P.S. The site at that URL you listed in your 2nd post seems to be dead or down.

Regards,
Bill

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Bill,
Thanks for the welcome, woke up this morning' with some new energy to take a crack at my project after fussing with it last night. The URL in my second post seems to be back online if it was down earlier. It is a Romanian domain so that may have something to do with your connection to it.

:arrow: As for your suggestion on changing the HID Report Descriptors you were spot on, I must have looked over that 20 times without that ever having dawned on me, switched it to 0x01 and my project is now working flawlessly. Looks like I have some more reading to do on HID Descriptors. At least I was able to learn a bit more about bit-shifting in the process.

Once more, thanks :D. Glad I found this site, looking forward to becoming an active member of these forums.

PS: from what I have learned about bit-shifting, I think this problem could have been solved by shifting the report buffer in a more accurate way, understandable this would not be an ideal way to fix it, but as an exercise in programming for AVR I think I may give it a try just to see the outcome, Let you know what happens when I get around to doing that. For now I'm going to finish hardware side of this project.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

codiahw wrote:
The URL in my second post seems to be back online if it was down earlier. It is a Romanian domain so that may have something to do with your connection to it.
Just FYI... A link to a popular AVR C compiler (CodeVisionAVR) with a Romanian domain is working fine for me, but that URL from your 2nd post is still a zombie for me.

codiahw wrote:
As for your suggestion on changing the HID Report Descriptors you were spot on, [...]
Excellent -- very glad to hear you got it working!

If you haven't already done so, I'd humbly suggest that you drop a quick email to the Boxster project's author, maybe pointing him to this thread, so that he can fix the issue "upstream".

codiahw wrote:
[...] looking forward to becoming an active member of these forums.
Happy to have you here!

codiahw wrote:
PS: from what I have learned about bit-shifting, I think this problem could have been solved by shifting the report buffer in a more accurate way, understandable this would not be an ideal way to fix it, but as an exercise in programming for AVR I think I may give it a try just to see the outcome, Let you know what happens when I get around to doing that.
Sounds good. (To be completely honest, other than reading the comment in the original project's code, I didn't really look too deeply at his bit-shifting code.)

Regards,
Bill

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

- Sent e-mail to Boxster project author, who had a read over of your suggested fix and said thanks.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Now I'm officially confused. :? I thought that when you said that my suggestion worked, that it did so without the need for any bit-shifting of the "buttons pressed" bytes in the USB report buffer. Did I misunderstand?

I'm asking because the Boxster project author, Olof Holmgren, has released a new (untested) version of his code with no sign of my recommended change but with changes to fix his broken bit-shifting "quick fix" code.

I don't have time at the moment to test this "Usage Minimum of 0 or 1" theory on a V-USB project of my own, but I would expect that if he used my suggested change, no bit-shifting at all would be needed. Am I missing something?

Sorry to be so persistent on this, but since my 1st post in this thread, I noticed that his Boxster project is listed on the official V-USB 'HID Projects' page, so I feel it's important to get this correct so that a possibly broken or hackish solution isn't propagated.

Regards,
Bill

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

TL;DR: Don't use a 'Usage Minimum' field of 0 in the USB HID Report Descriptor -- use 1! No bit-shifting is needed.

Having gotten no reply to my last post, I decided to look into this a bit more deeply now that I have a minute to do so.

Background: When emulating joysticks (and, apparently, gamepads), the USB HID Report Descriptor is configured with 'Usage Minimum' and 'Usage Maximum' values. For years now, I've successfully used 1 for 'Usage Minimum' and, as one might expect, a value for 'Usage Maximum' that matches the total number of joystick buttons on the emulated HID joystick.

I just modified the firmware of the MCU on a PCB of one of my V-USB projects to act like a 12-button joystick. As always, I used a 'Usage Minimum' field of '1'. I then tested buttons 1-3 under Linux and all worked as expected. I then moved the device to a WinXP PC and again all worked as expected.

Note: Under Windows, I did all the testing under the 'Control Panel', 'Game Controllers', 'Properties' sheet (using the graphical button indications on the 'Test' tab) and also under Microsoft's 'Combat Flight Simulator'.

Next, I changed the 'Usage Minimum' from 1 to 0, to mimic what the Boxster project was (and still is) doing. Testing under Linux shows problems immediately:

  • Physical joystick button #1 is now reporting as #13 (1 more than the total number of joystick buttons being emulated)
  • Physical joystick button #2 is now reporting as #1
  • Physical joystick button #3 is now reporting as #2
Under WinXP's 'Game Controllers' 'Test' screen (sometimes referred to as the "calibration screen", as the OP did), I see that everything appears to be normal. In other words, physical buttons 1-3 are reported as such. This matches what OP 'codiahw' reported in his initial post.

But when I run Microsoft's Combat Flight Simulator, with joystick buttons 1-3 configured to various simulator actions, I can see that things are not right. More specifically, physical joystick button #1 does nothing (not even an action assigned as button #13, thinking of how Linux saw that button). And physical joystick button 'n' (for 'n' greater than 1) are all seen in Combat Flight Simulator as joystick button 'n - 1'.

This explains the shift-by-one code done in the Boxster firmware. It's essentially an attempt to work around the problem.

The logical conclusion of my testing is this: As long as you use a 'Usage Minimum' value in the USB HID Report Descriptor of '1', there is no need to bit-shift anything in the firmware.

Although my testing was done by emulating a 12-button joystick and the Boxster project emulates an 18-button gamepad, I strongly suspect the issue would be identical.

To help close the loop, I've sent an email to the Boxster project author pointing him to this post so that he can hopefully update his project's source code accordingly.

That is all. Now back to your regularly scheduled programming (no pun intended!).... :)

Regards,
Bill

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just to completely close the loop on this....

I got a very nice email reply from the Boxster project's author (Olof Holmgren) and he's already issued updates to implement my suggestion to the Boxster project (and another V-USB project of his called 'Retro Adapter' that used a similar bit-shift work-around). He temporarily lacks access to his hardware so he's been unable to test the fix, but we're confident that it will work as expected.

Thanks, Olof!

Regards,
Bill

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry for the slow response, been busy with the holidays. But you were correct the first time, I used the descriptor fix you suggested and completely removed the bit shift fix and my project is working perfectly. The e-mail I received back from Olof did state that he would fix the bit shift first and then look into the descriptor fix later when he had more time. But by now you have figured that out.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No problem on the delayed response, 'codiahw'. I figured you either had email notification disabled or, like me, it's enabled but never works, so I simply "took the bull by the horns".

Thanks for clarifying your situation. Based on my tests, I'd been assuming that my initial assumption was correct, if that makes any sense. :) But it's good to have the loop truly and fully closed now.

Regards,
Bill