Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 6 of 6

Thread: Teensy 2.0 12 axis joystick/gamepad

  1. #1
    Junior Member
    Join Date
    Mar 2020
    Posts
    5

    Teensy 2.0 12 axis joystick/gamepad

    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_gate way

    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

  2. #2
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    21,467
    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.

  3. #3
    Junior Member
    Join Date
    Mar 2020
    Posts
    5
    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!

  4. #4
    Junior Member
    Join Date
    Mar 2020
    Posts
    5
    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.

    Click image for larger version. 

Name:	usb-data.png 
Views:	3 
Size:	38.5 KB 
ID:	19502
    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!

  5. #5
    Hi Dran,

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

    Quote Originally Posted by Dran View Post
    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.

    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.

    Quote Originally Posted by Dran View Post
    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.

    Quote Originally Posted by Dran View Post
    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.

    Quote Originally Posted by Dran View Post
    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

  6. #6
    Junior Member
    Join Date
    Mar 2020
    Posts
    5
    Quote Originally Posted by Pointy View Post
    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.

    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!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •