xWAFFELx

cirque touchpad esp32 ble mouse

Feb 16th, 2021 (edited)
435
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Arduino 14.76 KB | None | 0 0
  1. // Copyright (c) 2018 Cirque Corp. Restrictions apply. See: www.cirque.com/sw-license
  2.  
  3. #include <SPI.h>
  4. #include <BleMouse.h>
  5.  
  6. // ___ Using a Cirque TM0XX0XX w/ Curved Overlay and Arduino ___
  7. // This demonstration application is built to work with a Teensy 3.1/3.2 but it can easily be adapted to
  8. // work with Arduino-based systems.
  9. // When using with DK000013 development kit, connect sensor to the FFC connector
  10. // labeled 'Sensor0'.
  11. // This application connects to a TM0XX0XX circular touch pad via SPI. To verify that your touch pad is configured
  12. // for SPI-mode, make sure that R1 is populated with a 470k resistor (or whichever resistor connects pins 24 & 25 of the 1CA027 IC).
  13. // The pad is configured for Absolute mode tracking.  Touch data is sent in text format over USB CDC to
  14. // the host PC.  You can open a terminal window on the PC to the USB CDC port and see X, Y, and Z data
  15. // fill the window when you touch the sensor. Tools->Serial Monitor can be used to view touch data.
  16. // NOTE: all config values applied in this sample are meant for a module using REXT = 976kOhm
  17.  
  18. //  Pinnacle TM0XX0XX with Arduino
  19. //  Hardware Interface
  20. //  GND
  21. //  +3.3V
  22. //  SCK = Pin 13
  23. //  MISO = Pin 12
  24. //  MOSI = Pin 11
  25. //  SS = Pin 8
  26. //  DR = Pin 7
  27.  
  28. // Hardware pin-number labels
  29. #define SCK_PIN   18
  30. #define DIN_PIN   19 //miso
  31. #define DOUT_PIN  23 //mosi
  32. #define CS_PIN    2
  33. #define DR_PIN    5
  34.  
  35. #define SDA_PIN   4
  36. #define SCL_PIN   15
  37.  
  38. #define LED_0     21
  39. #define LED_1     20
  40.  
  41. // Masks for Cirque Register Access Protocol (RAP)
  42. #define WRITE_MASK  0x80
  43. #define READ_MASK   0xA0
  44.  
  45. // Register config values for this demo
  46. #define SYSCONFIG_1   0x00
  47. //#define FEEDCONFIG_1  0x03 //absolute
  48. #define FEEDCONFIG_1  0x41 //relative, x-inverted
  49. #define FEEDCONFIG_2  0x1F
  50. #define Z_IDLE_COUNT  0x05
  51.  
  52. // Coordinate scaling values
  53. #define PINNACLE_XMAX     2047    // max value Pinnacle can report for X
  54. #define PINNACLE_YMAX     1535    // max value Pinnacle can report for Y
  55. #define PINNACLE_X_LOWER  127     // min "reachable" X value
  56. #define PINNACLE_X_UPPER  1919    // max "reachable" X value
  57. #define PINNACLE_Y_LOWER  63      // min "reachable" Y value
  58. #define PINNACLE_Y_UPPER  1471    // max "reachable" Y value
  59. #define PINNACLE_X_RANGE  (PINNACLE_X_UPPER-PINNACLE_X_LOWER)
  60. #define PINNACLE_Y_RANGE  (PINNACLE_Y_UPPER-PINNACLE_Y_LOWER)
  61. #define ZONESCALE 256   // divisor for reducing x,y values to an array index for the LUT
  62. #define ROWS_Y ((PINNACLE_YMAX + 1) / ZONESCALE)
  63. #define COLS_X ((PINNACLE_XMAX + 1) / ZONESCALE)
  64.  
  65. // ADC-attenuation settings (held in BIT_7 and BIT_6)
  66. // 1X = most sensitive, 4X = least sensitive
  67. #define ADC_ATTENUATE_1X   0x00
  68. #define ADC_ATTENUATE_2X   0x40
  69. #define ADC_ATTENUATE_3X   0x80
  70. #define ADC_ATTENUATE_4X   0xC0
  71.  
  72. // Convenient way to store and access measurements
  73. typedef struct _absData
  74. {
  75.   uint16_t xValue;
  76.   uint16_t yValue;
  77.   uint16_t zValue;
  78.   uint8_t buttonFlags;
  79.   bool touchDown;
  80.   bool hovering;
  81. } absData_t;
  82.  
  83. typedef struct _relData
  84. {
  85.   uint8_t buttons;
  86.   int8_t xDelta;
  87.   int8_t yDelta;
  88.   int8_t wheelCount;
  89. } relData_t;
  90.  
  91. absData_t touchData;
  92. relData_t relativeData;
  93.  
  94. //const uint16_t ZONESCALE = 256;
  95. //const uint16_t ROWS_Y = 6;
  96. //const uint16_t COLS_X = 8;
  97.  
  98. // These values require tuning for optimal touch-response
  99. // Each element represents the Z-value below which is considered "hovering" in that XY region of the sensor.
  100. // The values present are not guaranteed to work for all HW configurations.
  101. const uint8_t ZVALUE_MAP[ROWS_Y][COLS_X] =
  102. {
  103.   {0, 0,  0,  0,  0,  0, 0, 0},
  104.   {0, 2,  3,  5,  5,  3, 2, 0},
  105.   {0, 3,  5, 15, 15,  5, 2, 0},
  106.   {0, 3,  5, 15, 15,  5, 3, 0},
  107.   {0, 2,  3,  5,  5,  3, 2, 0},
  108.   {0, 0,  0,  0,  0,  0, 0, 0},
  109. };
  110.  
  111.  
  112. BleMouse bleMouse;
  113.  
  114.  
  115. // setup() gets called once at power-up, sets up serial debug output and Cirque's Pinnacle ASIC.
  116. void setup()
  117. {
  118.   Serial.begin(115200);
  119.   while(!Serial); // needed for USB
  120.   bleMouse.begin();
  121.  
  122.   pinMode(LED_0, OUTPUT);
  123.  
  124.   Pinnacle_Init();
  125.  
  126.   // These functions are required for use with thick overlays (curved)
  127.   setAdcAttenuation(ADC_ATTENUATE_1X);
  128.   tuneEdgeSensitivity();
  129.  
  130.   Serial.println();
  131.   Serial.println("X\tY\tZ\tBtn\tData");
  132.   Pinnacle_EnableFeed(true);
  133. }
  134.  
  135. // loop() continuously checks to see if data-ready (DR) is high. If so, reads and reports touch data to terminal.
  136. void loop()
  137. {
  138.   if(DR_Asserted())
  139.   {
  140.     //Pinnacle_GetAbsolute(&touchData);
  141.     //Pinnacle_CheckValidTouch(&touchData);     // Checks for "hover" caused by curved overlays
  142.     Pinnacle_getRelative(&relativeData);
  143. //    ScaleData(&touchData, 1024, 1024);      // Scale coordinates to arbitrary X, Y resolution
  144.  
  145.     bleMouse.move(relativeData.xDelta,relativeData.yDelta);
  146.     Serial.print("X ");
  147.     Serial.print(relativeData.xDelta);
  148.     Serial.print('\t');
  149.     Serial.print("Y ");
  150.     Serial.print(relativeData.yDelta);
  151.     Serial.print('\t');
  152.     Serial.println("valid");
  153. //    Serial.print(touchData.xValue);
  154. //    Serial.print('\t');
  155. //    Serial.print(touchData.yValue);
  156. //    Serial.print('\t');
  157. //    Serial.print(touchData.zValue);
  158. //    Serial.print('\t');
  159. //    Serial.print(touchData.buttonFlags);
  160. //    Serial.print('\t');
  161. //    if(Pinnacle_zIdlePacket(&touchData))
  162. //    {
  163. //      Serial.println("liftoff");
  164. //    }
  165. //    else if(touchData.hovering)
  166. //    {
  167. //      Serial.println("hovering");
  168. //    }
  169. //    else
  170. //    {
  171. //      Serial.println("valid");
  172. //    }
  173.   }
  174.   AssertSensorLED(touchData.touchDown);
  175. }
  176.  
  177. /*  Pinnacle-based TM0XX0XX Functions  */
  178. void Pinnacle_Init()
  179. {
  180.   RAP_Init();
  181.   DeAssert_CS();
  182.   pinMode(DR_PIN, INPUT);
  183.  
  184.   // Host clears SW_CC flag
  185.   Pinnacle_ClearFlags();
  186.  
  187.   // Host configures bits of registers 0x03 and 0x05
  188.   RAP_Write(0x03, SYSCONFIG_1);
  189.   RAP_Write(0x05, FEEDCONFIG_2);
  190.  
  191.   // Host enables preferred output mode (absolute)
  192.   RAP_Write(0x04, FEEDCONFIG_1);
  193.  
  194.   // Host sets z-idle packet count to 5 (default is 30)
  195.   RAP_Write(0x0A, Z_IDLE_COUNT);
  196.   Serial.println("Pinnacle Initialized...");
  197. }
  198.  
  199. // Reads XYZ data from Pinnacle registers 0x14 through 0x17
  200. // Stores result in absData_t struct with xValue, yValue, and zValue members
  201. void Pinnacle_GetAbsolute(absData_t * result)
  202. {
  203.   uint8_t data[6] = { 0,0,0,0,0,0 };
  204.   RAP_ReadBytes(0x12, data, 6);
  205.  
  206.   Pinnacle_ClearFlags();
  207.  
  208.   result->buttonFlags = data[0] & 0x3F;
  209.   result->xValue = data[2] | ((data[4] & 0x0F) << 8);
  210.   result->yValue = data[3] | ((data[4] & 0xF0) << 4);
  211.   result->zValue = data[5] & 0x3F;
  212.  
  213.   result->touchDown = result->xValue != 0;
  214. }
  215.  
  216. // Reads X, Y, and Scroll-Wheel deltas from Pinnacle, as well as button states
  217. // NOTE: this function should be called immediately after DR is asserted (HIGH)
  218. void Pinnacle_getRelative(relData_t * result)
  219. {
  220.   uint8_t data[4] = { 0,0,0,0 };
  221.   RAP_ReadBytes(0x12, data, 4);
  222.  
  223.   Pinnacle_ClearFlags();
  224.  
  225.   result->buttons = data[0] & 0x07;
  226.   result->xDelta = (int8_t)data[1];
  227.   result->yDelta = (int8_t)data[2];
  228.   result->wheelCount = (int8_t)data[3];
  229. }
  230.  
  231. // Checks touch data to see if it is a z-idle packet (all zeros)
  232. bool Pinnacle_zIdlePacket(absData_t * data)
  233. {
  234.   return data->xValue == 0 && data->yValue == 0 && data->zValue == 0;
  235. }
  236.  
  237. // Clears Status1 register flags (SW_CC and SW_DR)
  238. void Pinnacle_ClearFlags()
  239. {
  240.   RAP_Write(0x02, 0x00);
  241.   delayMicroseconds(50);
  242. }
  243.  
  244. // Enables/Disables the feed
  245. void Pinnacle_EnableFeed(bool feedEnable)
  246. {
  247.   uint8_t temp;
  248.  
  249.   RAP_ReadBytes(0x04, &temp, 1);  // Store contents of FeedConfig1 register
  250.  
  251.   if(feedEnable)
  252.   {
  253.     temp |= 0x01;                 // Set Feed Enable bit
  254.     RAP_Write(0x04, temp);
  255.   }
  256.   else
  257.   {
  258.     temp &= ~0x01;                // Clear Feed Enable bit
  259.     RAP_Write(0x04, temp);
  260.   }
  261. }
  262.  
  263.  
  264. /*  Curved Overlay Functions  */
  265. // Adjusts the feedback in the ADC, effectively attenuating the finger signal
  266. // By default, the the signal is maximally attenuated (ADC_ATTENUATE_4X for use with thin, flat overlays
  267. void setAdcAttenuation(uint8_t adcGain)
  268. {
  269.   uint8_t temp = 0x00;
  270.  
  271.   Serial.println();
  272.   Serial.println("Setting ADC gain...");
  273.   ERA_ReadBytes(0x0187, &temp, 1);
  274.   temp &= 0x3F; // clear top two bits
  275.   temp |= adcGain;
  276.   ERA_WriteByte(0x0187, temp);
  277.   ERA_ReadBytes(0x0187, &temp, 1);
  278.   Serial.print("ADC gain set to:\t");
  279.   Serial.print(temp &= 0xC0, HEX);
  280.   switch(temp)
  281.   {
  282.     case ADC_ATTENUATE_1X:
  283.       Serial.println(" (X/1)");
  284.       break;
  285.     case ADC_ATTENUATE_2X:
  286.       Serial.println(" (X/2)");
  287.       break;
  288.     case ADC_ATTENUATE_3X:
  289.       Serial.println(" (X/3)");
  290.       break;
  291.     case ADC_ATTENUATE_4X:
  292.       Serial.println(" (X/4)");
  293.       break;
  294.     default:
  295.       break;
  296.   }
  297. }
  298.  
  299. // Changes thresholds to improve detection of fingers
  300. void tuneEdgeSensitivity()
  301. {
  302.   uint8_t temp = 0x00;
  303.  
  304.   Serial.println();
  305.   Serial.println("Setting xAxis.WideZMin...");
  306.   ERA_ReadBytes(0x0149, &temp, 1);
  307.   Serial.print("Current value:\t");
  308.   Serial.println(temp, HEX);
  309.   ERA_WriteByte(0x0149,  0x04);
  310.   ERA_ReadBytes(0x0149, &temp, 1);
  311.   Serial.print("New value:\t");
  312.   Serial.println(temp, HEX);
  313.  
  314.   Serial.println();
  315.   Serial.println("Setting yAxis.WideZMin...");
  316.   ERA_ReadBytes(0x0168, &temp, 1);
  317.   Serial.print("Current value:\t");
  318.   Serial.println(temp, HEX);
  319.   ERA_WriteByte(0x0168,  0x03);
  320.   ERA_ReadBytes(0x0168, &temp, 1);
  321.   Serial.print("New value:\t");
  322.   Serial.println(temp, HEX);
  323. }
  324.  
  325. // This function identifies when a finger is "hovering" so your system can choose to ignore them.
  326. // Explanation: Consider the response of the sensor to be flat across it's area. The Z-sensitivity of the sensor projects this area
  327. // a short distance upwards above the surface of the sensor. Imagine it is a solid cylinder (wider than it is tall)
  328. // 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
  329. // on the perimeter. If the sensitivity is tuned such that the sensing area projects to the highest part of the overlay, the lowest
  330. // 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.
  331. // 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.
  332. // 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).
  333. void Pinnacle_CheckValidTouch(absData_t * touchData)
  334. {
  335.   uint32_t zone_x, zone_y;
  336.   //eliminate hovering
  337.   zone_x = touchData->xValue / ZONESCALE;
  338.   zone_y = touchData->yValue / ZONESCALE;
  339.   touchData->hovering = !(touchData->zValue > ZVALUE_MAP[zone_y][zone_x]);
  340. }
  341.  
  342. /*  ERA (Extended Register Access) Functions  */
  343. // Reads <count> bytes from an extended register at <address> (16-bit address),
  344. // stores values in <*data>
  345. void ERA_ReadBytes(uint16_t address, uint8_t * data, uint16_t count)
  346. {
  347.   uint8_t ERAControlValue = 0xFF;
  348.  
  349.   Pinnacle_EnableFeed(false); // Disable feed
  350.  
  351.   RAP_Write(0x1C, (uint8_t)(address >> 8));     // Send upper byte of ERA address
  352.   RAP_Write(0x1D, (uint8_t)(address & 0x00FF)); // Send lower byte of ERA address
  353.  
  354.   for(uint16_t i = 0; i < count; i++)
  355.   {
  356.     RAP_Write(0x1E, 0x05);  // Signal ERA-read (auto-increment) to Pinnacle
  357.  
  358.     // Wait for status register 0x1E to clear
  359.     do
  360.     {
  361.       RAP_ReadBytes(0x1E, &ERAControlValue, 1);
  362.     } while(ERAControlValue != 0x00);
  363.  
  364.     RAP_ReadBytes(0x1B, data + i, 1);
  365.  
  366.     Pinnacle_ClearFlags();
  367.   }
  368. }
  369.  
  370. // Writes a byte, <data>, to an extended register at <address> (16-bit address)
  371. void ERA_WriteByte(uint16_t address, uint8_t data)
  372. {
  373.   uint8_t ERAControlValue = 0xFF;
  374.  
  375.   Pinnacle_EnableFeed(false); // Disable feed
  376.  
  377.   RAP_Write(0x1B, data);      // Send data byte to be written
  378.  
  379.   RAP_Write(0x1C, (uint8_t)(address >> 8));     // Upper byte of ERA address
  380.   RAP_Write(0x1D, (uint8_t)(address & 0x00FF)); // Lower byte of ERA address
  381.  
  382.   RAP_Write(0x1E, 0x02);  // Signal an ERA-write to Pinnacle
  383.  
  384.   // Wait for status register 0x1E to clear
  385.   do
  386.   {
  387.     RAP_ReadBytes(0x1E, &ERAControlValue, 1);
  388.   } while(ERAControlValue != 0x00);
  389.  
  390.   Pinnacle_ClearFlags();
  391. }
  392.  
  393. /*  RAP Functions */
  394.  
  395. void RAP_Init()
  396. {
  397.   pinMode(CS_PIN, OUTPUT);
  398.   SPI.begin();
  399. }
  400.  
  401. // Reads <count> Pinnacle registers starting at <address>
  402. void RAP_ReadBytes(byte address, byte * data, byte count)
  403. {
  404.   byte cmdByte = READ_MASK | address;   // Form the READ command byte
  405.  
  406.   SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE1));
  407.  
  408.   Assert_CS();
  409.   SPI.transfer(cmdByte);  // Signal a RAP-read operation starting at <address>
  410.   SPI.transfer(0xFC);     // Filler byte
  411.   SPI.transfer(0xFC);     // Filler byte
  412.   for(byte i = 0; i < count; i++)
  413.   {
  414.     data[i] =  SPI.transfer(0xFC);  // Each subsequent SPI transfer gets another register's contents
  415.   }
  416.   DeAssert_CS();
  417.  
  418.   SPI.endTransaction();
  419. }
  420.  
  421. // Writes single-byte <data> to <address>
  422. void RAP_Write(byte address, byte data)
  423. {
  424.   byte cmdByte = WRITE_MASK | address;  // Form the WRITE command byte
  425.  
  426.   SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE1));
  427.  
  428.   Assert_CS();
  429.   SPI.transfer(cmdByte);  // Signal a write to register at <address>
  430.   SPI.transfer(data);    // Send <value> to be written to register
  431.   DeAssert_CS();
  432.  
  433.   SPI.endTransaction();
  434. }
  435.  
  436. /*  Logical Scaling Functions */
  437. // Clips raw coordinates to "reachable" window of sensor
  438. // NOTE: values outside this window can only appear as a result of noise
  439. void ClipCoordinates(absData_t * coordinates)
  440. {
  441.   if(coordinates->xValue < PINNACLE_X_LOWER)
  442.   {
  443.     coordinates->xValue = PINNACLE_X_LOWER;
  444.   }
  445.   else if(coordinates->xValue > PINNACLE_X_UPPER)
  446.   {
  447.     coordinates->xValue = PINNACLE_X_UPPER;
  448.   }
  449.   if(coordinates->yValue < PINNACLE_Y_LOWER)
  450.   {
  451.     coordinates->yValue = PINNACLE_Y_LOWER;
  452.   }
  453.   else if(coordinates->yValue > PINNACLE_Y_UPPER)
  454.   {
  455.     coordinates->yValue = PINNACLE_Y_UPPER;
  456.   }
  457. }
  458.  
  459. // Scales data to desired X & Y resolution
  460. void ScaleData(absData_t * coordinates, uint16_t xResolution, uint16_t yResolution)
  461. {
  462.   uint32_t xTemp = 0;
  463.   uint32_t yTemp = 0;
  464.  
  465.   ClipCoordinates(coordinates);
  466.  
  467.   xTemp = coordinates->xValue;
  468.   yTemp = coordinates->yValue;
  469.  
  470.   // translate coordinates to (0, 0) reference by subtracting edge-offset
  471.   xTemp -= PINNACLE_X_LOWER;
  472.   yTemp -= PINNACLE_Y_LOWER;
  473.  
  474.   // scale coordinates to (xResolution, yResolution) range
  475.   coordinates->xValue = (uint16_t)(xTemp * xResolution / PINNACLE_X_RANGE);
  476.   coordinates->yValue = (uint16_t)(yTemp * yResolution / PINNACLE_Y_RANGE);
  477. }
  478.  
  479. /*  I/O Functions */
  480. void Assert_CS()
  481. {
  482.   digitalWrite(CS_PIN, LOW);
  483. }
  484.  
  485. void DeAssert_CS()
  486. {
  487.   digitalWrite(CS_PIN, HIGH);
  488. }
  489.  
  490. void AssertSensorLED(bool state)
  491. {
  492.   digitalWrite(LED_0, !state);
  493. }
  494.  
  495. bool DR_Asserted()
  496. {
  497.   return digitalRead(DR_PIN);
  498. }
Add Comment
Please, Sign In to add comment