Changeset 703832c in avrstuff
- Timestamp:
- Sep 26, 2021, 10:16:19 AM (3 years ago)
- Branches:
- main
- Children:
- e545350
- Parents:
- 81b8d53
- Location:
- grip2hid
- Files:
-
- 6 added
- 1 deleted
- 1 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
grip2hid/README.md
r81b8d53 r703832c 11 11 (2 gameports, each allowing to use 2 gamepads thanks to Gravis chaining system). 12 12 13 The gamepads are each reported as a separate USB report, and show up as 4 independant 14 gamepads on both Windows and Haiku. Buttons are assigned in this order: 15 green, yellow, red, blue, L1, R1, start, select, R2, L2. This order is reasonable 16 (but not perfect) while allowing to reuse the bits received from the gamepad almost 17 directly to fill the HID report. The only change needed is inverting the Y axis, 18 because USB wants the up direction to be lowest values. 19 13 20 It is powered by an AT90USB AVR microcontroller, because these implement USB in 14 hardware and have easily usable external interupts (PCINT) making it much easier 15 to implement the protocol (this helps because the gamepad is the master and 16 drives the clock). 21 hardware and make it easy to implement an HID device. 22 23 You need the LUFA USB stack to compile this project. I am not including it to 24 avoid code duplication. Download and extract it yourself, or set the LUFA_PATH variable 25 to where you already have it when compiling. 17 26 18 27 [Further reading on GrIP](http://pulkomandy.tk/_/_Electronique/_Gravis%20Interface%20Protocol) -
grip2hid/grip.cpp
r81b8d53 r703832c 1 1 #include <avr/io.h> 2 #include <avr/interrupt.h>3 #include <avr/wdt.h>4 #include <avr/pgmspace.h>5 #include <util/delay.h>6 2 7 #include <string.h>8 3 #include <stdbool.h> 9 4 10 #include "../libs/usart/usart.h" 11 5 // The UART is on PD2 (Rx) and PD3 (Tx) 6 // The gamepads are all connected on port B 12 7 #define GRIP_PORT PORTB 13 8 #define GRIP_DDR DDRB … … 32 27 } 33 28 29 // Push the next bit and returns true if it completes a word. 30 // The whole 24 bit word is stored in "word" and consists of: 31 // - One 7-bit sync pattern: always 0111111 32 // - Three 6-bit blocks starting with a 0 followed by 5 button bits 34 33 bool PushBit(uint32_t bit) 35 34 { 36 word = (word << 1) | (bit &1);35 word = (word >> 1) | ((bit & 1) << 31); 37 36 count++; 38 37 39 38 switch (state) { 40 39 case 0: 41 if ((word & 0x 3F) != 0x1F) return false;42 count = 6;40 if ((word & 0xFE000000) != 0x7C000000) return false; 41 count = 7; 43 42 state = 1; 44 43 break; … … 55 54 } 56 55 57 void Dump() { 58 USARTWriteHex(word >> 16); 59 USARTWriteHex(word >> 8); 60 USARTWriteHex(word); 61 } 62 56 public: 57 uint32_t word; 63 58 private: 64 uint32_t word;65 59 uint8_t count; 66 uint8_t state; 60 uint8_t state; // 0 = looking for sync, 1 = synchronized (we received 0111111) 67 61 }; 68 62 69 63 70 int main() { 71 wdt_enable(WDTO_2S); 72 64 extern "C" void GrIP_Init() { 73 65 // GrIP input 74 66 GRIP_PORT = 0xFF; // Enable pull-ups 75 67 GRIP_DDR = 0; // Port as input 68 } 76 69 77 USARTInit(); 78 USARTWriteChar('h'); 79 USARTWriteChar('\r'); 80 USARTWriteChar('\n'); 81 70 extern "C" uint8_t GrIP_Read(uint32_t* v, uint8_t k2) { 82 71 // Initial value of oldv for edge detection 83 72 uint8_t oldv = GRIP_PIN; 73 static uint8_t k = 0; 74 if (k2 != 0) 75 k = k2 - 1; 76 else { 77 k++; if (k > 3) k = 0; 78 } 84 79 85 for (;;) {86 80 // Because the CPU is too slow, if we try to scan all pads at once we 87 81 // don't manage to decode them (missed transitions). So we scan them … … 95 89 // also fixes the problem mentionned below that when less pads are 96 90 // connected, it will not slowdown waiting for one of them to timeout. 91 // 92 // When a gamepad is plugged, the loop seems to complete in around 1000 iterations. 93 // When no gamepad is plugged, that's a timeout. 97 94 98 // FIXME the loop to 255 here to wait for a bit isn't too nice. We99 // should rather use a timer with a known period?100 95 // Process pad1 101 96 GrIP pad; 102 uint8_t i; 103 for (i = 0; i < 255; i++) { 104 wdt_reset(); 97 uint16_t i; 105 98 99 if (k == 0) 100 for (i = 0; i < 2048; i++) { 106 101 uint8_t newv = GRIP_PIN; 107 108 102 if (!(newv & GRIP_CLK_A)) { // clock is down 109 103 if (oldv & GRIP_CLK_A) { // and it was up at previous read … … 111 105 uint32_t bit = (newv & GRIP_DAT_A) != 0; 112 106 if (pad.PushBit(bit)) { 107 *v = pad.word; 113 108 break; 114 109 } … … 118 113 } 119 114 120 pad.Dump();121 USARTWriteChar(' ');122 123 115 // Process pad 2 124 for (i = 0; i < 255; i++) { 125 wdt_reset(); 126 116 if (k == 1) 117 for (i = 0; i < 2048; i++) { 127 118 uint8_t newv = GRIP_PIN; 128 119 if (!(newv & GRIP_CLK_B)) { // clock is down … … 131 122 uint32_t bit = (newv & GRIP_DAT_B) != 0; 132 123 if (pad.PushBit(bit)) { 124 *v = pad.word; 133 125 break; 134 126 } … … 138 130 } 139 131 140 pad.Dump();141 USARTWriteChar(' ');142 143 132 // Process pad 3 144 for (i = 0; i < 255; i++) { 145 wdt_reset(); 146 133 if (k == 2) 134 for (i = 0; i < 2048; i++) { 147 135 uint8_t newv = GRIP_PIN; 148 136 if (!(newv & GRIP_CLK_C)) { // clock is down … … 151 139 uint32_t bit = (newv & GRIP_DAT_C) != 0; 152 140 if (pad.PushBit(bit)) { 141 *v = pad.word; 153 142 break; 154 143 } … … 158 147 } 159 148 160 pad.Dump();161 USARTWriteChar(' ');162 163 149 // Process pad 4 164 for (i = 0; i < 255; i++) { 165 wdt_reset(); 166 150 if (k == 3) 151 for (i = 0; i < 2048; i++) { 167 152 uint8_t newv = GRIP_PIN; 168 153 if (!(newv & GRIP_CLK_D)) { // clock is down … … 171 156 uint32_t bit = (newv & GRIP_DAT_D) != 0; 172 157 if (pad.PushBit(bit)) { 158 *v = pad.word; 173 159 break; 174 160 } … … 178 164 } 179 165 180 pad.Dump(); 181 USARTWriteChar('\r'); 182 USARTWriteChar('\n'); 183 } 184 185 return 0; 166 return k; 186 167 } 187 168
Note:
See TracChangeset
for help on using the changeset viewer.