Skip to content

Commit 0f1daa7

Browse files
committed
put together an SPI demo and Arduino API example - not tested, but compiles
1 parent 00d1277 commit 0f1daa7

File tree

3 files changed

+352
-0
lines changed

3 files changed

+352
-0
lines changed
Lines changed: 288 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
2+
/*
3+
* ---------------------------------------------------------------------------------
4+
* Copyright (c) 2025, SparkFun Electronics Inc.
5+
*
6+
* SPDX-License-Identifier: MIT
7+
* ---------------------------------------------------------------------------------
8+
*/
9+
10+
/*
11+
* Example using the SparkFun FPC2534 Fingerprint sensor library to demonstrate navigation mode
12+
* of the sensor. This example uses the SPI interface to communicate with the sensor.
13+
*
14+
* Example Setup:
15+
* - Connect the SparkFun Qwiic FPC2534 Fingerprint sensor to your microcontroller using SPI.
16+
* - Connect the RST pin on the sensor to a digital pin on your microcontroller. This is used by the
17+
* example to "reset the sensor" on startup.
18+
* - Connect the IRQ pin on the sensor to a digital pin on your microcontroller. The sensor triggers
19+
* an interrupt on this pin when it has data to send.
20+
* - Update the IRQ_PIN and RST_PIN defines below to match the pins you are using.
21+
*
22+
* Operation:
23+
24+
* - The example registers several callback functions with the sensor library. These functions are called as
25+
* messages are received from the sensor.
26+
* - The example places the sensor in navigation mode. In this mode, the sensor detects simple gestures
27+
* such as left, right, up, down swipes, as well as press and long-press events.
28+
* - The example prints out messages to the serial console as events are received from the sensor.
29+
* - On a press event, the example toggles the on-board LED of the sensor on and off.
30+
* - On a long-press event, the example requests the firmware version from the sensor and prints it out when received.
31+
*
32+
33+
*---------------------------------------------------------------------------------
34+
*/
35+
#include <Arduino.h>
36+
37+
#include "SparkFun_FPC2534.h"
38+
39+
//----------------------------------------------------------------------------
40+
// User Config -
41+
//----------------------------------------------------------------------------
42+
// UPDATE THESE DEFINES TO MATCH YOUR HARDWARE SETUP
43+
//
44+
// These are the pins the IRQ and RST pins of the sensor are connected to the microcontroller.
45+
//
46+
// NOTE: The IRQ pin must be an interrupt-capable pin on your microcontroller
47+
//
48+
// Example pins tested for various SparkFun boards:
49+
50+
// // ESP32 thing plus
51+
// #define IRQ_PIN 16
52+
// #define RST_PIN 21
53+
// #define I2C_BUS 0
54+
55+
// ESP32 thing plus C
56+
// #define IRQ_PIN 32
57+
// #define RST_PIN 14
58+
// #define I2C_BUS 0
59+
60+
// ESP32 IoT RedBoard
61+
#define IRQ_PIN 26
62+
#define RST_PIN 27
63+
#define CS_PIN 6
64+
65+
// rp2350 thing plus
66+
// #define IRQ_PIN 11
67+
// #define RST_PIN 12
68+
// #define I2C_BUS 0
69+
70+
// rp2350 RedBoard IoT
71+
// #define IRQ_PIN 29
72+
// #define RST_PIN 28
73+
// #define I2C_BUS 0
74+
75+
// State flags to manage sensor startup/state
76+
bool startNavigation = true;
77+
78+
// Used to track LED state
79+
bool ledState = false;
80+
81+
// Declare our sensor object. Note the SPI version of the sensor class is used.
82+
SfeFPC2534SPI mySensor;
83+
84+
//------------------------------------------------------------------------------------
85+
// Callback functions the library calls
86+
//------------------------------------------------------------------------------------
87+
// Unlike a majority of Arduino Sensor libraries, the FPC2534 library is event/callback driven.
88+
// The library calls functions you define when events occur. This allows your code to respond
89+
// to messages from the sensor. These messages are ready by calling the processNextResponse() function
90+
// in your main loop.
91+
//----------------------------------------------------------------------------
92+
// on_error()
93+
//
94+
// Call if the sensor library detects/encounters an error
95+
//
96+
static void on_error(uint16_t error)
97+
{
98+
// Just print the error code
99+
Serial.print("[ERROR] code:\t");
100+
Serial.println(error);
101+
}
102+
103+
//----------------------------------------------------------------------------
104+
// on_is_ready_change()
105+
//
106+
// Call when the device ready state changes
107+
//
108+
static void on_is_ready_change(bool isReady)
109+
{
110+
// On startup the device isn't immediately ready. A message is sent when it is.
111+
// The Library will call this function when that happens
112+
113+
if (isReady)
114+
{
115+
Serial.println("[STARTUP]\tFPC2534 Device is ready");
116+
117+
// do we need to start navigation mode?
118+
if (mySensor.currentMode() != STATE_NAVIGATION && startNavigation)
119+
{
120+
// Place the sensor in Navigation mode and print out a menue.
121+
startNavigation = false;
122+
fpc_result_t rc = mySensor.startNavigationMode(0);
123+
124+
// error?
125+
if (rc != FPC_RESULT_OK)
126+
{
127+
Serial.print("[ERROR]\tFailed to start navigation mode - error:");
128+
Serial.println(rc);
129+
return;
130+
}
131+
132+
Serial.println("[SETUP]\tSensor In Navigation mode.");
133+
Serial.println();
134+
Serial.println("\t- Swipe Up, Down, Left, Right to see events.");
135+
Serial.println("\t- Press to toggle LED on/off.");
136+
Serial.println("\t- Long Press to get firmware version.");
137+
Serial.println();
138+
}
139+
else
140+
Serial.println("[STATUS] \tFPC2534 Device is NOT ready");
141+
}
142+
}
143+
144+
//----------------------------------------------------------------------------
145+
// on_version()
146+
//
147+
// Call when the sensor sends a version string
148+
//
149+
static void on_version(char *version)
150+
{
151+
// just print the version string
152+
Serial.print("\t\t");
153+
Serial.println(version);
154+
}
155+
156+
//----------------------------------------------------------------------------
157+
// on_navigation()
158+
//
159+
// Call when the sensor sends a navigation event
160+
//
161+
static void on_navigation(uint16_t gesture)
162+
{
163+
Serial.print("[NAVIGATION]\t");
164+
switch (gesture)
165+
{
166+
case CMD_NAV_EVENT_NONE:
167+
Serial.println("NONE");
168+
break;
169+
case CMD_NAV_EVENT_UP:
170+
Serial.println("UP");
171+
break;
172+
case CMD_NAV_EVENT_DOWN:
173+
Serial.println("DOWN");
174+
break;
175+
case CMD_NAV_EVENT_RIGHT:
176+
Serial.println("RIGHT");
177+
break;
178+
case CMD_NAV_EVENT_LEFT:
179+
Serial.println("LEFT");
180+
break;
181+
case CMD_NAV_EVENT_PRESS:
182+
// Toggle the on-board LED
183+
Serial.print("PRESS -> {LED ");
184+
Serial.print(ledState ? "OFF" : "ON");
185+
Serial.println("}");
186+
ledState = !ledState;
187+
mySensor.setLED(ledState);
188+
break;
189+
190+
case CMD_NAV_EVENT_LONG_PRESS:
191+
// Request the firmware version from the sensor. The sensor will respond
192+
// with a version event that will call our on_version() function above.
193+
Serial.println("LONG PRESS -> {Get Version}");
194+
mySensor.requestVersion();
195+
break;
196+
default:
197+
Serial.println("UNKNOWN");
198+
break;
199+
}
200+
}
201+
202+
// ------------------------------------------------------------------------------------
203+
// Fill in the library callback structure with our callback functions
204+
//
205+
// This is passed to the library so it knows what functions to call when events occur.
206+
static sfDevFPC2534Callbacks_t cmd_cb = {0};
207+
208+
//------------------------------------------------------------------------------------
209+
// reset_sensor()
210+
//
211+
// Simple function to toggle the reset pin of the sensor
212+
//
213+
void reset_sensor(void)
214+
{
215+
// Reset the sensor by toggling the reset pin
216+
pinMode(RST_PIN, OUTPUT);
217+
digitalWrite(RST_PIN, LOW); // Set reset pin low
218+
delay(10); // Wait for 10 ms
219+
digitalWrite(RST_PIN, HIGH); // Set reset pin high
220+
delay(250); // Wait for sensor to initialize
221+
}
222+
223+
//------------------------------------------------------------------------------------
224+
// setup()
225+
//
226+
void setup()
227+
{
228+
delay(2000);
229+
230+
// Set up serial communication for debugging
231+
Serial.begin(115200); // Set baud rate to 115200
232+
while (!Serial)
233+
{
234+
; // Wait for serial port to connect. Needed for native USB port only
235+
}
236+
Serial.println();
237+
Serial.println("----------------------------------------------------------------");
238+
Serial.println(" SparkFun FPC2534 Navigation Example - I2C");
239+
Serial.println("----------------------------------------------------------------");
240+
Serial.println();
241+
242+
// Configure the CS ping
243+
pinMode(CS_PIN, OUTPUT);
244+
digitalWrite(CS_PIN, HIGH); // Set CS pin high as a start off point.
245+
246+
// Initialize the SPI communication
247+
SPI.begin();
248+
249+
// The sensor is available - Initialize the sensor library
250+
if (!mySensor.begin(CS_PIN, IRQ_PIN))
251+
{
252+
Serial.println("[ERROR]\tFPC2534 not found. Check wiring. HALT.");
253+
while (1)
254+
delay(1000);
255+
}
256+
Serial.println("[STARTUP]\tFPC2534 initialized.");
257+
258+
// Setup our callback functions structure
259+
cmd_cb.on_error = on_error;
260+
cmd_cb.on_version = on_version;
261+
cmd_cb.on_navigation = on_navigation;
262+
cmd_cb.on_is_ready_change = on_is_ready_change;
263+
264+
// set the callbacks for the sensor library to call
265+
mySensor.setCallbacks(cmd_cb);
266+
267+
// One last reset of the sensor = observation shows that this is needed after the above device ping...
268+
reset_sensor();
269+
270+
// Ready to go!
271+
Serial.println("[STARTUP]\tFingerprint system initialized.");
272+
}
273+
274+
//------------------------------------------------------------------------------------
275+
void loop()
276+
{
277+
278+
// Call the library to process the next response from the sensor. The library will call our above
279+
// callback functions as events occur.
280+
fpc_result_t rc = mySensor.processNextResponse();
281+
if (rc != FPC_RESULT_OK && rc != FPC_PENDING_OPERATION)
282+
{
283+
Serial.print("[ERROR] Sensor Processing Error: ");
284+
Serial.println(rc);
285+
}
286+
287+
delay(200);
288+
}

