Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2023 Brendan Doherty (2bndy5)
Copyright (c) 2025 Brendan Doherty (2bndy5)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
14 changes: 8 additions & 6 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@

.. image:: https://readthedocs.org/projects/cirquepinnacle/badge/?version=latest
.. |docs-badge| image:: https://readthedocs.org/projects/cirquepinnacle/badge/?version=latest
:target: https://cirquepinnacle.readthedocs.io/en/latest/?badge=latest
:alt: Documentation Status
.. image:: https://github.com/2bndy5/CirquePinnacle/actions/workflows/build_arduino.yml/badge.svg
.. |arduino-badge| image:: https://github.com/2bndy5/CirquePinnacle/actions/workflows/build_arduino.yml/badge.svg
:target: https://github.com/2bndy5/CirquePinnacle/actions/workflows/build_arduino.yml
:alt: Arduino build
.. image:: https://github.com/2bndy5/CirquePinnacle/actions/workflows/build_platformio.yml/badge.svg
.. |pio-badge| image:: https://github.com/2bndy5/CirquePinnacle/actions/workflows/build_platformio.yml/badge.svg
:target: https://github.com/2bndy5/CirquePinnacle/actions/workflows/build_platformio.yml
:alt: PlatformIO build
.. image:: https://github.com/2bndy5/CirquePinnacle/actions/workflows/build_pico_sdk.yml/badge.svg
.. |pico-sdk-badge| image:: https://github.com/2bndy5/CirquePinnacle/actions/workflows/build_pico_sdk.yml/badge.svg
:target: https://github.com/2bndy5/CirquePinnacle/actions/workflows/build_pico_sdk.yml
:alt: Pico SDK build
.. image:: https://github.com/2bndy5/CirquePinnacle/actions/workflows/build_linux.yml/badge.svg
.. |linux-badge| image:: https://github.com/2bndy5/CirquePinnacle/actions/workflows/build_linux.yml/badge.svg
:target: https://github.com/2bndy5/CirquePinnacle/actions/workflows/build_linux.yml
:alt: Linux build
.. image:: https://github.com/2bndy5/CirquePinnacle/actions/workflows/build_python.yml/badge.svg
.. |py-badge| image:: https://github.com/2bndy5/CirquePinnacle/actions/workflows/build_python.yml/badge.svg
:target: https://github.com/2bndy5/CirquePinnacle/actions/workflows/build_python.yml
:alt: Python build

|docs-badge| |arduino-badge| |pio-badge| |pico-sdk-badge| |linux-badge| |py-badge|

Introduction
============

Expand Down
8 changes: 8 additions & 0 deletions docs/API/arduino_wrappers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,11 @@ Arduino GPIOClass
This is library-specific API wrapping the Arduino GPIO interface.

.. cpp-apigen-group:: arduino-gpio


Arduino Interrupts
------------------

This is library-specific API wrapping the Arduino interrupt functionality.

.. cpp-apigen-group:: arduino-irq
20 changes: 17 additions & 3 deletions examples/absolute_mode/absolute_mode.ino
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ PinnacleTouchSPI trackpad(DR_PIN, SS_PIN);
// an object to hold data reported by the Cirque trackpad
AbsoluteReport data;

// interrupt related handling
volatile bool isDataReady = false; // track the interrupts with our own IRQ flag
/// A callback function that allows `loop()` to know when the trackpad's DR pin is active
void interruptHandler() {
isDataReady = true;
}

