Examples
Arduino Examples
Relative Mode
Example to output data reports in Relative Mode.
examples/relative_mode/relative_mode.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51 | /*
* This example reads data from the Cirque trackpad in "relative mode" and prints the values.
*
* See documentation at https://cirquepinnacle.rtfd.io/
*/
#include <CirquePinnacle.h>
#define SS_PIN 2
#define DR_PIN 7
PinnacleTouchSPI trackpad(DR_PIN, SS_PIN);
// If using I2C, then use the following line (not the line above)
// PinnacleTouchI2C trackpad(DR_PIN);
// an object to hold data reported by the Cirque trackpad
RelativeReport data;
void setup() {
Serial.begin(115200);
while (!Serial) {
// wait till Serial monitor is opened
}
if (!trackpad.begin()) {
Serial.println(F("Cirque Pinnacle not responding!"));
while (true) {
// hold program in infinite loop
}
}
Serial.println(F("CirquePinnacle/examples/relative_mode"));
trackpad.setDataMode(PINNACLE_RELATIVE);
trackpad.relativeModeConfig(); // uses default config
Serial.println(F("Touch the trackpad to see the data."));
}
void loop() {
if (trackpad.available()) {
trackpad.read(&data);
Serial.print(F("Left:"));
Serial.print(data.buttons & 1);
Serial.print(F(" Right:"));
Serial.print(data.buttons & 2);
Serial.print(F(" Middle:"));
Serial.print(data.buttons & 4);
Serial.print(F("\tX:"));
Serial.print(data.x);
Serial.print(F("\tY:"));
Serial.print(data.y);
Serial.print(F("\tScroll:"));
Serial.println(data.scroll);
}
}
|
Absolute Mode
Example to output data reports in Absolute Mode.
examples/absolute_mode/absolute_mode.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106 | /*
* This example reads data from the Cirque trackpad in "absolute mode" and prints the values.
*
* See documentation at https://cirquepinnacle.rtfd.io/
*/
#include <math.h> // sqrt(), pow(), atan2()
#include <CirquePinnacle.h>
#define SS_PIN 2
#define DR_PIN 7
PinnacleTouchSPI trackpad(DR_PIN, SS_PIN);
// If using I2C, then use the following line (not the line above)
// PinnacleTouchI2C trackpad(DR_PIN);
// an object to hold data reported by the Cirque trackpad
AbsoluteReport data;
void setup() {
Serial.begin(115200);
while (!Serial) {
// wait till Serial monitor is opened
}
if (!trackpad.begin()) {
Serial.println(F("Cirque Pinnacle not responding!"));
while (true) {
// hold program in infinite loop
}
}
Serial.println(F("CirquePinnacle/examples/absolute_mode"));
trackpad.setDataMode(PINNACLE_ABSOLUTE);
trackpad.absoluteModeConfig(1); // set count of z-idle packets to 1
Serial.println(F("\n*** Enter 'M' to measure and print raw data."));
Serial.println(F("*** Enter 'T' to measure and print trigonometric calculations.\n"));
Serial.println(F("Touch the trackpad to see the data."));
}
/*
Showing all the Serial output below will slow down the board's ability to
read() data from the trackpad in a timely manner (resulting in data loss).
Use this compile-time definition to switch between printing
raw data (false) or trigonometry data (true)
*/
bool onlyShowTrigVals = false;
#ifndef M_PI
#define PI M_PI
#else
#define PI 3.14159
#endif
void loop() {
if (trackpad.available()) {
trackpad.read(&data);
// datasheet recommends clamping the axes value to reliable range
if (data.z) { // only clamp values if Z axis is not idle.
data.x = data.x > 1920 ? 1920 : (data.x < 128 ? 128 : data.x); // 128 <= x <= 1920
data.y = data.y > 1472 ? 1472 : (data.y < 64 ? 64 : data.y); // 64 <= y <= 1472
}
if (!onlyShowTrigVals) {
// print raw data from the trackpad
Serial.print(F("B1:"));
Serial.print(data.buttons & 1);
Serial.print(F(" B2:"));
Serial.print(data.buttons & 2);
Serial.print(F(" B3:"));
Serial.print(data.buttons & 4);
Serial.print(F("\tX:"));
Serial.print(data.x);
Serial.print(F("\tY:"));
Serial.print(data.y);
Serial.print(F("\tZ:"));
Serial.println(data.z);
} else {
// print trigonometric data from the trackpad
if (!data.z) { // only compute angle and radius if touching (or near) the sensor
Serial.println(F("Idling"));
} else {
// coordinates assume axes have been clamped to recommended ranges
double coord_x = (int16_t)(data.x) - 960;
double coord_y = (int16_t)(data.y) - 736; // NOTE: y-axis is inverted by default
double radius = sqrt(pow(coord_x, 2) + pow(coord_y, 2));
// angle (in degrees) ranges (-180, 180]
double angle = atan2(coord_y, coord_x) * 180 / PI;
// This Serial output is meant to be compatible with the Arduino IDE Serial Plotter applet.
Serial.print(F("angle:"));
Serial.print(angle);
Serial.print(F(",radius:"));
Serial.println(radius);
}
}
} // end if trackpad.available()
while (Serial.available()) {
char input = Serial.read();
if (input == 't' || input == 'T') {
onlyShowTrigVals = true;
} else if (input == 'm' || input == 'M') {
onlyShowTrigVals = false;
}
}
}
|
AnyMeas Mode
Example to output data reports in AnyMeas Mode.
examples/anymeas_mode/anymeas_mode.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82 | /*
* This example reads data from the Cirque trackpad in "anymeas mode" and prints the values.
*
* See documentation at https://cirquepinnacle.rtfd.io/
*/
#include <CirquePinnacle.h>
#define SS_PIN 2
#define DR_PIN 7
PinnacleTouchSPI trackpad(DR_PIN, SS_PIN);
// If using I2C, then use the following line (not the line above)
// PinnacleTouchI2C trackpad(DR_PIN);
typedef struct _MeasureVector {
uint32_t toggle;
uint32_t polarity;
} measureVector;
measureVector vectorDeterminants[] = {
// toggle , polarity
{ 0x0000FFFF, 0x00000000 }, // toggle all x-axis bits negatively (to 0)
{ 0x0FFF0000, 0x00000000 }, // toggle all y-axis bits negatively (to 0)
{ 0x00FF00FF, 0x000000FF }, // toggle Y0-Y7 negatively (to 0) & X0-X7 positively (to 1)
{ 0x00FF00FF, 0x00FF0000 } // toggle Y0-Y7 positively (to 1) & X0-X7 negatively (to 0)
};
const uint8_t variousVectors_size = sizeof(vectorDeterminants) / sizeof(measureVector);
int16_t compensations[variousVectors_size];
void compensate() {
int16_t value;
int32_t accumulatedValue;
for (uint8_t i = 0; i < variousVectors_size; ++i) {
uint8_t sweep = 0;
accumulatedValue = 0;
while (sweep < 5) // take 5 measurements and average them for a bit lower noise compensation value
{
value = trackpad.measureAdc(vectorDeterminants[i].toggle, vectorDeterminants[i].polarity);
sweep++;
accumulatedValue += value;
}
compensations[i] = accumulatedValue / 5;
Serial.print(F("compensate "));
Serial.print(i);
Serial.print(F(": "));
Serial.println(compensations[i]);
}
}
void setup() {
Serial.begin(115200);
while (!Serial) {
// wait till Serial monitor is opened
}
if (!trackpad.begin()) {
Serial.println(F("Cirque Pinnacle not responding!"));
while (true) {
// hold program in infinite loop
}
}
Serial.println(F("CirquePinnacle/examples/anymeas_mode"));
trackpad.setDataMode(PINNACLE_ANYMEAS);
trackpad.anymeasModeConfig();
compensate();
Serial.println(F("starting in 5 seconds..."));
delay(5000);
}
void loop() {
for (uint8_t i = 0; i < variousVectors_size; i++) {
int16_t measurement = trackpad.measureAdc(vectorDeterminants[i].toggle,
vectorDeterminants[i].polarity);
measurement -= compensations[i];
Serial.print(F("meas"));
Serial.print(i);
Serial.print(F(":"));
Serial.print(measurement);
Serial.print(F(" \t"));
}
Serial.println();
}
|
Linux Examples
Relative Mode
Example to output data reports in Relative Mode.
examples/linux/relative_mode.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70 | /*
* This example reads data from the Cirque trackpad in "relative mode" and prints the values.
*
* See documentation at https://cirquepinnacle.rtfd.io/
*/
#include <iostream> // cout, endl
#include <CirquePinnacle/CirquePinnacle.h> // trackpad object
#ifdef USE_SW_DR // if using PINNACLE_SW_DR
#define DR_PIN PINNACLE_SW_DR
#endif
#if defined(PINNACLE_DRIVER_mraa) && !defined(DR_PIN)
#define DR_PIN 22 // GPIO25
#elif !defined(DR_PIN)
#define DR_PIN 25
#endif
#define SS_PIN 0
#ifndef USE_I2C
PinnacleTouchSPI trackpad(DR_PIN, SS_PIN);
#else // If using I2C, then use the following line (not the line above)
PinnacleTouchI2C trackpad(DR_PIN);
#endif
// an object to hold data reported by the Cirque trackpad
RelativeReport data;
bool setup()
{
if (!trackpad.begin()) {
std::cout << "Cirque Pinnacle not responding!" << std::endl;
return false;
}
std::cout << "CirquePinnacle/examples/linux/relative_mode\n"
<< std::endl;
#ifndef USE_SW_DR // if using PINNACLE_SW_DR
std::cout << "-- Using HW DataReady pin." << std::endl;
#endif
#ifndef USE_I2C
std::cout << "-- Using SPI interface." << std::endl;
#else
std::cout << "-- Using I2C interface." << std::endl;
#endif
std::cout << "\nTouch the trackpad to see the data" << std::endl;
return true;
}
void loop()
{
if (trackpad.available()) {
trackpad.read(&data);
std::cout << "Left:" << (unsigned int)(data.buttons & 1)
<< " Right:" << (unsigned int)(data.buttons & 2)
<< " Middle:" << (unsigned int)(data.buttons & 4)
<< "\tX:" << (int)(data.x)
<< "\tY:" << (int)(data.y)
<< "\tScroll:" << (int)(data.scroll) << std::endl;
}
}
int main()
{
if (!setup()) { // if trackpad.begin() failed
return -1; // fail fast
}
while (true) { // use ctrl+C to exit
loop();
}
return 0; // we will never reach this
}
|
Absolute Mode
Example to output data reports in Absolute Mode.
examples/linux/absolute_mode.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118 | /*
* This example reads data from the Cirque trackpad in "absolute mode" and prints the values.
*
* See documentation at https://cirquepinnacle.rtfd.io/
*/
#include <cmath> // sqrt(), pow(), atan2(), M_PI
#include <iostream> // cout, endl, cin
#include <iomanip> // setprecision()
#include <CirquePinnacle/CirquePinnacle.h> // trackpad object, absoluteClampAxis()
#ifdef USE_SW_DR // if using PINNACLE_SW_DR
#define DR_PIN PINNACLE_SW_DR
#endif
#if defined(PINNACLE_DRIVER_mraa) && !defined(DR_PIN)
#define DR_PIN 22 // GPIO25
#elif !defined(DR_PIN)
#define DR_PIN 25
#endif
#define SS_PIN 0
#ifndef USE_I2C
PinnacleTouchSPI trackpad(DR_PIN, SS_PIN);
#else // If using I2C, then use the following line (not the line above)
PinnacleTouchI2C trackpad(DR_PIN);
#endif
// an object to hold data reported by the Cirque trackpad
AbsoluteReport data;
/*
Showing all the printed output below will slow down the board's ability to
read() data from the trackpad in a timely manner (resulting in data loss).
Use this compile-time definition to switch between printing
raw data (false) or trigonometry data (true)
*/
static bool onlyShowTrigVals;
bool setup()
{
if (!trackpad.begin()) {
std::cout << "Cirque Pinnacle not responding!" << std::endl;
return false;
}
std::cout << "CirquePinnacle/examples/linux/absolute_mode\n"
<< std::endl;
trackpad.setDataMode(PINNACLE_ABSOLUTE);
trackpad.absoluteModeConfig(1); // set count of z-idle packets to 1
#ifndef USE_SW_DR // if using PINNACLE_SW_DR
std::cout << "-- Using HW DataReady pin." << std::endl;
#endif
#ifndef USE_I2C
std::cout << "-- Using SPI interface." << std::endl;
#else
std::cout << "-- Using I2C interface." << std::endl;
#endif
std::cout << "\nShow trigonometric calculations? [y/N] ('N' means show raw data) ";
char input;
std::cin >> input;
onlyShowTrigVals = input == 'y' || input == 'Y';
std::cout << "showing ";
if (onlyShowTrigVals)
std::cout << "trigonometric calculations." << std::endl;
else
std::cout << "raw data." << std::endl;
std::cout << "\nTouch the trackpad to see the data" << std::endl;
return true;
}
void loop()
{
if (trackpad.available()) {
trackpad.read(&data);
// datasheet recommends clamping the axes value to reliable range
if (data.z) { // only clamp values if Z axis is not idle.
data.x = data.x > 1920 ? 1920 : (data.x < 128 ? 128 : data.x); // 128 <= x <= 1920
data.y = data.y > 1472 ? 1472 : (data.y < 64 ? 64 : data.y); // 64 <= y <= 1472
}
if (!onlyShowTrigVals) {
// print raw data from the trackpad
std::cout << "B1: " << (unsigned int)(data.buttons & 1)
<< " B2: " << (unsigned int)(data.buttons & 2)
<< " B3: " << (unsigned int)(data.buttons & 4)
<< "\tX: " << data.x
<< "\tY: " << data.y
<< "\tZ: " << (unsigned int)(data.z) << std::endl;
}
else {
// print trigonometric data from the trackpad
if (!data.z) { // only compute angle and radius if touching (or near) the sensor
std::cout << "Idling" << std::endl;
}
else {
// coordinates assume axes have been clamped to recommended ranges
double coord_x = (int16_t)(data.x) - 960;
double coord_y = (int16_t)(data.y) - 736; // NOTE: y-axis is inverted by default
double radius = sqrt(pow(coord_x, 2) + pow(coord_y, 2));
double angle = atan2(coord_y, coord_x) * 180 / M_PI; // angle (in degrees) ranges (-180, 180]
std::cout << std::setprecision(5) << "angle: " << angle << "\tradius: " << radius << std::endl;
}
}
} // end if trackpad.available()
} //end loop()
int main()
{
if (!setup()) { // if trackpad.begin() failed
return -1; // fail fast
}
while (true) { // use ctrl+C to exit
loop();
}
return 0; // we will never reach this
}
|
AnyMeas Mode
Example to output data reports in AnyMeas Mode.
examples/linux/anymeas_mode.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105 | /*
* This example reads data from the Cirque trackpad in "anymeas mode" and prints the values.
*
* See documentation at https://cirquepinnacle.rtfd.io/
*/
#include <iostream> // cout, endl
#include <unistd.h> // sleep()
#include <CirquePinnacle/CirquePinnacle.h> // trackpad object
#ifdef PINNACLE_DRIVER_mraa
#define DR_PIN 22 // GPIO25
#else
#define DR_PIN 25
#endif
#define SS_PIN 0
#ifndef USE_I2C
PinnacleTouchSPI trackpad(DR_PIN, SS_PIN);
#else // If using I2C, then use the following line (not the line above)
PinnacleTouchI2C trackpad(DR_PIN);
#endif
typedef struct _MeasureVector
{
unsigned long toggle;
unsigned long polarity;
} measureVector;
measureVector vectorDeterminants[] = {
// toggle , polarity
{0x0000FFFF, 0x00000000}, // toggle all x-axis bits negatively (to 0)
{0x0FFF0000, 0x00000000}, // toggle all y-axis bits negatively (to 0)
{0x00FF00FF, 0x000000FF}, // toggle Y0-Y7 negatively (to 0) & X0-X7 positively (to 1)
{0x00FF00FF, 0x00FF0000} // toggle Y0-Y7 positively (to 1) & X0-X7 negatively (to 0)
};
const uint8_t variousVectors_size = sizeof(vectorDeterminants) / sizeof(measureVector);
int16_t compensations[variousVectors_size];
void compensate()
{
signed long accumulatedValue;
for (uint8_t i = 0; i < variousVectors_size; ++i) {
uint8_t sweep = 0;
accumulatedValue = 0;
while (sweep < 5) // take 5 measurements and average them for a bit lower noise compensation value
{
int16_t value = trackpad.measureAdc(vectorDeterminants[i].toggle, vectorDeterminants[i].polarity);
sweep++;
accumulatedValue += value;
}
compensations[i] = accumulatedValue / 5;
std::cout << "compensation " << (unsigned int)i << ": " << compensations[i] << std::endl;
}
}
bool setup()
{
if (!trackpad.begin()) {
std::cout << "Cirque Pinnacle not responding!" << std::endl;
return false;
}
std::cout << "CirquePinnacle/examples/linux/anymeas_mode" << std::endl;
trackpad.setDataMode(PINNACLE_ANYMEAS);
trackpad.anymeasModeConfig();
#ifndef USE_SW_DR // if using PINNACLE_SW_DR
std::cout << "-- Using HW DataReady pin." << std::endl;
#endif
#ifndef USE_I2C
std::cout << "-- Using SPI interface." << std::endl;
#else
std::cout << "-- Using I2C interface." << std::endl;
#endif
compensate();
for (uint8_t i = 5; i; --i) {
std::cout << "starting in " << (unsigned int)i << "second" << (i < 1 ? 's' : ' ') << '\r';
sleep(1);
}
std::cout << std::endl;
return true;
}
void loop()
{
for (unsigned int i = 0; i < variousVectors_size; i++) {
int16_t measurement = trackpad.measureAdc(
vectorDeterminants[i].toggle,
vectorDeterminants[i].polarity);
measurement -= compensations[i];
std::cout << "meas" << i << ": " << measurement << "\t";
}
std::cout << std::endl;
}
int main()
{
if (!setup()) { // if trackpad.begin() failed
return -1; // fail fast
}
while (true) { // use ctrl+C to exit
loop();
}
return 0; // we will never reach this
}
|
RPi Pico SDK Examples
defaultPins.h
The DR_PIN
AND SS_PIN
example definitions for various RP2040 based boards.
examples/pico_sdk/defaultPins.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 | // pre-chosen pins for different boards
#ifndef DEFAULTPINS_H
#define DEFAULTPINS_H
#ifdef USE_SW_DR // if using PINNACLE_SW_DR
#define DR_PIN PINNACLE_SW_DR
#endif
#if defined(ADAFRUIT_QTPY_RP2040)
#define SS_PIN PICO_DEFAULT_UART_RX_PIN // the pin labeled RX (GPIO5)
#ifndef DR_PIN // if not using PINNACLE_SW_DR
#define DR_PIN PICO_DEFAULT_UART_TX_PIN // the pin labeled TX (GPIO20)
#endif
#elif defined(PIMORONI_TINY2040)
#define SS_PIN PICO_DEFAULT_SPI_CSN_PIN // pin 5
#ifndef DR_PIN // if not using PINNACLE_SW_DR
#define DR_PIN 1 // pin 1
#endif
#elif defined(SPARFUN_THINGPLUS)
#define SS_PIN 21 // the pin labeled 21
#ifndef DR_PIN // if not using PINNACLE_SW_DR
#define DR_PIN 22 // the pin labeled 22
#endif
#elif defined(ADAFRUIT_ITSYBITSY_RP2040)
#define SS_PIN 12 // the pin labeled 2
#ifndef DR_PIN // if not using PINNACLE_SW_DR
#define DR_PIN 6 // the pin labeled 7
#endif
#else
// pins available on (ADAFRUIT_FEATHER_RP2040 || Pico_board || Sparkfun_ProMicro || SparkFun MicroMod)
#define SS_PIN 6
#ifndef DR_PIN // if not using PINNACLE_SW_DR
#define DR_PIN 8
#endif
#endif // board detection macro defs
#endif // DEFAULTPINS_H
|
Relative Mode
Example to output data reports in Relative Mode.
examples/pico_sdk/relative_mode.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76 | /*
* This example reads data from the Cirque trackpad in "relative mode" and prints the values.
*
* See documentation at https://cirquepinnacle.rtfd.io/
*/
#include "pico/stdlib.h" // printf(), getchar_timeout_us()
#include "pico/bootrom.h" // reset_usb_boot()
#include <tusb.h> // tud_cdc_connected()
#include <CirquePinnacle.h> // trackpad object
#include "defaultPins.h" // board presumptive default pin numbers for SS_PIN and DR_PIN
#ifndef USE_I2C
PinnacleTouchSPI trackpad(DR_PIN, SS_PIN);
#else // If using I2C, then use the following line (not the line above)
PinnacleTouchI2C trackpad(DR_PIN);
#endif
// an object to hold data reported by the Cirque trackpad
RelativeReport data;
bool setup()
{
// wait here until the CDC ACM (serial port emulation) is connected
while (!tud_cdc_connected()) {
sleep_ms(10);
}
if (!trackpad.begin()) {
printf("Cirque Pinnacle not responding!\n");
return false;
}
printf("CirquePinnacle/examples/pico_sdk/relative_mode\n");
#ifndef USE_SW_DR
printf("-- Using HW Data Ready pin\n");
#endif
#ifndef USE_I2C
printf("-- Using SPI interface\n");
#else
printf("-- Using I2C interface\n");
#endif
printf("\n*** Enter 'B' to reset to bootloader.\n");
printf("\nTouch the trackpad to see the data\n");
return true;
}
void loop()
{
if (trackpad.available()) {
trackpad.read(&data);
printf("Left:%d ", data.buttons & 1);
printf("Right:%d ", data.buttons & 2);
printf("Middle:%d", data.buttons & 4);
printf("\tX: %d\tY: %d\tScroll: %d\n", data.x, data.y, data.scroll);
}
char input = getchar_timeout_us(0); // get char from buffer for user input
if (input != PICO_ERROR_TIMEOUT && (input == 'b' || input == 'B')) {
// reset to bootloader
trackpad.shutdown(true);
reset_usb_boot(0, 0);
}
}
int main()
{
stdio_init_all(); // init necessary IO for the RP2040
while (!setup()) { // if trackpad.begin() failed
// hold program in infinite attempts to initialize trackpad
}
while (true) {
loop();
}
return 0; // we will never reach this
}
|
Absolute Mode
Example to output data reports in Absolute Mode.
examples/pico_sdk/absolute_mode.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122 | /*
* This example reads data from the Cirque trackpad in "absolute mode" and prints the values.
*
* See documentation at https://cirquepinnacle.rtfd.io/
*/
#include <cmath> // sqrt(), pow(), atan2()
#include "pico/stdlib.h" // printf(), getchar_timeout_us()
#include "pico/bootrom.h" // reset_usb_boot()
#include <tusb.h> // tud_cdc_connected()
#include <CirquePinnacle.h> // trackpad object
#include "defaultPins.h" // board presumptive default pin numbers for SS_PIN and DR_PIN
#ifndef USE_I2C
PinnacleTouchSPI trackpad(DR_PIN, SS_PIN);
#else // If using I2C, then use the following line (not the line above)
PinnacleTouchI2C trackpad(DR_PIN);
#endif
// an object to hold data reported by the Cirque trackpad
AbsoluteReport data;
#ifndef PI
#define PI 3.14159
#endif
/*
Showing all the printed output below will slow down the board's ability to
read() data from the trackpad in a timely manner (resulting in data loss).
Change this variable (via Serial input) to switch between printing
raw data (false) or trigonometric data (true)
*/
bool onlyShowTrigVals = false;
bool setup()
{
// wait here until the CDC ACM (serial port emulation) is connected
while (!tud_cdc_connected()) {
sleep_ms(10);
}
if (!trackpad.begin()) {
printf("Cirque Pinnacle not responding!\n");
return false;
}
printf("CirquePinnacle/examples/pico_sdk/absolute_mode\n");
trackpad.setDataMode(PINNACLE_ABSOLUTE);
trackpad.absoluteModeConfig(1); // set count of z-idle packets to 1
#ifndef USE_SW_DR
printf("-- Using HW Data Ready pin\n");
#endif
#ifndef USE_I2C
printf("-- Using SPI interface\n");
#else
printf("-- Using I2C interface\n");
#endif
printf("\n*** Enter 'M' to measure and print raw data.");
printf("\n*** Enter 'T' to measure and print trigonometric calculations.");
printf("\n*** Enter 'B' to reset to bootloader.\n");
printf("\nTouch the trackpad to see the data\n");
return true;
}
void loop()
{
if (trackpad.available()) {
trackpad.read(&data);
// datasheet recommends clamping the axes value to reliable range
if (data.z) { // only clamp values if Z axis is not idle.
data.x = data.x > 1920 ? 1920 : (data.x < 128 ? 128 : data.x); // 128 <= x <= 1920
data.y = data.y > 1472 ? 1472 : (data.y < 64 ? 64 : data.y); // 64 <= y <= 1472
}
if (!onlyShowTrigVals) {
// print raw data from the trackpad
printf("B1:%d B2:%d B3:%d", data.buttons & 1, data.buttons & 2, data.buttons & 4);
printf("\tX:%d\tY:%d\tZ:%d\n", data.x, data.y, data.z);
}
else {
// print trigonometric calculations from the trackpad data
if (!data.z) { // only compute angle and radius if touching (or near) the sensor
printf("Idling\n");
}
else {
// coordinates assume axes have been clamped to recommended ranges
double coord_x = (int16_t)(data.x) - 960;
double coord_y = (int16_t)(data.y) - 736; // NOTE: y-axis is inverted by default
double radius = sqrt(pow(coord_x, 2) + pow(coord_y, 2));
double angle = atan2(coord_y, coord_x) * 180 / PI; // angle (in degrees) ranges (-180, 180]
printf("angle: %.2f\tradius: %.2f\n", angle, radius);
}
}
} // end if trackpad.available()
char input = getchar_timeout_us(0); // get char from buffer for user input
if (input != PICO_ERROR_TIMEOUT && (input == 'b' || input == 'B')) {
reset_usb_boot(0, 0); // reset to bootloader
}
else if (input != PICO_ERROR_TIMEOUT && (input == 'm' || input == 'M')) {
onlyShowTrigVals = false;
}
else if (input != PICO_ERROR_TIMEOUT && (input == 't' || input == 'T')) {
onlyShowTrigVals = true;
}
} //end loop()
int main()
{
stdio_init_all(); // init necessary IO for the RP2040
while (!setup()) { // if trackpad.begin() failed
// hold program in infinite attempts to initialize trackpad
}
while (true) {
loop();
}
return 0; // we will never reach this
}
|
AnyMeas Mode
Example to output data reports in AnyMeas Mode.
examples/pico_sdk/anymeas_mode.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110 | /*
* This example reads data from the Cirque trackpad in "anymeas mode" and prints the values.
*
* See documentation at https://cirquepinnacle.rtfd.io/
*/
#include "pico/stdlib.h" // printf(), getchar_timeout_us()
#include "pico/bootrom.h" // reset_usb_boot()
#include <tusb.h> // tud_cdc_connected()
#include <CirquePinnacle.h> // trackpad object
#include "defaultPins.h" // board presumptive default pin numbers for SS_PIN and DR_PIN
#ifndef USE_I2C
PinnacleTouchSPI trackpad(DR_PIN, SS_PIN);
#else // If using I2C, then use the following line (not the line above)
PinnacleTouchI2C trackpad(DR_PIN);
#endif
typedef struct _MeasureVector
{
unsigned long toggle;
unsigned long polarity;
} measureVector;
measureVector vectorDeterminants[] = {
// toggle , polarity
{0x0000FFFF, 0x00000000}, // toggle all x-axis bits negatively (to 0)
{0x0FFF0000, 0x00000000}, // toggle all y-axis bits negatively (to 0)
{0x00FF00FF, 0x000000FF}, // toggle Y0-Y7 negatively (to 0) & X0-X7 positively (to 1)
{0x00FF00FF, 0x00FF0000} // toggle Y0-Y7 positively (to 1) & X0-X7 negatively (to 0)
};
const uint8_t variousVectors_size = sizeof(vectorDeterminants) / sizeof(measureVector);
int16_t compensations[variousVectors_size];
void compensate()
{
int32_t accumulatedValue;
for (uint8_t i = 0; i < variousVectors_size; ++i) {
uint8_t sweep = 0;
accumulatedValue = 0;
while (sweep < 5) // take 5 measurements and average them for a bit lower noise compensation value
{
int16_t value = trackpad.measureAdc(vectorDeterminants[i].toggle, vectorDeterminants[i].polarity);
sweep++;
accumulatedValue += value;
}
compensations[i] = accumulatedValue / 5;
printf("compensation %d: %d\n", i, compensations[i]);
}
}
bool setup()
{
// wait here until the CDC ACM (serial port emulation) is connected
while (!tud_cdc_connected()) {
sleep_ms(10);
}
if (!trackpad.begin()) {
printf("Cirque Pinnacle not responding!\n");
return false;
}
printf("CirquePinnacle/examples/pico_sdk/anymeas_mode\n");
trackpad.setDataMode(PINNACLE_ANYMEAS);
#ifndef USE_I2C
printf("-- Using SPI interface\n");
#else
printf("-- Using I2C interface\n");
#endif
printf("\n*** Enter 'B' to reset to bootloader.\n");
compensate();
for (uint8_t i = 5; i; --i) {
printf("starting in %d second%c\r", i, i > 1 ? 's' : ' ');
sleep_ms(1000);
}
return true;
}
void loop()
{
for (uint8_t i = 0; i < variousVectors_size; i++) {
int16_t measurement = trackpad.measureAdc(
vectorDeterminants[i].toggle,
vectorDeterminants[i].polarity);
measurement -= compensations[i];
printf("meas%d: %d\t", i, measurement);
}
printf("\n");
char input = getchar_timeout_us(0); // get char from buffer for user input
if (input != PICO_ERROR_TIMEOUT && (input == 'b' || input == 'B')) {
// reset to bootloader
trackpad.shutdown(true);
reset_usb_boot(0, 0);
}
}
int main()
{
stdio_init_all(); // init necessary IO for the RP2040
while (!setup()) { // if trackpad.begin() failed
// hold program in infinite attempts to initialize trackpad
}
while (true) {
loop();
}
return 0; // we will never reach this
}
|
Python Examples
Relative Mode
Example to output data reports in Relative Mode.
examples/cpython/relative_mode.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88 | """
This example reads data from the Cirque trackpad in "relative mode" and
prints the values.
See documentation at https://cirquepinnacle.rtfd.io/
"""
import time
from typing import Union
from cirque_pinnacle import (
RelativeReport,
PinnacleTouchSPI,
PinnacleTouchI2C,
PINNACLE_SW_DR,
PINNACLE_DRIVER,
)
print("CirquePinnacle/examples/cpython/relative_mode\n")
# a HW ``dr_pin`` is more efficient, but not required for Absolute or Relative modes
dr_pin = PINNACLE_SW_DR # uses internal DR flag
if not input("Use SW Data Ready? [y/N] ").lower().startswith("y"):
print("-- Using HW Data Ready pin.")
if PINNACLE_DRIVER == "mraa":
dr_pin = 22 # GPIO25
else:
dr_pin = 25 # GPIO25
trackpad: Union[PinnacleTouchSPI, PinnacleTouchI2C]
if not input("Is the trackpad configured for I2C? [y/N] ").lower().startswith("y"):
print("-- Using SPI interface.")
ss_pin = 0 # uses /dev/spidev0.0 (CE0 or GPIO8)
trackpad = PinnacleTouchSPI(dr_pin, ss_pin)
else:
print("-- Using I2C interface")
trackpad = PinnacleTouchI2C(dr_pin)
if not trackpad.begin():
raise OSError("Cirque Pinnacle not responding!")
# an object to hold data reported by the Cirque trackpad
data = RelativeReport()
def print_data(timeout=6):
"""Print available data reports from the Pinnacle touch controller
until there's no input for a period of ``timeout`` seconds."""
print(
"Touch the sensor to see the data. Exits after",
timeout,
"seconds of inactivity.",
)
start = time.monotonic()
while time.monotonic() - start < timeout:
while trackpad.available(): # is there new data?
trackpad.read(data)
print(data)
start = time.monotonic()
def set_role():
"""Set the role using stdin stream. Arguments for functions can be
specified using a space delimiter (e.g. 'M 10' calls `print_data(10)`)
"""
user_input = (
input(
"\n*** Enter 'M' to measure and print data."
"\n*** Enter 'Q' to quit example.\n"
)
or "?"
).split()
if user_input[0].upper().startswith("M"):
print_data(*[int(x) for x in user_input[1:2]])
return True
if user_input[0].upper().startswith("Q"):
return False
print(user_input[0], "is an unrecognized input. Please try again.")
return set_role()
if __name__ == "__main__":
try:
while set_role():
pass # continue example until 'Q' is entered
except KeyboardInterrupt:
print(" Keyboard Interrupt detected.")
else:
print("\nRun print_data() to read and print data.")
|
Absolute Mode
Example to output data reports in Absolute Mode.
examples/cpython/absolute_mode.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138 | """
This example reads data from the Cirque trackpad in "absolute mode" and
prints the values.
See documentation at https://cirquepinnacle.rtfd.io/
"""
import math
import time
from typing import Union
from cirque_pinnacle import (
AbsoluteReport,
PinnacleTouchSPI,
PinnacleTouchI2C,
PINNACLE_SW_DR,
PINNACLE_ABSOLUTE,
PINNACLE_DRIVER,
)
print("CirquePinnacle/examples/cpython/absolute_mode")
# a HW ``dr_pin`` is more efficient, but not required for Absolute or Relative modes
dr_pin = PINNACLE_SW_DR # uses internal DR flag
if not input("Use SW Data Ready? [y/N] ").lower().startswith("y"):
print("-- Using HW Data Ready pin.")
if PINNACLE_DRIVER == "mraa":
dr_pin = 22 # GPIO25
else:
dr_pin = 25 # GPIO25
trackpad: Union[PinnacleTouchSPI, PinnacleTouchI2C]
if not input("Is the trackpad configured for I2C? [y/N] ").lower().startswith("y"):
print("-- Using SPI interface.")
ss_pin = 0 # uses /dev/spidev0.0 (CE0 or GPIO8)
trackpad = PinnacleTouchSPI(dr_pin, ss_pin)
else:
print("-- Using I2C interface")
trackpad = PinnacleTouchI2C(dr_pin)
if not trackpad.begin():
raise OSError("Cirque Pinnacle not responding!")
trackpad.data_mode = PINNACLE_ABSOLUTE
trackpad.absolute_mode_config(1) # set count of z-idle packets to 1
# an object to hold data reported by the Cirque trackpad
data = AbsoluteReport()
def print_data(timeout=6):
"""Print available data reports from the Pinnacle touch controller
until there's no input for a period of ``timeout`` seconds."""
print(
"Touch the sensor to see the data. Exits after",
timeout,
"seconds of inactivity.",
)
start = time.monotonic()
while time.monotonic() - start < timeout:
while trackpad.available(): # is there new data?
trackpad.read(data)
# specification sheet recommends clamping absolute position data of
# X & Y axis for reliability
if data.z: # only clamp values if Z axis is not idle
data.x = max(128, min(1920, data.x)) # 128 <= x < = 1920
data.y = max(64, min(1472, data.y)) # 64 <= y < = 1472
print(data)
start = time.monotonic()
def print_trig(timeout=6):
"""Print available data reports from the Pinnacle touch controller as trigonometric
calculations until there's no input for a period of ``timeout`` seconds."""
print(
"Touch the trackpad to see the data. Exits after",
timeout,
"seconds of inactivity.",
)
start = time.monotonic()
while time.monotonic() - start < timeout:
while trackpad.available(): # is there new data?
trackpad.read(data)
if not data.z: # if not touching (or near) the sensor
print("Idling") # don't do calc when both axes are 0
else: # if touching (or near) the sensor
# datasheet recommends clamping X & Y axis for reliability
data.x = max(128, min(1920, data.x)) # 128 <= x <= 1920
data.y = max(64, min(1472, data.y)) # 64 <= y <= 1472
# coordinates assume axes have been clamped to recommended ranges
coord_x = data.x - 960
coord_y = data.y - 736 # NOTE: y-axis is inverted by default
radius = math.sqrt(math.pow(coord_x, 2) + math.pow(coord_y, 2))
# angle (in degrees) ranges [-180, 180];
angle = math.atan2(coord_y, coord_x) * 180 / math.pi
print("angle: %.2f\tradius: %.2f" % (angle, radius))
start = time.monotonic()
def set_role():
"""Set the role using stdin stream. Arguments for functions can be
specified using a space delimiter (e.g. 'M 10' calls `print_data(10)`)
"""
user_input = (
input(
"\n*** Enter 'M' to measure and print raw data."
"\n*** Enter 'T' to measure and print trigonometric calculations."
"\n*** Enter 'Q' to quit example.\n"
)
or "?"
).split()
if user_input[0].upper().startswith("M"):
print_data(*[int(x) for x in user_input[1:2]])
return True
if user_input[0].upper().startswith("T"):
print_trig(*[int(x) for x in user_input[1:2]])
return True
if user_input[0].upper().startswith("Q"):
return False
print(user_input[0], "is an unrecognized input. Please try again.")
return set_role()
if __name__ == "__main__":
try:
while set_role():
pass # continue example until 'Q' is entered
except KeyboardInterrupt:
print(" Keyboard Interrupt detected.")
else:
print(
"\nRun print_data() to read and print raw data.",
"Run print_trig() to measure and print trigonometric calculations.",
sep="\n",
)
|
AnyMeas Mode
Example to output data reports in AnyMeas Mode.
examples/cpython/anymeas_mode.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113 | """
This example reads data from the Cirque trackpad in "anymeas mode" and
prints the values.
See documentation at https://cirquepinnacle.rtfd.io/
"""
import time
from typing import Union
from cirque_pinnacle import (
PinnacleTouchSPI,
PinnacleTouchI2C, # noqa: imported but unused
PINNACLE_ANYMEAS,
PINNACLE_DRIVER,
)
print("CirquePinnacle/examples/cpython/anymeas_mode\n")
if PINNACLE_DRIVER == "mraa":
dr_pin = 22 # GPIO25
else:
dr_pin = 25 # GPIO25
trackpad: Union[PinnacleTouchSPI, PinnacleTouchI2C]
if not input("Is the trackpad configured for I2C? [y/N] ").lower().startswith("y"):
print("-- Using SPI interface.")
ss_pin = 0 # uses /dev/spidev0.0 (CE0 or GPIO8)
trackpad = PinnacleTouchSPI(dr_pin, ss_pin)
else:
print("-- Using I2C interface")
trackpad = PinnacleTouchI2C(dr_pin)
if not trackpad.begin():
raise OSError("Cirque Pinnacle not responding!")
trackpad.data_mode = PINNACLE_ANYMEAS
# we'll use this list of tuples as args to PinnacleTouch.measure_adc()
vectors = [
# toggle , polarity
(0x0000FFFF, 0x00000000), # toggle all x-axis bits negatively (to 0)
(0x0FFF0000, 0x00000000), # toggle all y-axis bits negatively (to 0)
(
0x00FF00FF,
0x000000FF,
), # toggle Y0-Y7 negatively (to 0) & X0-X7 positively (to 1)
(
0x00FF00FF,
0x00FF0000,
), # toggle Y0-Y7 positively (to 1) & X0-X7 negatively (to 0)
]
# a list of compensations to use with measured `vectors`
compensation = [0] * len(vectors)
def compensate():
sweep = 5
for i, (toggle, polarity) in enumerate(vectors):
value = 0
for _ in range(sweep):
value += trackpad.measure_adc(toggle, polarity)
compensation[i] = int(value / sweep)
print("compensation {}: {}".format(i, compensation[i]))
def take_measurements(timeout=6):
"""Read ``len(vectors)`` number of measurements and print results for
``timeout`` number of seconds."""
print("Taking measurements for", timeout, "seconds.")
start = time.monotonic()
while time.monotonic() - start < timeout:
for i, (toggle, polarity) in enumerate(vectors):
result = trackpad.measure_adc(toggle, polarity)
print("meas{}: {}".format(i, result - compensation[i]), end="\t")
print()
def set_role():
"""Set the role using stdin stream. Arguments for functions can be
specified using a space delimiter (e.g. 'C 10' calls `compensate(10)`)
"""
user_input = (
input(
"\n*** Enter 'C' to get compensations for measurements."
"\n*** Enter 'M' to read and print measurements."
"\n*** Enter 'Q' to quit example.\n"
)
or "?"
).split()
if user_input[0].upper().startswith("C"):
compensate(*[int(x) for x in user_input[1:2]])
return True
if user_input[0].upper().startswith("M"):
take_measurements(*[int(x) for x in user_input[1:2]])
return True
if user_input[0].upper().startswith("Q"):
return False
print(user_input[0], "is an unrecognized input. Please try again.")
return set_role()
if __name__ == "__main__":
try:
while set_role():
pass # continue example until 'Q' is entered
except KeyboardInterrupt:
print(" Keyboard Interrupt detected.")
else:
print(
"\nRun compensate() to set compensations for measurements.",
"Run take_measurements() to read and print measurements.",
sep="\n",
)
|