Teensy 2.0 12 axis joystick/gamepad

Status
Not open for further replies.

Dran

Member
Hello! I'd like to ask the cunning people of the teensy forum if the following idea is feasible. I'd like to make a 12(x10bit) axis joystick/gamepad with the help of teensy 2.0. More specifically I want to "translate" a radio controller to a USB device. First I was quite happy to find the many axis joystick thread, but I soon found out that it wouldn't work with my teensy 2.0. Then after some time I found a post by Les "Pointy", which describes the making of a custom teensy++ 2.0 joystick. I assume the same could be applied to teensy 2.0 (I wanted to post a question in the comments of that post, but the button was "greyed out" even though I filled in all the fields).

I'm new to things like micro controllers and programming, and feel like I might be out of my depth, which is why I'd like to ask the forum members if this project is feasible and if I have understood the principles correctly.


I'd feel somewhat rude to just refer you to the post (but I still recommend the original source, of course), which is why I'll attempt a quick summary and hope I don't get things to mixed up. Les post describes that in order to create your custom joystick you need to edit boards.txt in ‘arduino install folder\hardware\teensy‘ by adding following lines (I suppose for teensy 2.0, one would place and name these lines accordingly ("teensy2.menu.usb...")):

teensypp2.menu.usb.gamepad.name=Gamepad Controller
teensypp2.menu.usb.gamepad.build.define0=-DUSB_GAMEPAD
teensypp2.menu.usb.gamepad.fake_serial=teensy_gateway

Thereafter one needs to add the correct inclusions in the file "core_id.h", "usb.c", "usb_api.cpp", "usb_api.h", "usb_private.h", in ‘arduino install folder\hardware\teensy\cores\teensy’ by adding following lines:
#elif defined(USB_GAMEPAD)
#include "../usb_gamepad/[name of the file you are editing at the moment]"

Then one should make a folder in the ‘arduino install folder\hardware\teensy\cores‘ directory and name the folder 'usb_gamepad'. Inside that folder one should put the files provided in the post by Les "Pointy" (usb_private.h, usb_api.cpp, usb.c, usb_api-h, core_id.h). The last step is to edit the provided sketch code, if needed, and upload it to the teensy.

Then Pointy explains that if you want to customize it further you should edit "gamepad_report_data" and "GAMEPAD_SIZE" in "usb_private.h", as well as "gamepad_report_data" in "usb_api.h" if you need more than 56 bits for the packet. In my example, with 12 10 bit axis, I assume I need then 120 bits. Thefore I change usb_private.h to "#define GAMEPAD_SIZE 13", and "gamepad_report_data[12]", and also "gamepad_report_data[12]" in usb_api.h. For clarity, the "13" in "#define GAMEPAD_SIZE 13" comes from the fact that the value is set to 8 in the original code, which is 1 more than the 7 bytes required by the gamepad in the example. Therefore I'd like to ask why it is the case, and of course to be corrected if the value of GAMEPAD_SIZE should not simply be one more than the amount of bytes.

Next step would be to edit the HID descriptor in usb.c. Since I want to add several axis, I assume I should add the Z, Zrotate, and several sliders. This would mean that the descriptor should also contain
USAGE (Z) 09 32
USAGE (Rz) 09 35
USAGE (Slider) 09 36 (this repeated 6 times)
And the REPORT_COUNT should be increased to 12.

Now I wonder if the sliders somehow need to get specific names in the descriptor (like Slider1, Slider2, etc).

Thereafter I'd need to edit the code 'usb_api.h' to handle the bites and bytes from right to left, to send the data. And I suppose, since I don't need the buttons, I should remove that part of the code.

Lastly I'd have to change the Sketch accordingly to map the analog inputs to the different axis/sliders.

Is what I want to achieve possible with the specified hardware? Have I understood the described parts of the code correctly? Where have I made the obvious mistakes and where do you see the pitfalls? I'm very thankful for any input! And if "Pointy" sees this post, I'd like to thank you for your blog post. I couldn't send a comment on the blog though.