void setup() {
Serial.begin(115200);
while (!Serial) {
Expand All @@ -30,6 +37,10 @@ void setup() {
Serial.println(F("CirquePinnacle/examples/absolute_mode"));
trackpad.setDataMode(PINNACLE_ABSOLUTE);
trackpad.absoluteModeConfig(1); // set count of z-idle packets to 1

// pinMode() is already called by trackpad.begin()
attachInterrupt(digitalPinToInterrupt(DR_PIN), interruptHandler, RISING);

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."));
Expand All @@ -43,14 +54,17 @@ raw data (false) or trigonometry data (true)
*/
bool onlyShowTrigVals = false;

#ifndef M_PI
#if defined(M_PI) && !defined(PI)
#define PI M_PI
#else
#endif
#ifndef PI
#define PI 3.14159
#endif

void loop() {
if (trackpad.available()) {
// using `interruptHandler()` to update `isDataReady`
if (isDataReady) {
isDataReady = false; // reset our IRQ flag
trackpad.read(&data);

// datasheet recommends clamping the axes value to reliable range
Expand Down
44 changes: 38 additions & 6 deletions examples/anymeas_mode/anymeas_mode.ino
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,17 @@ void compensate() {
}
}

// the index number used to iterate through our vectorDeterminants array used in loop()
unsigned int vectorIndex = 0;

// interrupt related handling
volatile bool isDataReady = false; // track the interrupts with our own IRQ flag
bool waitingForInterrupt = false; // a flag to control iteration of our loop()
/// A callback function that allows `loop()` to know when the trackpad's DR pin is active
void interruptHandler() {
isDataReady = true;
}

void setup() {
Serial.begin(115200);
while (!Serial) {
Expand All @@ -63,20 +74,41 @@ void setup() {
trackpad.setDataMode(PINNACLE_ANYMEAS);
trackpad.anymeasModeConfig();
compensate();

// setup interrupt handler.
// `pinMode()` is already called by `trackpad.begin()`.
// We do this AFTER calling `compensate()` because
// `compensate()` will unnecessarily trigger `interruptHandler()`
attachInterrupt(digitalPinToInterrupt(DR_PIN), interruptHandler, RISING);

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];
if (!isDataReady && !waitingForInterrupt) {
trackpad.startMeasureAdc(
vectorDeterminants[vectorIndex].toggle,
vectorDeterminants[vectorIndex].polarity);
waitingForInterrupt = true;
} else if (isDataReady) {
isDataReady = false; // reset our IRQ flag
waitingForInterrupt = false; // allow iteration to continue

int16_t measurement = trackpad.getMeasureAdc();
measurement -= compensations[vectorIndex];
Serial.print(F("meas"));
Serial.print(i);
Serial.print(vectorIndex);
Serial.print(F(":"));
Serial.print(measurement);
Serial.print(F(" \t"));

// increment our loop iterator
if (vectorIndex < (variousVectors_size - 1)) {
vectorIndex++;
} else {
vectorIndex = 0;
Serial.println();
}
}
Serial.println();
}
21 changes: 19 additions & 2 deletions examples/linux/absolute_mode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#include <cmath> // sqrt(), pow(), atan2(), M_PI
#include <iostream> // cout, endl, cin
#include <iomanip> // setprecision()
#include <CirquePinnacle/CirquePinnacle.h> // trackpad object, absoluteClampAxis()
#include <CirquePinnacle/CirquePinnacle.h> // trackpad object

#define DR_PIN 25 // GPIO25
#define SS_PIN 0
Expand All @@ -20,6 +20,14 @@ PinnacleTouchI2C trackpad(DR_PIN);
// an object to hold data reported by the Cirque trackpad
AbsoluteReport data;

// interrupt related handling
volatile bool isDataReady = false; // track the interrupts with our own IRQ flag
/// A callback function that allows `loop()` to know when the trackpad's DR pin is active
void interruptHandler()
{
isDataReady = true;
}

/*
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).
Expand All @@ -38,6 +46,12 @@ bool setup()
<< std::endl;
trackpad.setDataMode(PINNACLE_ABSOLUTE);
trackpad.absoluteModeConfig(1); // set count of z-idle packets to 1

// pull in arduino-like namespace
namespace arduino = cirque_pinnacle_arduino_wrappers;
// setup the interrupt handler
arduino::attachInterrupt(DR_PIN, &interruptHandler, arduino::RISING);

#ifndef USE_I2C
std::cout << "-- Using SPI interface." << std::endl;
#else
Expand All @@ -58,7 +72,10 @@ bool setup()

void loop()
{
if (trackpad.available()) {
// using `interruptHandler()` to update `isDataReady`
if (isDataReady) {
// assert(isDataReady == trackpad.available());
isDataReady = false; // reset our IRQ flag
trackpad.read(&data);

// datasheet recommends clamping the axes value to reliable range
Expand Down
54 changes: 45 additions & 9 deletions examples/linux/anymeas_mode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ void compensate()
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);
int16_t value = trackpad.measureAdc(
vectorDeterminants[i].toggle,
vectorDeterminants[i].polarity);
sweep++;
accumulatedValue += value;
}
Expand All @@ -50,6 +52,18 @@ void compensate()
}
}

// the index number used to iterate through our vectorDeterminants array used in loop()
unsigned int vectorIndex = 0;

// interrupt related handling
volatile bool isDataReady = false; // track the interrupts with our own IRQ flag
bool waitingForInterrupt = false; // a flag to control iteration of our loop()
/// A callback function that allows `loop()` to know when the trackpad's DR pin is active
void interruptHandler()
{
isDataReady = true;
}

bool setup()
{
if (!trackpad.begin()) {
Expand All @@ -66,8 +80,15 @@ bool setup()
#endif
compensate();

// pull in arduino-like namespace
namespace arduino = cirque_pinnacle_arduino_wrappers;
// setup interrupt handler.
// We do this AFTER calling `compensate()` because
// `compensate()` will unnecessarily trigger `interruptHandler()`
arduino::attachInterrupt(DR_PIN, &interruptHandler, arduino::RISING);

for (uint8_t i = 5; i; --i) {
std::cout << "starting in " << (unsigned int)i << "second" << (i < 1 ? 's' : ' ') << '\r';
std::cout << "starting in " << (unsigned int)i << " second" << (i < 1 ? 's' : ' ') << '\r' << std::flush;
sleep(1);
}
std::cout << std::endl;
Expand All @@ -76,14 +97,29 @@ bool setup()

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";
if (!isDataReady && !waitingForInterrupt) {
trackpad.startMeasureAdc(
vectorDeterminants[vectorIndex].toggle,
vectorDeterminants[vectorIndex].polarity);
waitingForInterrupt = true;
}
else if (isDataReady) {
isDataReady = false; // reset our IRQ flag
waitingForInterrupt = false; // allow iteration to continue

int16_t measurement = trackpad.getMeasureAdc();
measurement -= compensations[vectorIndex];
std::cout << "meas" << vectorIndex << ": " << measurement << "\t";

// increment our loop iterator
if (vectorIndex < (variousVectors_size - 1)) {
vectorIndex++;
}
else {
vectorIndex = 0;
std::cout << std::endl;
}
}
std::cout << std::endl;
}

int main()
Expand Down
19 changes: 18 additions & 1 deletion examples/linux/relative_mode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ PinnacleTouchI2C trackpad(DR_PIN);
// an object to hold data reported by the Cirque trackpad
RelativeReport data;

// interrupt related handling
volatile bool isDataReady = false; // track the interrupts with our own IRQ flag
/// A callback function that allows `loop()` to know when the trackpad's DR pin is active
void interruptHandler()
{
isDataReady = true;
}

bool setup()
{
if (!trackpad.begin()) {
Expand All @@ -26,6 +34,12 @@ bool setup()
}
std::cout << "CirquePinnacle/examples/linux/relative_mode\n"
<< std::endl;

// pull in arduino-like namespace
namespace arduino = cirque_pinnacle_arduino_wrappers;
// setup the interrupt handler
arduino::attachInterrupt(DR_PIN, &interruptHandler, arduino::RISING);

#ifndef USE_I2C
std::cout << "-- Using SPI interface." << std::endl;
#else
Expand All @@ -37,7 +51,10 @@ bool setup()

void loop()
{
if (trackpad.available()) {
// using `interruptHandler()` to update `isDataReady`
if (isDataReady) {
// assert(isDataReady == trackpad.available());
isDataReady = false; // reset our IRQ flag
trackpad.read(&data);
std::cout << "Left:" << (unsigned int)(data.buttons & 1)
<< " Right:" << (unsigned int)(data.buttons & 2)
Expand Down
19 changes: 18 additions & 1 deletion examples/pico_sdk/absolute_mode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,18 @@ PinnacleTouchSPI trackpad(DR_PIN, SS_PIN);
PinnacleTouchI2C trackpad(DR_PIN);
#endif

// interrupt related handling
volatile bool isDataReady = false; // track the interrupts with our own IRQ flag
/// A callback function that allows `loop()` to know when the trackpad's DR pin is active
void interruptHandler(uint gpio, uint32_t events)
{
if (gpio != DR_PIN && !(events & GPIO_IRQ_EDGE_RISE)) {
// the gpio pin and event does not match the configuration we specified
return;
}
isDataReady = true; // forward event handling back to main loop()
}

// an object to hold data reported by the Cirque trackpad
AbsoluteReport data;

Expand Down Expand Up @@ -51,6 +63,10 @@ bool setup()
#else
printf("-- Using I2C interface\n");
#endif

// setup interrupt handler
gpio_set_irq_enabled_with_callback(DR_PIN, GPIO_IRQ_EDGE_RISE, true, &interruptHandler);

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");
Expand All @@ -60,7 +76,8 @@ bool setup()

void loop()
{
if (trackpad.available()) {
if (isDataReady) {
// assert(isDataReady == trackpad.available());
trackpad.read(&data);

// datasheet recommends clamping the axes value to reliable range
Expand Down
Loading