Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // DWARFKINGKILI Current Project Prototype - JANUARY 2024
- // *This project has been built with modified code from Cirque Corp
- // Copyright (c) 2018 Cirque Corp. Restrictions apply. See: www.cirque.com/sw-license
- #include <SPI.h>
- #include <Arduino.h>
- #include <BleGamepad.h>
- // This device is currently built to operate with a ESP32.
- // It can easily be adapted to work with other Arduino-based systems.
- // This device is using a Cirque TM0XX0XX trackpad with a Curved Overlay.
- // A 12 pin FFC cable, A 12 pin 0.5mm Ribbon adapter, Jumper cables, and the ESP32
- // This application connects to a TM0XX0XX circular trackpad via SPI. To verify that
- // your trackpad is configured for SPI-mode, make sure that R1 is populated with a
- // 470k resistor (or whichever resitor connects pins 24 & 25 of the 1CA027 IC).
- // NOTE: To eliminate any confusion in the hookup process I've listed below the old
- // and new terminology. For example MISO (OLD) = CIPO (NEW). Depending on when you
- // started to code, this may be useful
- // NOTE: Additionally I've color coded the wires to aid in your hookup process.
- // The TM0XX0XX circular trackpad is configured for Relative mode tracking.
- //Pinnacle TM0XX0XX with Arduino
- //Touchpad -> 12 Pin FFC cable -> Adapeter -> Jumper cables -> ESP32
- //12 pin 0.5mm Ribbon Adapter
- //Pin 1 SCK (SPI clock line) (Green)
- //Pin 2 MISO (SPI Master Input Slave Output) (Red)
- //Pin 3 SS (Slave Select (AKA Chip Select)) (Brown)
- //Pin 4 DR (Data Ready interrupt) (Orange)
- //Pin 5 MOSI (SPI Master Output Slave Input) (White)
- //Pin 6 BTN2 (Hardware input button #2)
- //Pin 7 BTN3 (Hardware input button #3)
- //Pin 8 BTN1 (Hardware input button #1)
- //Pin 9 SCL (I2C clock line)
- //Pin 10 SDA (I2C data line)
- //Pin 11 GND (Ground) (Yellow)
- //Pin 12 VDD (3V power supply) (Blue)
- // Hardware pin-number labels
- #define SCK_PIN 18 //Clock
- #define DIN_PIN 19 //Miso
- #define DOUT_PIN 23 //Mosi
- #define CS_PIN 5 //Slave Select
- #define DR_PIN 22 //DataReady
- #define SDA_PIN 42
- #define SCL_PIN 39
- #define LED_0 21
- #define LED_1 20
- // Masks for Cirque Register Access Protocol (RAP)
- #define WRITE_MASK 0x80
- #define READ_MASK 0xA0
- // Register config values for this demo
- #define SYSCONFIG_1 0x00
- #define FEEDCONFIG_1 0x83 //Inverted Axis
- #define FEEDCONFIG_2 0x06
- #define Z_IDLE_COUNT 0x05
- // Coordinate scaling values
- #define PINNACLE_XMAX 2047 // max value Pinnacle can report for X (0 to (8 * 256) -1)
- #define PINNACLE_YMAX 1535 // max value Pinnacle can report for Y (0 to (6 * 256) -1)
- #define PINNACLE_X_LOWER 511 // min "reachable" X value
- #define PINNACLE_X_UPPER 1535 // max "reachable" X value
- #define PINNACLE_Y_LOWER 226 // min "reachable" Y value
- #define PINNACLE_Y_UPPER 1250 // max "reachable" Y value
- #define PINNACLE_X_RANGE (PINNACLE_X_UPPER-PINNACLE_X_LOWER)
- #define PINNACLE_Y_RANGE (PINNACLE_Y_UPPER-PINNACLE_Y_LOWER)
- #define ZONESCALE 256 // divisor for reducing x,y values to an array index for the LUT
- #define ROWS_Y ((PINNACLE_YMAX + 1) / ZONESCALE)
- #define COLS_X ((PINNACLE_XMAX + 1) / ZONESCALE)
- // ADC-attenuation settings (held in BIT_7 and BIT_6)
- // 1X = most sensitive, 4X = least sensitive
- #define ADC_ATTENUATE_1X 0x00
- #define ADC_ATTENUATE_2X 0x40
- #define ADC_ATTENUATE_3X 0x80
- #define ADC_ATTENUATE_4X 0xC0
- // Convenient way to store and access measurements
- typedef struct _absData
- {
- uint16_t xValue;
- uint16_t yValue;
- uint16_t zValue;
- uint8_t buttonFlags;
- bool touchDown;
- bool hovering;
- } absData_t;
- absData_t touchData;
- //const uint16_t ZONESCALE = 256;
- //const uint16_t ROWS_Y = 6;
- //const uint16_t COLS_X = 8;
- // These values require tuning for optimal touch-response
- // Each element represents the Z-value below which is considered "hovering" in that XY region of the sensor.
- // The values present are not guaranteed to work for all HW configurations.
- const uint8_t ZVALUE_MAP[ROWS_Y][COLS_X] =
- {
- {5, 5, 5, 5, 5, 5, 5, 5},
- {5, 5, 5, 5, 5, 5, 5, 5},
- {5, 5, 5, 15, 15, 5, 5, 5},
- {5, 5, 5, 15, 15, 5, 5, 5},
- {5, 5, 5, 5, 5, 5, 5, 5},
- {5, 5, 5, 5, 5, 5, 5, 5},
- };
- BleGamepad bleGamepad("ESP32 BLE JOYSTICK", "DWARFKINGKILI", 100);
- BleGamepadConfiguration bleGamepadConfig; // Create a BleGamepadConfiguration object to store all of the options
- const int numberOfPotSamples = 64;
- // Number of pot samples to take (to smooth the values)
- const int delayBetweenSamples = 1;
- // Delay in milliseconds between pot samples
- const int delayBetweenHIDReports = 2;
- // Additional delay in milliseconds between HID reports
- const int debounceDelay = 10;
- // Delay in milliseconds between button press
- // setup() gets called once at power-up, sets up serial debug output and Cirque's Pinnacle ASIC.
- void setup()
- {
- Serial.begin(115200);
- bleGamepadConfig.setControllerType(CONTROLLER_TYPE_GAMEPAD); // CONTROLLER_TYPE_JOYSTICK, CONTROLLER_TYPE_GAMEPAD (DEFAULT), CONTROLLER_TYPE_MULTI_AXIS
- analogReadResolution(12);
- // Sets the sample bits and read resolution, default is 12-bit (0 - 4095), range is 9 - 12 bits
- analogSetWidth(12);
- // Sets the sample bits and read resolution, default is 12-bit (0 - 4095), range is 9 - 12 bits
- // 9-bit gives an ADC range of 0-511
- // 10-bit gives an ADC range of 0-1023
- // 11-bit gives an ADC range of 0-2047
- // 12-bit gives an ADC range of 0-4095
- analogSetAttenuation(ADC_11db);
- // Sets the input attenuation for ALL ADC inputs, default is ADC_11db, range is ADC_0db, ADC_2_5db, ADC_6db, ADC_11db
- // ADC_0db provides no attenuation so IN/OUT = 1 / 1 an input of 3 volts remains at 3 volts before ADC measurement
- // 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
- // 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
- // 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
- analogSetClockDiv(255);
- // Set the divider for the ADC clock, default is 1, range is 1 - 255
- Serial.println("Starting BLE Joystick!");
- bleGamepad.begin(&bleGamepadConfig); // Begin gamepad with configuration options
- pinMode(LED_0, OUTPUT);
- Pinnacle_Init();
- // These functions are required for use with thick overlays (curved)
- setAdcAttenuation(ADC_ATTENUATE_1X);
- tuneEdgeSensitivity();
- Serial.println();
- Serial.println("X\tY\tZ\tBtn\tData");
- Pinnacle_EnableFeed(true);
- }
- // loop() continuously checks to see if data-ready (DR) is high. If so, reads and reports touch data to terminal.
- void loop()
- {
- if(DR_Asserted())
- {
- Pinnacle_GetAbsolute(&touchData);
- Pinnacle_CheckValidTouch(&touchData); // Checks for "hover" caused by curved overlays
- if (touchData.touchDown)
- ScaleData(&touchData, 32767, 32767); // Scale coordinates to arbitrary X, Y resolution
- else{
- touchData.xValue = 32767/2; //Joystick range divisible to center stick, Maintain value 3.5
- touchData.yValue = 32767/2; //Joystick range divsiible to center stick, Maintain value 2.75
- }
- bleGamepad.setX(touchData.xValue);
- bleGamepad.setY(touchData.yValue);
- Serial.print(touchData.xValue);
- Serial.print('\t');
- Serial.print(touchData.yValue);
- Serial.print('\t');
- Serial.print(touchData.zValue);
- Serial.print('\t');
- Serial.print(touchData.buttonFlags);
- Serial.print('\t');
- if(Pinnacle_zIdlePacket(&touchData))
- {
- Serial.println("liftoff");
- }
- else if(touchData.hovering)
- {
- Serial.println("hovering");
- }
- else
- {
- Serial.println("valid");
- }
- }
- AssertSensorLED(touchData.touchDown);
- }
- /* Pinnacle-based TM0XX0XX Functions */
- void Pinnacle_Init()
- {
- RAP_Init();
- DeAssert_CS();
- pinMode(DR_PIN, INPUT);
- // Host clears SW_CC flag
- Pinnacle_ClearFlags();
- // Host configures bits of registers 0x03 and 0x05
- RAP_Write(0x03, SYSCONFIG_1);
- RAP_Write(0x05, FEEDCONFIG_2);
- // Host enables preferred output mode (absolute)
- RAP_Write(0x04, FEEDCONFIG_1);
- // Host sets z-idle packet count to 5 (default is 30)
- RAP_Write(0x0A, Z_IDLE_COUNT);
- Serial.println("Pinnacle Initialized...");
- }
- // Reads XYZ data from Pinnacle registers 0x14 through 0x17
- // Stores result in absData_t struct with xValue, yValue, and zValue members
- void Pinnacle_GetAbsolute(absData_t * result)
- {
- uint8_t data[6] = { 0,0,0,0,0,0 };
- RAP_ReadBytes(0x12, data, 6);
- Pinnacle_ClearFlags();
- result->buttonFlags = data[0] & 0x3F;
- result->xValue = data[2] | ((data[4] & 0x0F) << 8);
- result->yValue = data[3] | ((data[4] & 0xF0) << 4);
- result->zValue = data[5] & 0x3F;
- result->touchDown = result->xValue != 0;
- }
- // Checks touch data to see if it is a z-idle packet (all zeros)
- bool Pinnacle_zIdlePacket(absData_t * data)
- {
- return data->xValue == 0 && data->yValue == 0 && data->zValue == 0;
- }
- // Clears Status1 register flags (SW_CC and SW_DR)
- void Pinnacle_ClearFlags()
- {
- RAP_Write(0x02, 0x00);
- delayMicroseconds(50);
- }
- // Enables/Disables the feed
- void Pinnacle_EnableFeed(bool feedEnable)
- {
- uint8_t temp;
- RAP_ReadBytes(0x04, &temp, 1); // Store contents of FeedConfig1 register
- if(feedEnable)
- {
- temp |= 0x01; // Set Feed Enable bit
- RAP_Write(0x04, temp);
- }
- else
- {
- temp &= ~0x01; // Clear Feed Enable bit
- RAP_Write(0x04, temp);
- }
- }
- /* Curved Overlay Functions */
- // Adjusts the feedback in the ADC, effectively attenuating the finger signal
- // By default, the the signal is maximally attenuated (ADC_ATTENUATE_4X for use with thin, flat overlays
- void setAdcAttenuation(uint8_t adcGain)
- {
- uint8_t temp = 0x00;
- Serial.println();
- Serial.println("Setting ADC gain...");
- ERA_ReadBytes(0x0187, &temp, 1);
- temp &= 0x3F; // clear top two bits
- temp |= adcGain;
- ERA_WriteByte(0x0187, temp);
- ERA_ReadBytes(0x0187, &temp, 1);
- Serial.print("ADC gain set to:\t");
- Serial.print(temp &= 0xC0, HEX);
- switch(temp)
- {
- case ADC_ATTENUATE_1X:
- Serial.println(" (X/1)");
- break;
- case ADC_ATTENUATE_2X:
- Serial.println(" (X/2)");
- break;
- case ADC_ATTENUATE_3X:
- Serial.println(" (X/3)");
- break;
- case ADC_ATTENUATE_4X:
- Serial.println(" (X/4)");
- break;
- default:
- break;
- }
- }
- // Changes thresholds to improve detection of fingers
- void tuneEdgeSensitivity()
- {
- uint8_t temp = 0x00;
- Serial.println();
- Serial.println("Setting xAxis.WideZMin...");
- ERA_ReadBytes(0x0149, &temp, 1);
- Serial.print("Current value:\t");
- Serial.println(temp, HEX);
- ERA_WriteByte(0x0149, 0x04);
- ERA_ReadBytes(0x0149, &temp, 1);
- Serial.print("New value:\t");
- Serial.println(temp, HEX);
- Serial.println();
- Serial.println("Setting yAxis.WideZMin...");
- ERA_ReadBytes(0x0168, &temp, 1);
- Serial.print("Current value:\t");
- Serial.println(temp, HEX);
- ERA_WriteByte(0x0168, 0x03);
- ERA_ReadBytes(0x0168, &temp, 1);
- Serial.print("New value:\t");
- Serial.println(temp, HEX);
- }
- // This function identifies when a finger is "hovering" so your system can choose to ignore them.
- // Explanation: Consider the response of the sensor to be flat across it's area. The Z-sensitivity of the sensor projects this area
- // a short distance upwards above the surface of the sensor. Imagine it is a solid cylinder (wider than it is tall)
- // 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
- // on the perimeter. If the sensitivity is tuned such that the sensing area projects to the highest part of the overlay, the lowest
- // 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.
- // 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.
- // 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).
- void Pinnacle_CheckValidTouch(absData_t * touchData)
- {
- uint32_t zone_x, zone_y;
- //eliminate hovering
- zone_x = touchData->xValue / ZONESCALE;
- zone_y = touchData->yValue / ZONESCALE;
- touchData->hovering = !(touchData->zValue > ZVALUE_MAP[zone_y][zone_x]);
- }
- /* ERA (Extended Register Access) Functions */
- // Reads <count> bytes from an extended register at <address> (16-bit address),
- // stores values in <*data>
- void ERA_ReadBytes(uint16_t address, uint8_t * data, uint16_t count)
- {
- uint8_t ERAControlValue = 0xFF;
- Pinnacle_EnableFeed(false); // Disable feed
- RAP_Write(0x1C, (uint8_t)(address >> 8)); // Send upper byte of ERA address
- RAP_Write(0x1D, (uint8_t)(address & 0x00FF)); // Send lower byte of ERA address
- for(uint16_t i = 0; i < count; i++)
- {
- RAP_Write(0x1E, 0x05); // Signal ERA-read (auto-increment) to Pinnacle
- // Wait for status register 0x1E to clear
- do
- {
- RAP_ReadBytes(0x1E, &ERAControlValue, 1);
- } while(ERAControlValue != 0x00);
- RAP_ReadBytes(0x1B, data + i, 1);
- Pinnacle_ClearFlags();
- }
- }
- // Writes a byte, <data>, to an extended register at <address> (16-bit address)
- void ERA_WriteByte(uint16_t address, uint8_t data)
- {
- uint8_t ERAControlValue = 0xFF;
- Pinnacle_EnableFeed(false); // Disable feed
- RAP_Write(0x1B, data); // Send data byte to be written
- RAP_Write(0x1C, (uint8_t)(address >> 8)); // Upper byte of ERA address
- RAP_Write(0x1D, (uint8_t)(address & 0x00FF)); // Lower byte of ERA address
- RAP_Write(0x1E, 0x02); // Signal an ERA-write to Pinnacle
- // Wait for status register 0x1E to clear
- do
- {
- RAP_ReadBytes(0x1E, &ERAControlValue, 1);
- } while(ERAControlValue != 0x00);
- Pinnacle_ClearFlags();
- }
- /* RAP Functions */
- void RAP_Init()
- {
- pinMode(CS_PIN, OUTPUT);
- SPI.begin();
- }
- // Reads <count> Pinnacle registers starting at <address>
- void RAP_ReadBytes(byte address, byte * data, byte count)
- {
- byte cmdByte = READ_MASK | address; // Form the READ command byte
- SPI.beginTransaction(SPISettings(20000000, MSBFIRST, SPI_MODE1));
- Assert_CS();
- SPI.transfer(cmdByte); // Signal a RAP-read operation starting at <address>
- SPI.transfer(0xFC); // Filler byte
- SPI.transfer(0xFC); // Filler byte
- for(byte i = 0; i < count; i++)
- {
- data[i] = SPI.transfer(0xFC); // Each subsequent SPI transfer gets another register's contents
- }
- DeAssert_CS();
- SPI.endTransaction();
- }
- // Writes single-byte <data> to <address>
- void RAP_Write(byte address, byte data)
- {
- byte cmdByte = WRITE_MASK | address; // Form the WRITE command byte
- SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE1));
- Assert_CS();
- SPI.transfer(cmdByte); // Signal a write to register at <address>
- SPI.transfer(data); // Send <value> to be written to register
- DeAssert_CS();
- SPI.endTransaction();
- }
- /* Logical Scaling Functions */
- // Clips raw coordinates to "reachable" window of sensor
- // NOTE: values outside this window can only appear as a result of noise
- void ClipCoordinates(absData_t * coordinates)
- {
- if(coordinates->xValue < PINNACLE_X_LOWER)
- {
- coordinates->xValue = PINNACLE_X_LOWER;
- }
- else if(coordinates->xValue > PINNACLE_X_UPPER)
- {
- coordinates->xValue = PINNACLE_X_UPPER;
- }
- if(coordinates->yValue < PINNACLE_Y_LOWER)
- {
- coordinates->yValue = PINNACLE_Y_LOWER;
- }
- else if(coordinates->yValue > PINNACLE_Y_UPPER)
- {
- coordinates->yValue = PINNACLE_Y_UPPER;
- }
- }
- // Scales data to desired X & Y resolution
- void ScaleData(absData_t * coordinates, uint16_t xResolution, uint16_t yResolution)
- {
- uint32_t xTemp = 0;
- uint32_t yTemp = 0;
- ClipCoordinates(coordinates);
- xTemp = coordinates->xValue;
- yTemp = coordinates->yValue;
- // translate coordinates to (0, 0) reference by subtracting edge-offset
- xTemp -= PINNACLE_X_LOWER;
- yTemp -= PINNACLE_Y_LOWER;
- // scale coordinates to (xResolution, yResolution) range
- coordinates->xValue = (uint16_t)(xTemp * xResolution / PINNACLE_X_RANGE);
- coordinates->yValue = (uint16_t)(yTemp * yResolution / PINNACLE_Y_RANGE);
- }
- /* I/O Functions */
- void Assert_CS()
- {
- digitalWrite(CS_PIN, LOW);
- }
- void DeAssert_CS()
- {
- digitalWrite(CS_PIN, HIGH);
- }
- void AssertSensorLED(bool state)
- {
- digitalWrite(LED_0, !state);
- }
- bool DR_Asserted()
- {
- return digitalRead(DR_PIN);
- }
Advertisement
Add Comment
Please, Sign In to add comment