/Dran
 
This code exists for Teensy LC, 3.2, 3.5, 3.6 and 4.0. You just edit usb_desc.h and change the line for 64 byte report size. The rest of the code checks for report size and switches to a joystick with a huge number of axes and buttons.

Your path of least resistance would be to just buy one of those newer boards and simply use the published code. Teensy LC is very affordable. :)

With enough time and trouble, it probably could be ported back to the old 8 bit boards. I have no plans to ever works on that, but you can if you like. Hopefully having the code for the newer boards as a reference can help you with some of the details. The rest are on you...

One gotcha is the PC software support. Last time I checked (admittedly years ago) the default drivers on Windows would support only the first 8 axes, no matter how many the device had. On MacOS, the situation seemed better, but one nice piece of software I found for testing joysticks would not recognize it, even though MacOS showed it as a USB device in System Profiler. On Linux, "jstest" works fine with a huge number of axes.
 
Thanks for the reply Paul :)! You are right, the Teensy LC is quite affordable (and offers nice features). Though suppliers here are out of stock (and have been for quite some time) or charging quite more than PJRC, and buying from abroad will make the customs charge me a fee that makes it quite less affordable. I got the Teensy 2.0 from a friend who had a spare one (they are also difficult to get). I'll make sure to check out the code for the newer boards! I'm planning to use this primarily with linux. My ambitions, at the moment, are not to make the whole extreme joystick code backwards compatible, but to, only add a few more axis. I'll report if I have any success, and of course, if any other "gotchas" come tom mind, I'd be happy to know! :)
 