src/SparkFun_FPC2534.h

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121

2222
#include "sfTk/sfDevFPC2534.h"
2323
#include "sfTk/sfDevFPC2534I2C.h"
24+
#include "sfTk/sfDevFPC2534SPI.h"
2425
#include "sfTk/sfDevFPC2534UART.h"
26+
#include <Arduino.h>
2527

2628
// Make a Arduino friendly Address define
2729
#define SFE_FPC2534_I2C_ADDRESS kFPC2534DefaultAddress
@@ -92,4 +94,62 @@ class SfeFPC2534UART : public sfDevFPC2534
9294

9395
private:
9496
sfDevFPC2534UART _commUART;
97+
};
98+
99+
//--------------------------------------------------------------------------------------------
100+
// SPI version of the FPC2534 class
101+
//
102+
///
103+
104+
class SfeFPC2534SPI : public sfDevFPC2534
105+
{
106+
public:
107+
SfeFPC2534SPI()
108+
{
109+
}
110+
/**
111+
* @brief Initialize the sensor using SPI communication
112+
* @param spiPort Reference to the SPIClass object to use (default is SPI)
113+
* @param busSPISettings SPI settings to use for the bus
114+
* @param csPin Chip select pin number
115+
* @param interruptPin Pin number for the interrupt)
116+
* @param bInit Whether to initialize the SPI bus (default is false)
117+
* @return true if initialization was successful, false otherwise
118+
*/
119+
120+
bool begin(SPIClass &spiPort, SPISettings &busSPISettings, const uint8_t csPin, const uint32_t interruptPin,
121+
bool bInit = false)
122+
{
123+
124+
// Setup the SPI communication
125+
if (!_commSPIBus.initialize(spiPort, busSPISettings, csPin, interruptPin, bInit))
126+
return false;
127+
128+
// Okay, the bus is a go, lets initialize the base class
129+
130+
return sfDevFPC2534::initialize(_commSPIBus);
131+
}
132+
133+
/**
134+
* @brief Initialize the sensor using SPI communication
135+
*
136+
* @param csPin Chip select pin number
137+
* @param interruptPin Pin number for the interrupt (default is 255, meaning no interrupt)
138+
* @param bInit Whether to initialize the SPI bus (default is false)
139+
* @return true if initialization was successful, false otherwise
140+
*/
141+
bool begin(const uint8_t csPin, const uint32_t interruptPin, bool bInit = false)
142+
{
143+
144+
// Setup the SPI communication
145+
if (!_commSPIBus.initialize(csPin, interruptPin, bInit))
146+
return false;
147+
148+
// Okay, the bus is a go, lets initialize the base class
149+
150+
return sfDevFPC2534::initialize(_commSPIBus);
151+
}
152+
153+
private:
154+
sfDevFPC2534SPI _commSPIBus;
95155
};

src/sfTk/sfDevFPC2534SPI.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ bool sfDevFPC2534SPI::initialize(SPIClass &spiPort, SPISettings &busSPISettings,
3232
// clear out our data buffer
3333
clearData();
3434

35+
// init?
36+
if (bInit)
37+
_spiPort->begin();
38+
3539
return true;
3640
}
3741
//--------------------------------------------------------------------------------------------

0 commit comments

Comments
 (0)