Guest User

Untitled

a guest
Oct 23rd, 2024
167
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 16.84 KB | None | 0 0
  1. // DWARFKINGKILI Current Project Prototype - JANUARY 2024
  2.  
  3. // *This project has been built with modified code from Cirque Corp
  4. // Copyright (c) 2018 Cirque Corp. Restrictions apply. See: www.cirque.com/sw-license
  5.  
  6. #include <SPI.h>
  7. #include <Arduino.h>
  8. #include <BleGamepad.h>
  9.  
  10. // This device is currently built to operate with a ESP32.
  11. // It can easily be adapted to work with other Arduino-based systems.
  12. // This device is using a Cirque TM0XX0XX trackpad with a Curved Overlay.
  13. // A 12 pin FFC cable, A 12 pin 0.5mm Ribbon adapter, Jumper cables, and the ESP32
  14.  
  15. // This application connects to a TM0XX0XX circular trackpad via SPI. To verify that
  16. // your trackpad is configured for SPI-mode, make sure that R1 is populated with a
  17. // 470k resistor (or whichever resitor connects pins 24 & 25 of the 1CA027 IC).
  18.  
  19. // NOTE: To eliminate any confusion in the hookup process I've listed below the old
  20. // and new terminology. For example MISO (OLD) = CIPO (NEW). Depending on when you
  21. // started to code, this may be useful
  22.  
  23. // NOTE: Additionally I've color coded the wires to aid in your hookup process.
  24.  
  25. // The TM0XX0XX circular trackpad is configured for Relative mode tracking.
  26.  
  27. //Pinnacle TM0XX0XX with Arduino
  28. //Touchpad -> 12 Pin FFC cable -> Adapeter -> Jumper cables -> ESP32
  29.  
  30. //12 pin 0.5mm Ribbon Adapter
  31. //Pin 1 SCK (SPI clock line) (Green)
  32. //Pin 2 MISO (SPI Master Input Slave Output) (Red)
  33. //Pin 3 SS (Slave Select (AKA Chip Select)) (Brown)
  34. //Pin 4 DR (Data Ready interrupt) (Orange)
  35. //Pin 5 MOSI (SPI Master Output Slave Input) (White)
  36. //Pin 6 BTN2 (Hardware input button #2)
  37. //Pin 7 BTN3 (Hardware input button #3)
  38. //Pin 8 BTN1 (Hardware input button #1)
  39. //Pin 9 SCL (I2C clock line)
  40. //Pin 10 SDA (I2C data line)
  41. //Pin 11 GND (Ground) (Yellow)
  42. //Pin 12 VDD (3V power supply) (Blue)
  43.  
  44. // Hardware pin-number labels
  45. #define SCK_PIN 18 //Clock
  46. #define DIN_PIN 19 //Miso
  47. #define DOUT_PIN 23 //Mosi
  48. #define CS_PIN 5 //Slave Select
  49. #define DR_PIN 22 //DataReady
  50.  
  51. #define SDA_PIN 42
  52. #define SCL_PIN 39
  53.  
  54. #define LED_0 21
  55. #define LED_1 20
  56.  
  57. // Masks for Cirque Register Access Protocol (RAP)
  58. #define WRITE_MASK 0x80
  59. #define READ_MASK 0xA0
  60.  
  61. // Register config values for this demo
  62. #define SYSCONFIG_1 0x00
  63. #define FEEDCONFIG_1 0x83 //Inverted Axis
  64. #define FEEDCONFIG_2 0x06
  65. #define Z_IDLE_COUNT 0x05
  66.  
  67. // Coordinate scaling values
  68. #define PINNACLE_XMAX 2047 // max value Pinnacle can report for X (0 to (8 * 256) -1)
  69. #define PINNACLE_YMAX 1535 // max value Pinnacle can report for Y (0 to (6 * 256) -1)
  70. #define PINNACLE_X_LOWER 511 // min "reachable" X value
  71. #define PINNACLE_X_UPPER 1535 // max "reachable" X value
  72. #define PINNACLE_Y_LOWER 226 // min "reachable" Y value
  73. #define PINNACLE_Y_UPPER 1250 // max "reachable" Y value
  74. #define PINNACLE_X_RANGE (PINNACLE_X_UPPER-PINNACLE_X_LOWER)
  75. #define PINNACLE_Y_RANGE (PINNACLE_Y_UPPER-PINNACLE_Y_LOWER)
  76. #define ZONESCALE 256 // divisor for reducing x,y values to an array index for the LUT
  77. #define ROWS_Y ((PINNACLE_YMAX + 1) / ZONESCALE)
  78. #define COLS_X ((PINNACLE_XMAX + 1) / ZONESCALE)
  79.  
  80. // ADC-attenuation settings (held in BIT_7 and BIT_6)
  81. // 1X = most sensitive, 4X = least sensitive
  82. #define ADC_ATTENUATE_1X 0x00
  83. #define ADC_ATTENUATE_2X 0x40
  84. #define ADC_ATTENUATE_3X 0x80
  85. #define ADC_ATTENUATE_4X 0xC0
  86.  
  87. // Convenient way to store and access measurements
  88. typedef struct _absData
  89. {
  90. uint16_t xValue;
  91. uint16_t yValue;
  92. uint16_t zValue;
  93. uint8_t buttonFlags;
  94. bool touchDown;
  95. bool hovering;
  96. } absData_t;
  97.  
  98. absData_t touchData;
  99.  
  100. //const uint16_t ZONESCALE = 256;
  101. //const uint16_t ROWS_Y = 6;
  102. //const uint16_t COLS_X = 8;
  103.  
  104. // These values require tuning for optimal touch-response
  105. // Each element represents the Z-value below which is considered "hovering" in that XY region of the sensor.
  106. // The values present are not guaranteed to work for all HW configurations.
  107. const uint8_t ZVALUE_MAP[ROWS_Y][COLS_X] =
  108. {
  109. {5, 5, 5, 5, 5, 5, 5, 5},
  110. {5, 5, 5, 5, 5, 5, 5, 5},
  111. {5, 5, 5, 15, 15, 5, 5, 5},
  112. {5, 5, 5, 15, 15, 5, 5, 5},
  113. {5, 5, 5, 5, 5, 5, 5, 5},
  114. {5, 5, 5, 5, 5, 5, 5, 5},
  115. };
  116.  
  117.  
  118. BleGamepad bleGamepad("ESP32 BLE JOYSTICK", "DWARFKINGKILI", 100);
  119. BleGamepadConfiguration bleGamepadConfig; // Create a BleGamepadConfiguration object to store all of the options
  120.  
  121. const int numberOfPotSamples = 64;
  122. // Number of pot samples to take (to smooth the values)
  123. const int delayBetweenSamples = 1;
  124. // Delay in milliseconds between pot samples
  125. const int delayBetweenHIDReports = 2;
  126. // Additional delay in milliseconds between HID reports
  127. const int debounceDelay = 10;
  128. // Delay in milliseconds between button press
  129.  
  130. // setup() gets called once at power-up, sets up serial debug output and Cirque's Pinnacle ASIC.
  131. void setup()
  132. {
  133. Serial.begin(115200);
  134.  
  135. bleGamepadConfig.setControllerType(CONTROLLER_TYPE_GAMEPAD); // CONTROLLER_TYPE_JOYSTICK, CONTROLLER_TYPE_GAMEPAD (DEFAULT), CONTROLLER_TYPE_MULTI_AXIS
  136.  
  137. analogReadResolution(12);
  138. // Sets the sample bits and read resolution, default is 12-bit (0 - 4095), range is 9 - 12 bits
  139. analogSetWidth(12);
  140. // Sets the sample bits and read resolution, default is 12-bit (0 - 4095), range is 9 - 12 bits
  141. // 9-bit gives an ADC range of 0-511
  142. // 10-bit gives an ADC range of 0-1023
  143. // 11-bit gives an ADC range of 0-2047
  144. // 12-bit gives an ADC range of 0-4095
  145. analogSetAttenuation(ADC_11db);
  146. // Sets the input attenuation for ALL ADC inputs, default is ADC_11db, range is ADC_0db, ADC_2_5db, ADC_6db, ADC_11db
  147. // ADC_0db provides no attenuation so IN/OUT = 1 / 1 an input of 3 volts remains at 3 volts before ADC measurement
  148. // ADC_2_5db provides an attenuation so that IN/OUT = 1 / 1.34 an input of 3 volts is reduced to 2.238 volts before ADC measurement
  149. // ADC_6db provides an attenuation so that IN/OUT = 1 / 2 an input of 3 volts is reduced to 1.500 volts before ADC measurement
  150. // ADC_11db provides an attenuation so that IN/OUT = 1 / 3.6 an input of 3 volts is reduced to 0.833 volts before ADC measurement
  151. analogSetClockDiv(255);
  152. // Set the divider for the ADC clock, default is 1, range is 1 - 255
  153.  
  154. Serial.println("Starting BLE Joystick!");
  155. bleGamepad.begin(&bleGamepadConfig); // Begin gamepad with configuration options
  156.  
  157. pinMode(LED_0, OUTPUT);
  158.  
  159. Pinnacle_Init();
  160.  
  161. // These functions are required for use with thick overlays (curved)
  162. setAdcAttenuation(ADC_ATTENUATE_1X);
  163.  
  164. tuneEdgeSensitivity();
  165.  
  166. Serial.println();
  167. Serial.println("X\tY\tZ\tBtn\tData");
  168. Pinnacle_EnableFeed(true);
  169. }
  170.  
  171. // loop() continuously checks to see if data-ready (DR) is high. If so, reads and reports touch data to terminal.
  172. void loop()
  173. {
  174. if(DR_Asserted())
  175. {
  176. Pinnacle_GetAbsolute(&touchData);
  177. Pinnacle_CheckValidTouch(&touchData); // Checks for "hover" caused by curved overlays
  178. if (touchData.touchDown)
  179. ScaleData(&touchData, 32767, 32767); // Scale coordinates to arbitrary X, Y resolution
  180. else{
  181. touchData.xValue = 32767/2; //Joystick range divisible to center stick, Maintain value 3.5
  182. touchData.yValue = 32767/2; //Joystick range divsiible to center stick, Maintain value 2.75
  183. }
  184.  
  185. bleGamepad.setX(touchData.xValue);
  186. bleGamepad.setY(touchData.yValue);
  187.  
  188. Serial.print(touchData.xValue);
  189. Serial.print('\t');
  190. Serial.print(touchData.yValue);
  191. Serial.print('\t');
  192. Serial.print(touchData.zValue);
  193. Serial.print('\t');
  194. Serial.print(touchData.buttonFlags);
  195. Serial.print('\t');
  196. if(Pinnacle_zIdlePacket(&touchData))
  197. {
  198. Serial.println("liftoff");
  199. }
  200. else if(touchData.hovering)
  201. {
  202. Serial.println("hovering");
  203. }
  204. else
  205. {
  206. Serial.println("valid");
  207. }
  208. }
  209. AssertSensorLED(touchData.touchDown);
  210. }
  211.  
  212. /* Pinnacle-based TM0XX0XX Functions */
  213. void Pinnacle_Init()
  214. {
  215. RAP_Init();
  216. DeAssert_CS();
  217. pinMode(DR_PIN, INPUT);
  218.  
  219. // Host clears SW_CC flag
  220. Pinnacle_ClearFlags();
  221.  
  222. // Host configures bits of registers 0x03 and 0x05
  223. RAP_Write(0x03, SYSCONFIG_1);
  224. RAP_Write(0x05, FEEDCONFIG_2);
  225.  
  226. // Host enables preferred output mode (absolute)
  227. RAP_Write(0x04, FEEDCONFIG_1);
  228.  
  229. // Host sets z-idle packet count to 5 (default is 30)
  230. RAP_Write(0x0A, Z_IDLE_COUNT);
  231. Serial.println("Pinnacle Initialized...");
  232. }
  233.  
  234. // Reads XYZ data from Pinnacle registers 0x14 through 0x17
  235. // Stores result in absData_t struct with xValue, yValue, and zValue members
  236. void Pinnacle_GetAbsolute(absData_t * result)
  237. {
  238. uint8_t data[6] = { 0,0,0,0,0,0 };
  239. RAP_ReadBytes(0x12, data, 6);
  240.  
  241. Pinnacle_ClearFlags();
  242.  
  243. result->buttonFlags = data[0] & 0x3F;
  244. result->xValue = data[2] | ((data[4] & 0x0F) << 8);
  245. result->yValue = data[3] | ((data[4] & 0xF0) << 4);
  246. result->zValue = data[5] & 0x3F;
  247.  
  248. result->touchDown = result->xValue != 0;
  249. }
  250.  
  251. // Checks touch data to see if it is a z-idle packet (all zeros)
  252. bool Pinnacle_zIdlePacket(absData_t * data)
  253. {
  254. return data->xValue == 0 && data->yValue == 0 && data->zValue == 0;
  255. }
  256.  
  257. // Clears Status1 register flags (SW_CC and SW_DR)
  258. void Pinnacle_ClearFlags()
  259. {
  260. RAP_Write(0x02, 0x00);
  261. delayMicroseconds(50);
  262. }
  263.  
  264. // Enables/Disables the feed
  265. void Pinnacle_EnableFeed(bool feedEnable)
  266. {
  267. uint8_t temp;
  268.  
  269. RAP_ReadBytes(0x04, &temp, 1); // Store contents of FeedConfig1 register
  270.  
  271. if(feedEnable)
  272. {
  273. temp |= 0x01; // Set Feed Enable bit
  274. RAP_Write(0x04, temp);
  275. }
  276. else
  277. {
  278. temp &= ~0x01; // Clear Feed Enable bit
  279. RAP_Write(0x04, temp);
  280. }
  281. }
  282.  
  283.  
  284. /* Curved Overlay Functions */
  285. // Adjusts the feedback in the ADC, effectively attenuating the finger signal
  286. // By default, the the signal is maximally attenuated (ADC_ATTENUATE_4X for use with thin, flat overlays
  287. void setAdcAttenuation(uint8_t adcGain)
  288. {
  289. uint8_t temp = 0x00;
  290.  
  291. Serial.println();
  292. Serial.println("Setting ADC gain...");
  293. ERA_ReadBytes(0x0187, &temp, 1);
  294. temp &= 0x3F; // clear top two bits
  295. temp |= adcGain;
  296. ERA_WriteByte(0x0187, temp);
  297. ERA_ReadBytes(0x0187, &temp, 1);
  298. Serial.print("ADC gain set to:\t");
  299. Serial.print(temp &= 0xC0, HEX);
  300. switch(temp)
  301. {
  302. case ADC_ATTENUATE_1X:
  303. Serial.println(" (X/1)");
  304. break;
  305. case ADC_ATTENUATE_2X:
  306. Serial.println(" (X/2)");
  307. break;
  308. case ADC_ATTENUATE_3X:
  309. Serial.println(" (X/3)");
  310. break;
  311. case ADC_ATTENUATE_4X:
  312. Serial.println(" (X/4)");
  313. break;
  314. default:
  315. break;
  316. }
  317. }
  318.  
  319. // Changes thresholds to improve detection of fingers
  320. void tuneEdgeSensitivity()
  321. {
  322. uint8_t temp = 0x00;
  323.  
  324. Serial.println();
  325. Serial.println("Setting xAxis.WideZMin...");
  326. ERA_ReadBytes(0x0149, &temp, 1);
  327. Serial.print("Current value:\t");
  328. Serial.println(temp, HEX);
  329. ERA_WriteByte(0x0149, 0x04);
  330. ERA_ReadBytes(0x0149, &temp, 1);
  331. Serial.print("New value:\t");
  332. Serial.println(temp, HEX);
  333.  
  334. Serial.println();
  335. Serial.println("Setting yAxis.WideZMin...");
  336. ERA_ReadBytes(0x0168, &temp, 1);
  337. Serial.print("Current value:\t");
  338. Serial.println(temp, HEX);
  339. ERA_WriteByte(0x0168, 0x03);
  340. ERA_ReadBytes(0x0168, &temp, 1);
  341. Serial.print("New value:\t");
  342. Serial.println(temp, HEX);
  343. }
  344.  
  345. // This function identifies when a finger is "hovering" so your system can choose to ignore them.
  346. // Explanation: Consider the response of the sensor to be flat across it's area. The Z-sensitivity of the sensor projects this area
  347. // a short distance upwards above the surface of the sensor. Imagine it is a solid cylinder (wider than it is tall)
  348. // in which a finger can be detected and tracked. Adding a curved overlay will cause a user's finger to dip deeper in the middle, and higher
  349. // on the perimeter. If the sensitivity is tuned such that the sensing area projects to the highest part of the overlay, the lowest
  350. // point will likely have excessive sensitivity. This means the sensor can detect a finger that isn't actually contacting the overlay in the shallower area.
  351. // ZVALUE_MAP[][] stores a lookup table in which you can define the Z-value and XY position that is considered "hovering". Experimentation/tuning is required.
  352. // NOTE: Z-value output decreases to 0 as you move your finger away from the sensor, and it's maximum value is 0x63 (6-bits).
  353. void Pinnacle_CheckValidTouch(absData_t * touchData)
  354. {
  355. uint32_t zone_x, zone_y;
  356. //eliminate hovering
  357. zone_x = touchData->xValue / ZONESCALE;
  358. zone_y = touchData->yValue / ZONESCALE;
  359. touchData->hovering = !(touchData->zValue > ZVALUE_MAP[zone_y][zone_x]);
  360. }
  361.  
  362. /* ERA (Extended Register Access) Functions */
  363. // Reads <count> bytes from an extended register at <address> (16-bit address),
  364. // stores values in <*data>
  365. void ERA_ReadBytes(uint16_t address, uint8_t * data, uint16_t count)
  366. {
  367. uint8_t ERAControlValue = 0xFF;
  368.  
  369. Pinnacle_EnableFeed(false); // Disable feed
  370.  
  371. RAP_Write(0x1C, (uint8_t)(address >> 8)); // Send upper byte of ERA address
  372. RAP_Write(0x1D, (uint8_t)(address & 0x00FF)); // Send lower byte of ERA address
  373.  
  374. for(uint16_t i = 0; i < count; i++)
  375. {
  376. RAP_Write(0x1E, 0x05); // Signal ERA-read (auto-increment) to Pinnacle
  377.  
  378. // Wait for status register 0x1E to clear
  379. do
  380. {
  381. RAP_ReadBytes(0x1E, &ERAControlValue, 1);
  382. } while(ERAControlValue != 0x00);
  383.  
  384. RAP_ReadBytes(0x1B, data + i, 1);
  385.  
  386. Pinnacle_ClearFlags();
  387. }
  388. }
  389.  
  390. // Writes a byte, <data>, to an extended register at <address> (16-bit address)
  391. void ERA_WriteByte(uint16_t address, uint8_t data)
  392. {
  393. uint8_t ERAControlValue = 0xFF;
  394.  
  395. Pinnacle_EnableFeed(false); // Disable feed
  396.  
  397. RAP_Write(0x1B, data); // Send data byte to be written
  398.  
  399. RAP_Write(0x1C, (uint8_t)(address >> 8)); // Upper byte of ERA address
  400. RAP_Write(0x1D, (uint8_t)(address & 0x00FF)); // Lower byte of ERA address
  401.  
  402. RAP_Write(0x1E, 0x02); // Signal an ERA-write to Pinnacle
  403.  
  404. // Wait for status register 0x1E to clear
  405. do
  406. {
  407. RAP_ReadBytes(0x1E, &ERAControlValue, 1);
  408. } while(ERAControlValue != 0x00);
  409.  
  410. Pinnacle_ClearFlags();
  411. }
  412.  
  413. /* RAP Functions */
  414.  
  415. void RAP_Init()
  416. {
  417. pinMode(CS_PIN, OUTPUT);
  418. SPI.begin();
  419. }
  420.  
  421. // Reads <count> Pinnacle registers starting at <address>
  422. void RAP_ReadBytes(byte address, byte * data, byte count)
  423. {
  424. byte cmdByte = READ_MASK | address; // Form the READ command byte
  425.  
  426. SPI.beginTransaction(SPISettings(20000000, MSBFIRST, SPI_MODE1));
  427.  
  428. Assert_CS();
  429. SPI.transfer(cmdByte); // Signal a RAP-read operation starting at <address>
  430. SPI.transfer(0xFC); // Filler byte
  431. SPI.transfer(0xFC); // Filler byte
  432. for(byte i = 0; i < count; i++)
  433. {
  434. data[i] = SPI.transfer(0xFC); // Each subsequent SPI transfer gets another register's contents
  435. }
  436. DeAssert_CS();
  437.  
  438. SPI.endTransaction();
  439. }
  440.  
  441. // Writes single-byte <data> to <address>
  442. void RAP_Write(byte address, byte data)
  443. {
  444. byte cmdByte = WRITE_MASK | address; // Form the WRITE command byte
  445.  
  446. SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE1));
  447.  
  448. Assert_CS();
  449. SPI.transfer(cmdByte); // Signal a write to register at <address>
  450. SPI.transfer(data); // Send <value> to be written to register
  451. DeAssert_CS();
  452.  
  453. SPI.endTransaction();
  454. }
  455.  
  456. /* Logical Scaling Functions */
  457. // Clips raw coordinates to "reachable" window of sensor
  458. // NOTE: values outside this window can only appear as a result of noise
  459. void ClipCoordinates(absData_t * coordinates)
  460. {
  461. if(coordinates->xValue < PINNACLE_X_LOWER)
  462. {
  463. coordinates->xValue = PINNACLE_X_LOWER;
  464. }
  465. else if(coordinates->xValue > PINNACLE_X_UPPER)
  466. {
  467. coordinates->xValue = PINNACLE_X_UPPER;
  468. }
  469. if(coordinates->yValue < PINNACLE_Y_LOWER)
  470. {
  471. coordinates->yValue = PINNACLE_Y_LOWER;
  472. }
  473. else if(coordinates->yValue > PINNACLE_Y_UPPER)
  474. {
  475. coordinates->yValue = PINNACLE_Y_UPPER;
  476. }
  477. }
  478.  
  479. // Scales data to desired X & Y resolution
  480. void ScaleData(absData_t * coordinates, uint16_t xResolution, uint16_t yResolution)
  481. {
  482. uint32_t xTemp = 0;
  483. uint32_t yTemp = 0;
  484.  
  485. ClipCoordinates(coordinates);
  486.  
  487. xTemp = coordinates->xValue;
  488. yTemp = coordinates->yValue;
  489.  
  490. // translate coordinates to (0, 0) reference by subtracting edge-offset
  491. xTemp -= PINNACLE_X_LOWER;
  492. yTemp -= PINNACLE_Y_LOWER;
  493.  
  494. // scale coordinates to (xResolution, yResolution) range
  495. coordinates->xValue = (uint16_t)(xTemp * xResolution / PINNACLE_X_RANGE);
  496. coordinates->yValue = (uint16_t)(yTemp * yResolution / PINNACLE_Y_RANGE);
  497. }
  498.  
  499. /* I/O Functions */
  500. void Assert_CS()
  501. {
  502. digitalWrite(CS_PIN, LOW);
  503. }
  504.  
  505. void DeAssert_CS()
  506. {
  507. digitalWrite(CS_PIN, HIGH);
  508. }
  509.  
  510. void AssertSensorLED(bool state)
  511. {
  512. digitalWrite(LED_0, !state);
  513. }
  514.  
  515. bool DR_Asserted()
  516. {
  517. return digitalRead(DR_PIN);
  518. }
  519.  
Advertisement
Add Comment
Please, Sign In to add comment