As expected, I've run into some difficulties. The code compiles and runs. The windows gamepad configurator shows the controller, though, as Paul mentioned, only 8 of the 12 axis. But all the axis are "dead centered" and don't respond to my movements. Therefore I suspect that I have a mistake in how I send the data (Everything runs as expected when running the default joystick code, or Pointy's gamepad code).

I decided to leave the 11 buttons from Pointy's code in there, and ad 8 axis to the previous 4, to a total of 12. This should give me total 17 bytes of data (2 for the buttons and 15 for the 12 axis, 10 bit each (12*10/8).

Edits to usb_private.h. I changed the gamepad_report_data[17] to 17 (as in amount of bytes). I changed GAMEPAD_SIZE to 18. Why 18? I don't know. In Pointy's code it's 8, which is one more than the amount of bytes that contain the gamepad data (7). Therefore I also made my GAMEPAD_SIZE 1 larger than the amount of bytes I calculated. Is this incorrect? Does this matter? Should I redefine anything else, for example "#define ENDPOINT0_SIZE"?
Code:
#ifndef usb_serial_h__
#define usb_serial_h__

#include <stdint.h>

#ifdef __cplusplus
extern "C"{
#endif

#define VENDOR_ID               0x16C0
#define PRODUCT_ID              0x0488
#define TRANSMIT_FLUSH_TIMEOUT  4   /* in milliseconds */
#define TRANSMIT_TIMEOUT        25   /* in milliseconds */

#define STR_PRODUCT             L"Pointy's Gamepad"
#define ENDPOINT0_SIZE          64

#define GAMEPAD_INTERFACE	0
#define GAMEPAD_ENDPOINT	1
#define GAMEPAD_SIZE		18
#define GAMEPAD_BUFFER		EP_DOUBLE_BUFFER
#define GAMEPAD_INTERVAL	1

#define NUM_ENDPOINTS		2
#define NUM_INTERFACE		1

// setup
void usb_init(void);			// initialize everything
void usb_shutdown(void);		// shut off USB

// variables
extern volatile uint8_t usb_configuration;
extern volatile uint8_t usb_suspended;
// this holds the actual usb data sent from the controller to the pc
extern uint8_t gamepad_report_data[17];

#ifdef __cplusplus
} // extern "C"
#endif
#endif

Edits to usb_api.cpp. I added additional rows of UEADTX from 0 to 16, for all the 17 bytes that I'm sending. Should I change anything else? Should I for example change the UEINTX = 0x3A , which is numerically equal to 56, to 0x88, which is equal to 136 (the number of bits in my 17 bytes).
Code:
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <stdint.h>
#include "usb_common.h"
#include "usb_private.h"
#include "usb_api.h"
#include "wiring.h"

void usb_gamepad_class::send_now(void)
{
        uint8_t intr_state, timeout;

        if (!usb_configuration) return;
        intr_state = SREG;
        cli();
        UENUM = GAMEPAD_ENDPOINT;
        timeout = UDFNUML + 50;
        while (1) {
                // are we ready to transmit?
                if (UEINTX & (1<<RWAL)) break;
                SREG = intr_state;
                // has the USB gone offline?
                if (!usb_configuration) return;
                // have we waited too long?
                if (UDFNUML == timeout) return;
                // get ready to try checking again
                intr_state = SREG;
                cli();
                UENUM = GAMEPAD_ENDPOINT;
        }
        UEDATX = gamepad_report_data[0];
        UEDATX = gamepad_report_data[1];
        UEDATX = gamepad_report_data[2];
        UEDATX = gamepad_report_data[3];
        UEDATX = gamepad_report_data[4];
        UEDATX = gamepad_report_data[5];
        UEDATX = gamepad_report_data[6];
        UEDATX = gamepad_report_data[7];
        UEDATX = gamepad_report_data[8];
        UEDATX = gamepad_report_data[9];
        UEDATX = gamepad_report_data[10];
        UEDATX = gamepad_report_data[11];
        UEDATX = gamepad_report_data[12];
        UEDATX = gamepad_report_data[13];
        UEDATX = gamepad_report_data[14];
        UEDATX = gamepad_report_data[15];
        UEDATX = gamepad_report_data[16];
        UEINTX = 0x3A;
        SREG = intr_state;
}

// Preinstantiate Objects //////////////////////////////////////////////////////
usb_gamepad_class	Gamepad = usb_gamepad_class();

In usb.c i edited the USB descriptor to add the Z, Rz axis and 6 sliders, and raised the report count to 12 (the bittons have a separate report count). DO I need to change the "#define CONFIG1_DESC_SIZE ( 9 + 9+9+7 )" or "#define GAMEPAD_HID_DESC_OFFSET ( 9 + 9 )"? I additionally changed the usb_init. I'm really quite unsure what if I should changing something and to what. I added additional rows to the gamepad_report_data and gave almost all of them a value of 0, but the final ones got the same values as in Pointy's code. Quite arbitrary of me, but it was a final attempt before ending for today. What do these hexadecimal values represent? Do I need to change this to make it work?
Code:
	0x09, 0x30,				// USAGE (X)
	0x09, 0x31,				// USAGE (Y)
	0x09, 0x32,                    		// USAGE (Z)
	0x09, 0x33,				// USAGE (Rx)
	0x09, 0x34,				// USAGE (Ry)
	0x09, 0x35,                    		// USAGE (Rz)
	0x09, 0x36,                    		// USAGE (Slider)
	0x09, 0x36,                    		// USAGE (Slider)
	0x09, 0x36,                    		// USAGE (Slider)
	0x09, 0x36,                    		// USAGE (Slider)
	0x09, 0x36,                    		// USAGE (Slider)
	0x09, 0x36,                    		// USAGE (Slider)
	0x75, 0x0A,				// REPORT_SIZE (10)
	0x95, 0x0C,				// REPORT_COUNT (12)
Code:
// initialize USB serial
void usb_init(void)
{
	uint8_t u;

	u = USBCON;
	if ((u & (1<<USBE)) && !(u & (1<<FRZCLK))) return;
	HW_CONFIG();
        USB_FREEZE();				// enable USB
        PLL_CONFIG();				// config PLL
        while (!(PLLCSR & (1<<PLOCK))) ;	// wait for PLL lock
        USB_CONFIG();				// start USB clock
        UDCON = 0;				// enable attach resistor
	usb_configuration = 0;
	usb_suspended = 0;
	gamepad_report_data[0] = 0;
	gamepad_report_data[1] = 0;
	gamepad_report_data[2] = 0;
	gamepad_report_data[3] = 0;
	gamepad_report_data[4] = 0;
	gamepad_report_data[5] = 0;
	gamepad_report_data[6] = 0;
	gamepad_report_data[7] = 0;
	gamepad_report_data[8] = 0;
	gamepad_report_data[9] = 0;
	gamepad_report_data[10] = 0;
	gamepad_report_data[11] = 0;
	gamepad_report_data[12] = 0;
	gamepad_report_data[13] = 0;
	gamepad_report_data[14] = 0x0F;
	gamepad_report_data[15] = 0x20;
	gamepad_report_data[16] = 0x80;
	UDINT = 0;
        UDIEN = (1<<EORSTE)|(1<<SOFE);
	//sei();  // init() in wiring.c does this
}

void usb_shutdown(void)
{
	UDIEN = 0;		// disable interrupts
	UDCON = 1;		// disconnect attach resistor
	USBCON = 0;		// shut off USB periperal
	PLLCSR = 0;		// shut off PLL
	usb_configuration = 0;
	usb_suspended = 1;
}

In usb_api.h I made my attempt to organize the data to send. I have to admit that I don't fully understand what I'm supposed to do, which is why I imitated the pattern. From Pointy's nice blog post I understand what we want to achieve. From the nice provided illustration I understand what the goal is, and I understand what the end goal is. The problem is that I don't understand how the data looks before we start to move the bits between bytes, which is why I'm unsure on where to move it. I also raised the gamepad_report_data to 17.

usb-data.png
Code:
#ifndef USBserial_h_
#define USBserial_h_

#include <inttypes.h>

#include "keylayouts.h"
#include "Print.h"
#include "Stream.h"

extern uint8_t gamepad_report_data[17];

class usb_gamepad_class
{
	public:
	usb_gamepad_class() { manual_mode = 0; }
	inline void button(uint8_t button, bool val) {
		button--;
		uint8_t mask = (1 << (button & 7)); // create button mask
		if (val)
		{
			// set bit with logical or
			if (button < 8) gamepad_report_data[0] |= mask; // buttons 0 to 7
			else if (button < 16) gamepad_report_data[1] |= mask; // buttons 8 - 10
		}
		else
		{
			// reset bit with  logical and
			mask = ~mask; // invert button mask
			if (button < 8) gamepad_report_data[0] &= mask; // buttons 0 to 7
			else if (button < 16) gamepad_report_data[1] &= mask; // buttons 8 to 10
		}
		if (!manual_mode) send_now();
	}
	inline void X(uint16_t val) {
		if (val > 1023) val = 1023;
		gamepad_report_data[2] = val; 
		gamepad_report_data[3] = (gamepad_report_data[3] & 0xFC) | (val >> 8); 
		if (!manual_mode) send_now();
	}
	inline void Y(uint16_t val) {
		if (val > 1023) val = 1023;
		gamepad_report_data[3] = (gamepad_report_data[3] & 0x3F) | (val << 2); 
		gamepad_report_data[4] = (gamepad_report_data[4] & 0xF0) | (val >> 6); 
		if (!manual_mode) send_now();
	}
	inline void Z(uint16_t val) {
		gamepad_report_data[4] = (gamepad_report_data[4] & 0x0F) | (val << 4); 
		gamepad_report_data[5] = (gamepad_report_data[5] & 0xC0) | (val >> 4); 
			if (!manual_mode) send_now();
	}
	inline void RX(uint16_t val) {
		if (val > 1023) val = 1023;
		gamepad_report_data[5] = (gamepad_report_data[5] & 0x3F ) | (val << 8); 
		gamepad_report_data[6] =   (val >> 2); 
		if (!manual_mode) send_now();
	}
// 4 additional axis
	inline void RY(uint16_t val) {
		if (val > 1023) val = 1023;
		gamepad_report_data[7] = val; 
		gamepad_report_data[8] = (gamepad_report_data[8] & 0xFC) | (val >> 8); 
		if (!manual_mode) send_now();
	}
	inline void RZ(uint16_t val) {
		if (val > 1023) val = 1023;
		gamepad_report_data[8] = (gamepad_report_data[8] & 0x3F) | (val << 2); 
		gamepad_report_data[9] = (gamepad_report_data[9] & 0xF0) | (val >> 6);
		if (!manual_mode) send_now();
	}
	inline void SLIDER1(uint16_t val) {
		gamepad_report_data[9] = (gamepad_report_data[9] & 0x0F) | (val << 4); 
		gamepad_report_data[10] = (gamepad_report_data[10] & 0xC0) | (val >> 4); 
			if (!manual_mode) send_now();
	}
	inline void SLIDER2(uint16_t val) {
		if (val > 1023) val = 1023;
		gamepad_report_data[10] = (gamepad_report_data[10] & 0x3F ) | (val << 8); 
		gamepad_report_data[11] =   (val >> 2); 
		if (!manual_mode) send_now();
	}

// 4 axis more
	inline void SLIDER3(uint16_t val) {
		if (val > 1023) val = 1023;
		gamepad_report_data[12] = val; 
		gamepad_report_data[13] = (gamepad_report_data[13] & 0xFC) | (val >> 8);
		if (!manual_mode) send_now();
	}
	inline void SLIDER4(uint16_t val) {
		if (val > 1023) val = 1023;
		gamepad_report_data[13] = (gamepad_report_data[13] & 0x3F) | (val << 2); 
		gamepad_report_data[14] = (gamepad_report_data[14] & 0xF0) | (val >> 6); 
		if (!manual_mode) send_now();
	}
	inline void SLIDER5(uint16_t val) {
		gamepad_report_data[14] = (gamepad_report_data[14] & 0x0F) | (val << 4); 
		gamepad_report_data[15] = (gamepad_report_data[15] & 0xC0) | (val >> 4); 
			if (!manual_mode) send_now();
	}
	inline void SLIDER6(uint16_t val) {
		if (val > 1023) val = 1023;
		gamepad_report_data[15] = (gamepad_report_data[15] & 0x3F ) | (val << 8); 
		gamepad_report_data[16] =   (val >> 2); 
		if (!manual_mode) send_now();
	}

	inline void useManualSend(bool mode) {
		manual_mode = mode;
	}
	
	void send_now(void);
	
	private:
	uint8_t manual_mode;
};

extern usb_gamepad_class Gamepad;

#endif

Finally in the Sketch File I'm just adding the additional axis to output their analog input.
Code:
/*
 
Simple Game Controller Code
For use with the Teensy++ 2.0 and MMA7361 Accelerometer
 
Version 1.00
 
(C)Pointy 2014
 
The code expects the following...
 
11 buttons wired between gnd and the Teens++ 2.0 pins 0-5 & 7-11
2 voltages on pins A0-A1 to represent the joystick X,Y position.
 
The MMA7361 is wired as follows...
 
VCC - 3.3V
GND - AGND
ZOUT - (Not used)
YOUT - A3 (RY Axis)
XOUT - A2 (RX Axis)
SLP - Tied High
 
*/
 
int ledPin = 6;
boolean ledOn = false;
 
void setup() {
 // set pin modes
 for(int i=0; i <13; i++){
 // ignore pin 6
 if (i != 6)
 pinMode(i,INPUT_PULLUP);
 }
 pinMode(ledPin, OUTPUT);
 // set manual send
 Gamepad.useManualSend(true);
 // set led off
 digitalWrite(ledPin,LOW);
}
 
void loop() {
 // MMA7361 doesn't output full range to we need to tweak values
 // read rx analog value
 int rx = analogRead(2);
 // double range
 rx = (rx - 511) * 2 + 511;
 // cap result
 if (rx > 1023)
 rx=1023;
 if (rx < 0)
 rx = 0;
 // invert rx
 rx=abs(1023-rx);
 // read rY analog value
 int ry = analogRead(3);
 // double range
 ry = (ry - 511) * 2 + 511;
 // cap result
 if (ry > 1023)
 ry=1023;
 if (ry < 0)
 ry = 0;
 
 // read analog inputs for x & y axis
 Gamepad.X(analogRead(0));
 Gamepad.Y(analogRead(1));
 Gamepad.RX(2);
 Gamepad.RY(3);
 Gamepad.Z(analogRead(4));
 Gamepad.RZ(analogRead(5));
 Gamepad.SLIDER1(analogRead(6));
 Gamepad.SLIDER2(analogRead(7));
 Gamepad.SLIDER3(analogRead(8));
 Gamepad.SLIDER4(analogRead(9));
 Gamepad.SLIDER5(analogRead(10));
 Gamepad.SLIDER6(analogRead(11));
 // read the digital inputs and set the buttons
 for(int i=0; i <12; i++){
 // buttons are 1 to 11, digital pins are 0 to 11 ignoring pin 6
 if (i <= 6)
 Gamepad.button(i+1, !digitalRead(i)); // 1st 6 buttons
 else
 Gamepad.button(i, !digitalRead(i));// last 5 buttons
 }
 
 // a brief delay, so this runs 100 times per second
 delay(10);
 
 Gamepad.send_now();
 
 // toggle our led
 ledOn = !ledOn;
 digitalWrite(ledPin, ledOn);
}

I'd be very grateful for any help at all to make this work! :D
 
Hi Dran,

As I said in my message, I haven't touched this in years, but I will try to help if I can.

As expected, I've run into some difficulties. The code compiles and runs. The windows gamepad configurator shows the controller, though, as Paul mentioned, only 8 of the 12 axis. But all the axis are "dead centered" and don't respond to my movements. Therefore I suspect that I have a mistake in how I send the data (Everything runs as expected when running the default joystick code, or Pointy's gamepad code).

If my original code works as expected, then at least you have a good starting point. I found the USB spec to be quite complicated and remember doing a lot of reading up on the subject, including reading some of the official documentation. I then spent even more time actually getting the code to work, and now my aging brain has forgotten it all, to make way for more useless info that i will probably forget next week. :rolleyes:

This morning , over my morning coffee, I did look over my original post, the code I posted and the code/comments you posted here. The one thing I would say straight away if you are new to this, is to take small baby steps. If the original code is working, then maybe try adding one more axis and see if you can get that working first.

Edits to usb_private.h. I changed the gamepad_report_data[17] to 17 (as in amount of bytes). I changed GAMEPAD_SIZE to 18. Why 18? I don't know. In Pointy's code it's 8, which is one more than the amount of bytes that contain the gamepad data (7). Therefore I also made my GAMEPAD_SIZE 1 larger than the amount of bytes I calculated. Is this incorrect?

I am really not sure on this, but maybe it needs to be multiples of 8 or a power of two. So you try 24 or 32. You could also try changing my original code to 7 and see if it still works, it may be completely irrelevant or even a typo.

In usb.c i edited the USB descriptor to add the Z, Rz axis and 6 sliders, and raised the report count to 12 (the bittons have a separate report count). DO I need to change the "#define CONFIG1_DESC_SIZE ( 9 + 9+9+7 )" or "#define GAMEPAD_HID_DESC_OFFSET ( 9 + 9 )"? I additionally changed the usb_init. I'm really quite unsure what if I should changing something and to what. I added additional rows to the gamepad_report_data and gave almost all of them a value of 0, but the final ones got the same values as in Pointy's code. Quite arbitrary of me, but it was a final attempt before ending for today. What do these hexadecimal values represent? Do I need to change this to make it work?

I don't think you need to change the CONFIG1_DESC_SIZE or GAMEPAD_HID_DESC_OFFSET as the config1_descriptor does not need changing. (The 9+9+9+7 are the blengths of each descriptor to give the total length and the hid descriptor is the 3rd one which is offset 9+9). As for the values in usb_init, honestly I have no clue, other than maybe I was setting default values to test something with the axes. I don't think these are relevant, again you change them to 0 in the original code and see if it still works.

In usb_api.h I made my attempt to organize the data to send. I have to admit that I don't fully understand what I'm supposed to do, which is why I imitated the pattern. From Pointy's nice blog post I understand what we want to achieve. From the nice provided illustration I understand what the goal is, and I understand what the end goal is. The problem is that I don't understand how the data looks before we start to move the bits between bytes, which is why I'm unsure on where to move it. I also raised the gamepad_report_data to 17.

The usb_gamepad_class looks fine to me and to be honest if this part was incorrect I would expect that the data would be jumbled and that moving an axis would result in an axis or axes moving, just not the correct one{s} or position.

Finally in the sketch you can send some debug values to see if this is the problem or if it is the descriptor/other usb code. (The code looks wrong for RX & RY, you are setting the values to 2 & 3 rather than reading an analog input, which means that I think the RX/RY axes would either far left/right or top/bottom, I think the range is 0 - 1023 with 511 being in the center, I just can't remember which is up/down or left/.right)

If I get more time I will try and find a Teensy2++ and have a play.

Good luck,

Les
 
Hi Dran,

As I said in my message, I haven't touched this in years, but I will try to help if I can.

If my original code works as expected, then at least you have a good starting point. I found the USB spec to be quite complicated and remember doing a lot of reading up on the subject, including reading some of the official documentation. I then spent even more time actually getting the code to work, and now my aging brain has forgotten it all, to make way for more useless info that i will probably forget next week. :rolleyes:

This morning , over my morning coffee, I did look over my original post, the code I posted and the code/comments you posted here. The one thing I would say straight away if you are new to this, is to take small baby steps. If the original code is working, then maybe try adding one more axis and see if you can get that working first.

I am really not sure on this, but maybe it needs to be multiples of 8 or a power of two. So you try 24 or 32. You could also try changing my original code to 7 and see if it still works, it may be completely irrelevant or even a typo.

I don't think you need to change the CONFIG1_DESC_SIZE or GAMEPAD_HID_DESC_OFFSET as the config1_descriptor does not need changing. (The 9+9+9+7 are the blengths of each descriptor to give the total length and the hid descriptor is the 3rd one which is offset 9+9). As for the values in usb_init, honestly I have no clue, other than maybe I was setting default values to test something with the axes. I don't think these are relevant, again you change them to 0 in the original code and see if it still works.

The usb_gamepad_class looks fine to me and to be honest if this part was incorrect I would expect that the data would be jumbled and that moving an axis would result in an axis or axes moving, just not the correct one{s} or position.

Finally in the sketch you can send some debug values to see if this is the problem or if it is the descriptor/other usb code. (The code looks wrong for RX & RY, you are setting the values to 2 & 3 rather than reading an analog input, which means that I think the RX/RY axes would either far left/right or top/bottom, I think the range is 0 - 1023 with 511 being in the center, I just can't remember which is up/down or left/.right)

If I get more time I will try and find a Teensy2++ and have a play.

Good luck,

Les
Many thanks for the reply Les! You are certainly right about the baby steps. Feel like I dove in at the deep end of the pool a little bit early. :) Good ideas for troubleshooting! I'll try them out and post any findings! Thanks again! :D
 
I am really not sure on this, but maybe it needs to be multiples of 8 or a power of two. So you try 24 or 32. You could also try changing my original code to 7 and see if it still works, it may be completely irrelevant or even a typo.
It works even if i set the value to 7, and also if I set it to a number above 7, but not below 7.
As for the values in usb_init, honestly I have no clue, other than maybe I was setting default values to test something with the axes. I don't think these are relevant, again you change them to 0 in the original code and see if it still works
Seems that you are right about that. These rows can be removed, and will work still.

In the usb_api.cpp, the amount of rows with UEDATX = gamepad_report_data[N]; seem to matter. If I remove or add a row in the original code, the gamepad shows up in windows with all axis, but they don't respond to input. So it seems that the amount of these rows must be equal to the amount of bytes one is sending.

Still, I can't get it to work. Either I have specified some of these things incorrectly, or there is something else that needs to be specified. I was thinking about how to do this incrementally, but the difficulty is that one needs an elegant solution for the moving of bits in to bytes in the usb_api.h file. By adding a multiple of 4 axis, I can "simplify" editing the usb_api.h file, since I can follow the same pattern as for the previous axis.
 
It works even if i set the value to 7, and also if I set it to a number above 7, but not below 7.

Seems that you are right about that. These rows can be removed, and will work still.

In the usb_api.cpp, the amount of rows with UEDATX = gamepad_report_data[N]; seem to matter. If I remove or add a row in the original code, the gamepad shows up in windows with all axis, but they don't respond to input. So it seems that the amount of these rows must be equal to the amount of bytes one is sending.

Still, I can't get it to work. Either I have specified some of these things incorrectly, or there is something else that needs to be specified. I was thinking about how to do this incrementally, but the difficulty is that one needs an elegant solution for the moving of bits in to bytes in the usb_api.h file. By adding a multiple of 4 axis, I can "simplify" editing the usb_api.h file, since I can follow the same pattern as for the previous axis.

I am not sure what to suggest to be honest. Did you try sending zeros or 1023 in the sketch, which should deflect the axis fully one way or the other? Do the buttons work? I would have thought if the USB descriptor was incorrect that either the device would not be recognized or would not show the correct axis/buttons. Unfortunately I don't really have time at the moment to dig out my Teensy 2 and have a play myself.

Where do you live?

Regards,

Les
 
I am not sure what to suggest to be honest. Did you try sending zeros or 1023 in the sketch, which should deflect the axis fully one way or the other? Do the buttons work? I would have thought if the USB descriptor was incorrect that either the device would not be recognized or would not show the correct axis/buttons. Unfortunately I don't really have time at the moment to dig out my Teensy 2 and have a play myself.

Where do you live?

Regards,

Les

I haven't tried the buttons, but I tried to send zeros or 1023 in the sketch. As previously, all of the axis are seen in the Windows Game Controllers software (in the control panel)m but they are dead centered and ignore my zeros and 1023's. I live in Sweden. I completely understand if you have plenty of other things that you need and want to do! :) Many thanks for the help so far! Let me know if any ideas pop up, and I'll also be sure to write if I have any success with my tinkering! :)
 
I haven't tried the buttons, but I tried to send zeros or 1023 in the sketch. As previously, all of the axis are seen in the Windows Game Controllers software (in the control panel)m but they are dead centered and ignore my zeros and 1023's. I live in Sweden. I completely understand if you have plenty of other things that you need and want to do! :) Many thanks for the help so far! Let me know if any ideas pop up, and I'll also be sure to write if I have any success with my tinkering! :)


I have a Teensy LC that I am not using, which I could let you have for about £20 including shipping. (A rough guess without your full address) if you are interested. It has pins soldered on it and I would need to just double check it works ok, as it hasn't been used for a while.

Regards,

Les
 
I have a Teensy LC that I am not using, which I could let you have for about £20 including shipping. (A rough guess without your full address) if you are interested. It has pins soldered on it and I would need to just double check it works ok, as it hasn't been used for a while.

Regards,

Les

Thanks for the offer! I need to travel in work for about the nearest two weeks. I'll have a go at this code when I get home, and if I'm stuck I'll gladly take that offer, as they are sold out.

Best regards!
 
Status
Not open for further replies.
Back
Top