{"id":544,"date":"2021-10-03T18:28:21","date_gmt":"2021-10-03T17:28:21","guid":{"rendered":"https:\/\/debaz.azzano.fr\/azzano\/?p=544"},"modified":"2021-10-05T16:40:26","modified_gmt":"2021-10-05T15:40:26","slug":"long-time-no-see-usb-joystick-playground","status":"publish","type":"post","link":"https:\/\/debaz.azzano.fr\/azzano\/long-time-no-see-usb-joystick-playground\/","title":{"rendered":"Long Time No See &#8211; USB &#038; Joystick Playground"},"content":{"rendered":"\n<p>This story started a few years ago when I was working as an intern into a PCB production facility. I had a great time there and after a few discussions with the CEO, he agreed on sharing some ressources for our skinny student competition at the time. (Many Galileo students got as Christmas gift hundred of 3.1mm milling bits) <\/p>\n\n\n\n<!--more-->\n\n\n\n<p>After circling in their office like a vulture, I spotted an old milling machine left in a corner<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-style-default\"><img loading=\"lazy\" width=\"3091\" height=\"4096\" src=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20160805_165400-3091x4096.jpg\" alt=\"\" class=\"wp-image-568\" srcset=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20160805_165400-3091x4096.jpg 3091w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20160805_165400-773x1024.jpg 773w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20160805_165400-768x1018.jpg 768w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20160805_165400-1159x1536.jpg 1159w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20160805_165400-1545x2048.jpg 1545w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20160805_165400-1260x1670.jpg 1260w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20160805_165400-scaled.jpg 1932w\" sizes=\"(max-width: 3091px) 100vw, 3091px\" \/><figcaption>It&#8217;s that big thing in the corner<\/figcaption><\/figure>\n\n\n\n<p>At the time, CPE-Lyon was supposed to recover it for the Galileo association but they dropped the ball and my dear acolyte Rafik and I ended up having a good time tearing it apart.<\/p>\n\n\n\n<p>We recovered quite a few things which almost all ended up in the bottomless pit of Galileo, but I kept for myself that beautiful 2D joystick fully analog.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" width=\"2048\" height=\"1015\" src=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/signal-2021-09-13-134823.jpg\" alt=\"\" class=\"wp-image-569\" srcset=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/signal-2021-09-13-134823.jpg 2048w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/signal-2021-09-13-134823-1024x508.jpg 1024w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/signal-2021-09-13-134823-768x381.jpg 768w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/signal-2021-09-13-134823-1536x761.jpg 1536w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/signal-2021-09-13-134823-1260x624.jpg 1260w\" sizes=\"(max-width: 2048px) 100vw, 2048px\" \/><figcaption>2-Axis Joystick + 1 Button (That red cap)<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/VID_20210918_211037.mp4\"><\/video><figcaption>Sneak peek of the inside working<\/figcaption><\/figure>\n\n\n\n<p>That joystick travelled with me across the ocean twice and went through multiple countries as part of my toolbox but I could never find a use for it.<\/p>\n\n\n\n<p>Tired of carrying it over, I finally decided to use it over a weekend &#8211; after all what is more useless than a not-used piece of equipment ? Another useless piece of equipment using that piece of equipment of course ! After all I am into 3D printing&#8230; <\/p>\n\n\n\n<h2>Mechanical Section<\/h2>\n\n\n\n<p>Before we get into the technical stuff, let&#8217;s consider how useful is a 2D joystick + 1 button&#8230; Not really right ?! In many applications you need more buttons than that, and sometimes, a second joystick. An obvious use case would be video games, but how many gamepad only have 1 button and 1 joystick ?! Think about it &#8211; how many game do you know are using so few buttons and axis ? <\/p>\n\n\n\n<p>So I decided to build a 4 buttons &#8211; 2D axis Joystick so that i could have a bit more flexibility and maybe use it with my CNC. As I was into emptying my tool box, I decided to go with Endswitch for the extra buttons.<\/p>\n\n\n\n<p>The plan was simple, get the white-ish buttons to only translate vertically and being bounced up by the endswitch itself. <\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" src=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/Button.png\" alt=\"\" class=\"wp-image-578\" width=\"840\" height=\"652\" srcset=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/Button.png 898w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/Button-768x597.png 768w\" sizes=\"(max-width: 840px) 100vw, 840px\" \/><figcaption>The buttons&#8217; neck would need to be long enough such that they are always guided by the case regardless of their vertical position !<\/figcaption><\/figure>\n\n\n\n<p>By measuring the force needed to trigger the endswitch, I could get an estimation of if this was going to work or not.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"2307\" height=\"4096\" src=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20211003_110957-2307x4096.jpg\" alt=\"\" class=\"wp-image-579\" srcset=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20211003_110957-2307x4096.jpg 2307w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20211003_110957-577x1024.jpg 577w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20211003_110957-768x1364.jpg 768w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20211003_110957-865x1536.jpg 865w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20211003_110957-1153x2048.jpg 1153w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20211003_110957-1260x2237.jpg 1260w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20211003_110957-scaled.jpg 1442w\" sizes=\"(max-width: 2307px) 100vw, 2307px\" \/><figcaption>With 23g applied I can hear the endswitch clicking. However the endswitch would only release at approx 10g, quite an hysteresis ! <\/figcaption><\/figure>\n\n\n\n<p>Using my new CNC machine I started milling some wood<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" width=\"1527\" height=\"1275\" src=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20211001_151433-1-1.jpg\" alt=\"\" class=\"wp-image-586\" srcset=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20211001_151433-1-1.jpg 1527w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20211001_151433-1-1-1024x855.jpg 1024w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20211001_151433-1-1-768x641.jpg 768w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20211001_151433-1-1-1260x1052.jpg 1260w\" sizes=\"(max-width: 1527px) 100vw, 1527px\" \/><figcaption>A button<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" width=\"2295\" height=\"2560\" src=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20210920_205628-scaled.jpg\" alt=\"\" class=\"wp-image-589\" srcset=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20210920_205628-scaled.jpg 2295w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20210920_205628-918x1024.jpg 918w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20210920_205628-768x857.jpg 768w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20210920_205628-1377x1536.jpg 1377w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20210920_205628-1836x2048.jpg 1836w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20210920_205628-1260x1405.jpg 1260w\" sizes=\"(max-width: 2295px) 100vw, 2295px\" \/><figcaption>The outside views of the case<\/figcaption><\/figure>\n\n\n\n<p>My small buttons were weigthing 5g so I was confident that it would work ! <\/p>\n\n\n\n<p>On the inside the plan was the following :<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" width=\"729\" height=\"875\" src=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/Screenshot-2021-10-03-113109.png\" alt=\"\" class=\"wp-image-596\"\/><\/figure>\n\n\n\n<p>And it worked out more or less flawlessly <\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" src=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20211003_113217-4096x2307.jpg\" alt=\"\" class=\"wp-image-597\" width=\"840\" height=\"473\" srcset=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20211003_113217-4096x2307.jpg 4096w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20211003_113217-1024x577.jpg 1024w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20211003_113217-768x432.jpg 768w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20211003_113217-1536x865.jpg 1536w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20211003_113217-2048x1153.jpg 2048w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20211003_113217-1260x710.jpg 1260w\" sizes=\"(max-width: 840px) 100vw, 840px\" \/><figcaption>Raw mechanical result &#8211; Without any coating<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"4096\" height=\"2307\" src=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20211003_134655-4096x2307.jpg\" alt=\"\" class=\"wp-image-656\" srcset=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20211003_134655-4096x2307.jpg 4096w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20211003_134655-1024x577.jpg 1024w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20211003_134655-768x432.jpg 768w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20211003_134655-1536x865.jpg 1536w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20211003_134655-2048x1153.jpg 2048w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/IMG_20211003_134655-1260x710.jpg 1260w\" sizes=\"(max-width: 4096px) 100vw, 4096px\" \/><figcaption>The inside<\/figcaption><\/figure>\n\n\n\n<h2>Electronic section<\/h2>\n\n\n\n<p>Regarding the electronics, I had few microcontrollers taking the dust. However there was one thing bothering me : regardless of my choice, how would the PC apprehend the information ? I could write a custom driver or an intermediate software to transcode the serial port to something else but that isn&#8217;t really efficient.  I don&#8217;t want to be installing and maintaining software over the years for something so simple.<\/p>\n\n\n\n<p>I started then searching on the web how normal periphals are being detected by computer automatically, could I make my joystick look like a mouse or a keyboard ?! That would solve my compatibility requirement.<\/p>\n\n\n\n<p>And the answer is yes &#8211; and it is quite simple actually &#8211; you just have to integrate the USB protocol and act like a standard peripheral. (The keyword for that would be : <strong>USB human interface device class<\/strong> if you are interested)<\/p>\n\n\n\n<p>However after couples of hours of frustration with different microcontrollers, I realised that I was starting with the wrong foot. Typical evaluation board have the USB port connected to the debugger, and not for the processor you are using !<\/p>\n\n\n\n<p>An example with the Nucleo-L412KB, the USB port is going to an STM32F103 which is acting as your ST-Link debugger but you will be downloading your code to the STM32L412KB which then has no USB port access.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" width=\"657\" height=\"777\" src=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/Stm32.png\" alt=\"\" class=\"wp-image-609\"\/><figcaption><img loading=\"lazy\" width=\"862\" height=\"453\" class=\"wp-image-610\" style=\"width: 800px;\" src=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/Stm32L412.png\" alt=\"\" srcset=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/Stm32L412.png 862w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/Stm32L412-768x404.png 768w\" sizes=\"(max-width: 862px) 100vw, 862px\" \/><\/figcaption><\/figure>\n\n\n\n<p>This is why on many &#8211; more costly- evaluation boards you will find multiple USB port. But I wasn&#8217;t going to use a bigger evaluation board for such a simple task. After looking back at my toolbox, I found an old STM32F103 Bluepill from Xavier and it has no debugger at all !<\/p>\n\n\n\n<p>To program this one, you will need an external debugger and for that I used a previously broken nucleo, this is how it goes :<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" width=\"490\" height=\"707\" src=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/STM32Bluepill-1.png\" alt=\"\" class=\"wp-image-612\"\/><figcaption>Note : The USB Enumerration is a little bit dodgy with the debugger and with televersing new software to the board while plugged in. It is often required to connect\/disconnect the USB user to get the computer to recognize the platform with the new code. To avoid loosing the debugger connection when doing so, an external 3.3V supply is required to keep the system running. That 3.3V supply cannot come from the nucleo as too much power is being drawn and the LDO output will be falling to 2V.<\/figcaption><\/figure>\n\n\n\n<p>Regarding the inputs, the joystick is composed of two 10kOhm potentiometers and the buttons are using the integrated pull down of the STM32. When pressed down, the buttons are connecting the digital inputs to 3.3V.<\/p>\n\n\n\n<h2>Software Consideration<\/h2>\n\n\n\n<p>I had a pretty harsh time to get the USB protocol right. I still haven&#8217;t found a decent tool to help me debug what is going on but here are the different tools that I was using.<\/p>\n\n\n\n<p>The Windows Peripheral List (Bluetooth and other devices settings), my worst nightmare was to see a &#8220;Driver error&#8221; message which would indicate that my HID descriptor was not correct.<\/p>\n\n\n\n<p>Wireshark + <a href=\"https:\/\/desowin.org\/usbpcap\/\">USBPcap <\/a>to investigate the USB communication and see if the USB report was incorrect. Note : The command on the official website was not working on my PC but the one below was.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">USBPcapCMD.exe -A -d \\\\.\\USBPcap3 -o - | \"C:\\Program Files\\Wireshark\\Wireshark.exe\" -k -i -<\/pre>\n\n\n\n<p id=\"block-3853d675-2fa9-4579-98f2-7c05b1e8c7a3\">The setup USB Game controller from windows which is surprisingly flexible and efficient!<\/p>\n\n\n\n<p>This <a href=\"https:\/\/eleccelerator.com\/usbdescreqparser\/\">website <\/a>to parse USB Descriptor &#8211; very handy to analyze what you find on the internet.<\/p>\n\n\n\n<p>The <a href=\"https:\/\/www.usb.org\/document-library\/hid-descriptor-tool\">software <\/a>from ubs.org to build up descriptor &#8211; it is not very intuitive but it does the job once you understand a little bit the inner components.<\/p>\n\n\n\n<figure class=\"wp-container-2 wp-block-gallery-1 wp-block-gallery columns-3 is-cropped\"><ul class=\"blocks-gallery-grid\"><li class=\"blocks-gallery-item\"><figure><img loading=\"lazy\" width=\"554\" height=\"443\" src=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/USB_DT.png\" alt=\"\" data-id=\"627\" data-full-url=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/USB_DT.png\" data-link=\"https:\/\/debaz.azzano.fr\/azzano\/?attachment_id=627\" class=\"wp-image-627\"\/><figcaption class=\"blocks-gallery-item__caption\">USB Descriptor Tool &#8211; your best friend to build custom descriptor and generate the corresponding hexa<\/figcaption><\/figure><\/li><li class=\"blocks-gallery-item\"><figure><img loading=\"lazy\" width=\"796\" height=\"633\" src=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/Wireshark_Package2.png\" alt=\"\" data-id=\"625\" data-full-url=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/Wireshark_Package2.png\" data-link=\"https:\/\/debaz.azzano.fr\/azzano\/?attachment_id=625\" class=\"wp-image-625\" srcset=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/Wireshark_Package2.png 796w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/Wireshark_Package2-768x611.png 768w\" sizes=\"(max-width: 796px) 100vw, 796px\" \/><figcaption class=\"blocks-gallery-item__caption\">Standard package with Gamepad related content<\/figcaption><\/figure><\/li><li class=\"blocks-gallery-item\"><figure><img loading=\"lazy\" width=\"1098\" height=\"668\" src=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/Wireshark.png\" alt=\"\" data-id=\"624\" data-full-url=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/Wireshark.png\" data-link=\"https:\/\/debaz.azzano.fr\/azzano\/?attachment_id=624\" class=\"wp-image-624\" srcset=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/Wireshark.png 1098w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/Wireshark-1024x623.png 1024w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/Wireshark-768x467.png 768w\" sizes=\"(max-width: 1098px) 100vw, 1098px\" \/><figcaption class=\"blocks-gallery-item__caption\">Gamepad descriptor<\/figcaption><\/figure><\/li><li class=\"blocks-gallery-item\"><figure><img loading=\"lazy\" width=\"778\" height=\"556\" src=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/GamepadWindwos.png\" alt=\"\" data-id=\"623\" data-full-url=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/GamepadWindwos.png\" data-link=\"https:\/\/debaz.azzano.fr\/azzano\/?attachment_id=623\" class=\"wp-image-623\" srcset=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/GamepadWindwos.png 778w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/GamepadWindwos-768x549.png 768w\" sizes=\"(max-width: 778px) 100vw, 778px\" \/><figcaption class=\"blocks-gallery-item__caption\">Gamepad tool from Windows &#8211; very handy for visualization<\/figcaption><\/figure><\/li><li class=\"blocks-gallery-item\"><figure><img loading=\"lazy\" width=\"556\" height=\"477\" src=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/Driver-Error.png\" alt=\"\" data-id=\"622\" data-full-url=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/Driver-Error.png\" data-link=\"https:\/\/debaz.azzano.fr\/azzano\/?attachment_id=622\" class=\"wp-image-622\"\/><figcaption class=\"blocks-gallery-item__caption\">Windows complaining about the descriptor when incorrect<\/figcaption><\/figure><\/li><\/ul><\/figure>\n\n\n\n<p>I am looking forward to people&#8217;s suggestions on better tool for the job.<\/p>\n\n\n\n<p>Regarding the implementation in the ST environment it is actually quite simple. This is how I did it :<\/p>\n\n\n\n<p>1- Use the auto generated code from cubemx<\/p>\n\n\n\n<p>2- Replace the standard mouse descriptor by my own. This is happening in Middlewares\\ST\\STM32_USB_Device_Library\\Class\\HID\\Src\\usbd_hid.c and the variable HID_MOUSE_ReportDesc.  \/!\\ Don&#8217;t forget to update the size of the array &#8211; it won&#8217;t throw an error at compilation but the USB communication will fail<\/p>\n\n\n\n<p>3- Update the report and report size to what you want to use<\/p>\n\n\n\n<p>4- Call the function USBD_HID_SendReport(&amp;hUsbDeviceFS,&amp;Report, SIZE); when you want to transmit a package<\/p>\n\n\n\n<p>I haven&#8217;t found a way to update the USB driver files while staying compatible with the code auto generation (no User code is allowed in the middlewares files for some reason) so better be careful and regularly save your progression in a backup folder or Git.<\/p>\n\n\n\n<figure class=\"wp-container-4 wp-block-gallery-3 wp-block-gallery columns-2 is-cropped\"><ul class=\"blocks-gallery-grid\"><li class=\"blocks-gallery-item\"><figure><img loading=\"lazy\" width=\"1211\" height=\"741\" src=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/Clock_Tree.png\" alt=\"\" data-id=\"632\" class=\"wp-image-632\" srcset=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/Clock_Tree.png 1211w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/Clock_Tree-1024x627.png 1024w, https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/Clock_Tree-768x470.png 768w\" sizes=\"(max-width: 1211px) 100vw, 1211px\" \/><figcaption class=\"blocks-gallery-item__caption\">Clock Tree<\/figcaption><\/figure><\/li><li class=\"blocks-gallery-item\"><figure><img loading=\"lazy\" width=\"734\" height=\"611\" src=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/Config_STM32.png\" alt=\"\" data-id=\"633\" data-full-url=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/Config_STM32.png\" data-link=\"https:\/\/debaz.azzano.fr\/azzano\/?attachment_id=633\" class=\"wp-image-633\"\/><figcaption class=\"blocks-gallery-item__caption\">STM Pin Configuration<\/figcaption><\/figure><\/li><\/ul><\/figure>\n\n\n\n<p>A good simple example can be found <a href=\"https:\/\/controllerstech.com\/how-to-use-stm32-as-a-keyboard\/\">here<\/a>.<\/p>\n\n\n\n<p>My code is available on <a href=\"https:\/\/github.com\/Guilhem74\/STM32_HID_Custom_Joystick\">Github<\/a>.<\/p>\n\n\n\n<h2>User Experience<\/h2>\n\n\n\n<p>To maximize the purpose of the hardware I decided to have 3 different configurations. I coded it such that they are available at any time without needing to re-download code in the microcontroller. The configurations are selected at startup (press a button while plugging the USB).<\/p>\n\n\n\n<p>1- Acting as a Joystick (default)<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" width=\"549\" height=\"83\" src=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/JoystickMessage.png\" alt=\"\" class=\"wp-image-638\"\/><\/figure>\n\n\n\n<p><img loading=\"lazy\" width=\"741\" height=\"482\" class=\"wp-image-635\" style=\"width: 500px;\" src=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/Joystick_fct.png\" alt=\"\"><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Descriptor :\n                0x05, 0x01,                    \/\/ USAGE_PAGE (Generic Desktop)\n\t\t0x09, 0x05,                    \/\/ USAGE (Game Pad)\n\t\t0xa1, 0x01,                    \/\/ COLLECTION (Application)\n\t\t0xa1, 0x00,                    \/\/   COLLECTION (Physical)\n\t\t0x05, 0x01,                    \/\/     USAGE_PAGE (Generic Desktop)\n\t\t0x09, 0x30,                    \/\/     USAGE (X)\n\t\t0x09, 0x31,                    \/\/     USAGE (Y)\n\t\t0x15, 0x81,                    \/\/     LOGICAL_MINIMUM (-127)\n\t\t0x25, 0x7f,                    \/\/     LOGICAL_MAXIMUM (127)\n\t\t0x75, 0x08,                    \/\/     REPORT_SIZE (8)\n\t\t0x95, 0x02,                    \/\/     REPORT_COUNT (2)\n\t\t0x81, 0x02,                    \/\/     INPUT (Data,Var,Abs)\n\t\t0x05, 0x09,                    \/\/     USAGE_PAGE (Button)\n\t\t0x19, 0x01,                    \/\/     USAGE_MINIMUM (Button 1)\n\t\t0x29, 0x04,                    \/\/     USAGE_MAXIMUM (Button 4)\n\t\t0x15, 0x00,                    \/\/     LOGICAL_MINIMUM (0)\n\t\t0x25, 0x01,                    \/\/     LOGICAL_MAXIMUM (1)\n\t\t0x75, 0x01,                    \/\/     REPORT_SIZE (8)\n\t\t0x95, 0x08,                    \/\/     REPORT_COUNT (1)\n\t\t0x81, 0x02,                    \/\/     INPUT (Data,Var,Abs)\n\t\t0xc0,                          \/\/     END_COLLECTION\n\t\t0xc0                           \/\/ END_COLLECTION<\/code><\/pre>\n\n\n\n<p>2- Acting as a Mouse (Press button 1 at startup to be detected as a Mouse)<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" width=\"398\" height=\"69\" src=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/MouseMessage.png\" alt=\"\" class=\"wp-image-640\"\/><\/figure>\n\n\n\n<p><img loading=\"lazy\" width=\"762\" height=\"474\" class=\"wp-image-637\" style=\"width: 500px;\" src=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/Mouse_Fct.png\" alt=\"\"><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Descriptor:\n                0x05, 0x01,        \/\/ Usage Page (Generic Desktop Ctrls)\n\t\t0x09, 0x02,        \/\/ Usage (Mouse)\n\t\t0xA1, 0x01,        \/\/ Collection (Application)\n\t\t0x09, 0x01,        \/\/   Usage (Pointer)\n\t\t0xA1, 0x00,        \/\/   Collection (Physical)\n\t\t0x05, 0x09,        \/\/     Usage Page (Button)\n\t\t0x19, 0x01,        \/\/     Usage Minimum (0x01)\n\t\t0x29, 0x03,        \/\/     Usage Maximum (0x03)\n\t\t0x15, 0x00,        \/\/     Logical Minimum (0)\n\t\t0x25, 0x01,        \/\/     Logical Maximum (1)\n\t\t0x95, 0x03,        \/\/     Report Count (3)\n\t\t0x75, 0x01,        \/\/     Report Size (1)\n\t\t0x81, 0x02,        \/\/     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)\n\t\t0x95, 0x01,        \/\/     Report Count (1)\n\t\t0x75, 0x05,        \/\/     Report Size (5)\n\t\t0x81, 0x01,        \/\/     Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)\n\t\t0x05, 0x01,        \/\/     Usage Page (Generic Desktop Ctrls)\n\t\t0x09, 0x30,        \/\/     Usage (X)\n\t\t0x09, 0x31,        \/\/     Usage (Y)\n\t\t0x09, 0x38,        \/\/     Usage (Wheel)\n\t\t0x15, 0x81,        \/\/     Logical Minimum (-127)\n\t\t0x25, 0x7F,        \/\/     Logical Maximum (127)\n\t\t0x75, 0x08,        \/\/     Report Size (8)\n\t\t0x95, 0x03,        \/\/     Report Count (3)\n\t\t0x81, 0x06,        \/\/     Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)\n\t\t0xC0,              \/\/   End Collection\n\t\t0x09, 0x3C,        \/\/   Usage (Motion Wakeup)\n\t\t0x05, 0xFF,        \/\/   Usage Page (Reserved 0xFF)\n\t\t0x09, 0x01,        \/\/   Usage (0x01)\n\t\t0x15, 0x00,        \/\/   Logical Minimum (0)\n\t\t0x25, 0x01,        \/\/   Logical Maximum (1)\n\t\t0x75, 0x01,        \/\/   Report Size (1)\n\t\t0x95, 0x02,        \/\/   Report Count (2)\n\t\t0xB1, 0x22,        \/\/   Feature (Data,Var,Abs,No Wrap,Linear,No Preferred State,No Null Position,Non-volatile)\n\t\t0x75, 0x06,        \/\/   Report Size (6)\n\t\t0x95, 0x01,        \/\/   Report Count (1)\n\t\t0xB1, 0x01,        \/\/   Feature (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)\n\t\t0xC0,              \/\/ End Collection\n<\/code><\/pre>\n\n\n\n<p>3- Acting as a simple keyboard mostly targetted for CNC control (Page UP\/DOWN are used for the Z axis and Left Shift key for fast movement)<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" width=\"445\" height=\"69\" src=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/KeyboardMessage.png\" alt=\"\" class=\"wp-image-639\"\/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" width=\"587\" height=\"370\" src=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/Keyboard_FCT.png\" alt=\"\" class=\"wp-image-636\"\/><\/figure>\n\n\n\n<pre class=\"wp-block-code\"><code>Descriptor :\n            0x05, 0x01,                    \/\/ USAGE_PAGE (Generic Desktop)\n\t    0x09, 0x06,                    \/\/ USAGE (Keyboard)\n\t    0xa1, 0x01,                    \/\/ COLLECTION (Application)\n\t    0x05, 0x07,                    \/\/   USAGE_PAGE (Keyboard)\n\t    0x19, 0xe0,                    \/\/   USAGE_MINIMUM (Keyboard LeftControl)\n\t    0x29, 0xe7,                    \/\/   USAGE_MAXIMUM (Keyboard Right GUI)\n\t    0x15, 0x00,                    \/\/   LOGICAL_MINIMUM (0)\n\t    0x25, 0x01,                    \/\/   LOGICAL_MAXIMUM (1)\n\t    0x75, 0x01,                    \/\/   REPORT_SIZE (1)\n\t    0x95, 0x08,                    \/\/   REPORT_COUNT (8)\n\t    0x81, 0x02,                    \/\/   INPUT (Data,Var,Abs)\n\t    0x95, 0x01,                    \/\/   REPORT_COUNT (1)\n\t    0x75, 0x08,                    \/\/   REPORT_SIZE (8)\n\t    0x81, 0x03,                    \/\/   INPUT (Cnst,Var,Abs)\n\t    0x95, 0x05,                    \/\/   REPORT_COUNT (5)\n\t    0x75, 0x01,                    \/\/   REPORT_SIZE (1)\n\t    0x05, 0x08,                    \/\/   USAGE_PAGE (LEDs)\n\t    0x19, 0x01,                    \/\/   USAGE_MINIMUM (Num Lock)\n\t    0x29, 0x05,                    \/\/   USAGE_MAXIMUM (Kana)\n\t    0x91, 0x02,                    \/\/   OUTPUT (Data,Var,Abs)\n\t    0x95, 0x01,                    \/\/   REPORT_COUNT (1)\n\t    0x75, 0x03,                    \/\/   REPORT_SIZE (3)\n\t    0x91, 0x03,                    \/\/   OUTPUT (Cnst,Var,Abs)\n\t    0x95, 0x06,                    \/\/   REPORT_COUNT (6)\n\t    0x75, 0x08,                    \/\/   REPORT_SIZE (8)\n\t    0x15, 0x00,                    \/\/   LOGICAL_MINIMUM (0)\n\t    0x25, 0x65,                    \/\/   LOGICAL_MAXIMUM (101)\n\t    0x05, 0x07,                    \/\/   USAGE_PAGE (Keyboard)\n\t    0x19, 0x00,                    \/\/   USAGE_MINIMUM (Reserved (no event indicated))\n\t    0x29, 0x65,                    \/\/   USAGE_MAXIMUM (Keyboard Application)\n\t    0x81, 0x00,                    \/\/   INPUT (Data,Ary,Abs)\n\t    0xc0                           \/\/ END_COLLECTION<\/code><\/pre>\n\n\n\n<h2>Result<\/h2>\n\n\n\n<p>You might recall that at the beginning of that post, I mentioned that I didn&#8217;t want to rewrite any driver or software. That proved to be successful as after finishing this project on my windows laptop, I decided to plug the module directly to my smartphone. Without any modification and without needing any application, I can now have a mouse\/keyboard or joystick on my phone.<\/p>\n\n\n\n<div class=\"wp-container-6 wp-block-columns\">\n<div class=\"wp-container-5 wp-block-column\" style=\"flex-basis:100%\">\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/20211003_131610_001.mp4\"><\/video><figcaption>Mouse Mode &#8211; not the best interface for a smartphone but it works<\/figcaption><\/figure>\n<\/div>\n<\/div>\n\n\n\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/20211003_131932_1.mp4\"><\/video><figcaption>Joystick mode : compatible with gaming app (In that case Drastic emulating Pokemon for Nintendo DS)<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/debaz.azzano.fr\/azzano\/wp-content\/uploads\/2021\/10\/VID_20211003_133017.mp4\"><\/video><figcaption>Keyboard mode : Using a different laptop with raw windows + MACH 3<\/figcaption><\/figure>\n\n\n\n<p>That&#8217;s it for now. Ultimately I would add more buttons to it and work on the deadzone for the joystick &#8211; at the moment it is a simple threshold which reduces the dynamic range.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This story started a few years ago when I was working as an intern into a PCB production facility. I had a great time there and after a few discussions with the CEO, he agreed on sharing some ressources for our skinny student competition at the time. (Many Galileo students got as Christmas gift hundred&hellip; <\/p>\n<p class=\"toivo-read-more\"><a href=\"https:\/\/debaz.azzano.fr\/azzano\/long-time-no-see-usb-joystick-playground\/\" class=\"more-link\">Read more <span class=\"screen-reader-text\">Long Time No See &#8211; USB &#038; Joystick Playground<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[7],"tags":[],"_links":{"self":[{"href":"https:\/\/debaz.azzano.fr\/azzano\/wp-json\/wp\/v2\/posts\/544"}],"collection":[{"href":"https:\/\/debaz.azzano.fr\/azzano\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/debaz.azzano.fr\/azzano\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/debaz.azzano.fr\/azzano\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/debaz.azzano.fr\/azzano\/wp-json\/wp\/v2\/comments?post=544"}],"version-history":[{"count":70,"href":"https:\/\/debaz.azzano.fr\/azzano\/wp-json\/wp\/v2\/posts\/544\/revisions"}],"predecessor-version":[{"id":672,"href":"https:\/\/debaz.azzano.fr\/azzano\/wp-json\/wp\/v2\/posts\/544\/revisions\/672"}],"wp:attachment":[{"href":"https:\/\/debaz.azzano.fr\/azzano\/wp-json\/wp\/v2\/media?parent=544"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/debaz.azzano.fr\/azzano\/wp-json\/wp\/v2\/categories?post=544"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/debaz.azzano.fr\/azzano\/wp-json\/wp\/v2\/tags?post=544"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}