Arduino library for the ProtoCentral tinyGSR electrodermal-activity (EDA / galvanic skin response) breakout — every hardware revision, one library.
Don't have one? Buy it here
| 🛒 Product page | https://protocentral.com/product/protocentral-tinygsr-gsr-eda-digital-output-sensor-board-qwiic-stemma-qt/ |
| 🔧 Hardware design files | https://github.com/Protocentral/protocentral_tinygsr_hardware |
| 🐍 MicroPython driver | https://github.com/Protocentral/protocentral-micropython-tinygsr |
| 📄 ADC datasheet (TI TLA2022) | https://www.ti.com/lit/ds/symlink/tla2022.pdf |
| 📄 Front-end op-amp (TI OPA2333) | https://www.ti.com/lit/ds/symlink/opa2333.pdf |
Current boards report an absolute skin conductance in microsiemens (µS) with no per-unit calibration, from a research-standard 0.5 V DC constant-voltage transimpedance front end. The original v1 board streamed a relative, hand-trimmed proxy instead, and is supported here in ADC-count mode.
One electrode sits at GND; the other is pinned at V_exc = 0.5 V by a zero-drift op-amp (OPA2333) in a transimpedance loop. The skin draws I = V_exc · G_skin, which a precision feedback resistor R_f = 39.2 kΩ converts to a voltage. The ADC reads it differentially (AIN0 = V_out, AIN1 = V_exc), so the 0.5 V pedestal is subtracted in hardware and only the conductance-proportional term I·R_f is digitised:
G[µS] = V_diff / (V_exc · R_f) × 1e6 V_exc ≈ 0.5007 V, R_f = 39.2 kΩ
Because V_exc and R_f are known precision quantities, counts map to µS deterministically — two boards agree with each other, and a reading taken today is comparable with one from next month.
| Revision | begin() argument |
Front end | ADC address | Reports |
|---|---|---|---|---|
| v3 (current) · v2 | TINYGSR_REV_V3 (default) |
OPA2333 constant-voltage TIA, R_f 39.2 kΩ 0.1 % | 0x48 |
absolute µS + resistance, Rcal self-check |
| v1 (original) | TINYGSR_REV_V1 |
LMV324 with a 200 kΩ trimpot | 0x49 |
relative ADC counts only |
The revision cannot be detected at runtime — both boards present the same TLA2022, and either one's ADDR jumper can be moved — so you state it at begin(). Leave the constructor's address at its default and begin() resolves 0x48 or 0x49 to match; pass an address explicitly and that always wins.
On a v1 board readConductance(), readResistance() and readFiltered() return NAN. Its gain is set by a trimpot turned by hand, so nothing maps counts to microsiemens, and returning a plausible-looking number that means nothing would be worse than saying so. Use readCounts() / readCountsFiltered() — the signal shape EDA analysis actually uses is unaffected. v1 owners still gain from this library: it replaces the old TLA20xx + FIR dependency pair with one self-contained install.
- Absolute skin conductance in microsiemens (µS) and resistance in ohms
- Built-in 8-tap moving-average smoothing — no external filter library
- One-point self-calibration against the board's on-board 100 kΩ 0.1 % Rcal (= 10.00 µS)
- No-contact and over-range flags so a bad electrode is visible in software
- Raw voltage and raw ADC-count escape hatches for power users
- ADC-agnostic transfer function (
conductanceFromVoltage) for a 16-bit ADS111x front end - Supports every tinyGSR revision from one library
- Standalone —
depends=is empty; nothing else to install - I²C / Qwiic / STEMMA QT — Arduino, ESP32, Nano 33 BLE, RP2040 and other 3.3 V or 5 V hosts
- Open the Arduino IDE
- Go to Sketch → Include Library → Manage Libraries
- Search for "ProtoCentral tinyGSR"
- Click Install
- Download or clone this repository
- Copy it into your Arduino libraries folder (
~/Documents/Arduino/libraries/) - Restart the Arduino IDE
| tinyGSR pin | Arduino connection | Pin function |
|---|---|---|
| VCC | 3.3 V or 5 V | Power supply (3.3 V – 5 V) |
| GND | GND | Ground |
| SDA | A4 (or the board's SDA pin) | I²C data |
| SCL | A5 (or the board's SCL pin) | I²C clock |
Or skip the wiring entirely: plug a Qwiic / STEMMA QT cable into either of the board's two connectors. I²C pull-ups are on board, and the second connector daisy-chains the next device.
Attach Ag/AgCl electrodes to the supplied 3.5 mm snap lead and place them on two fingers of the same hand, or on the thenar and hypothenar of the palm. Non-polarizable Ag/AgCl electrodes are required for a stable DC baseline — dry or steel contacts drift.
#include <Wire.h>
#include "protocentral_TinyGSR.h"
TinyGSR gsr;
void setup() {
Serial.begin(115200);
Wire.begin();
gsr.begin(); // v2/v3 board; pass TINYGSR_REV_V1 for an original v1
}
void loop() {
Serial.println(gsr.readFiltered(), 3); // smoothed conductance in µS
delay(100);
}A relaxed tonic level is typically ~1–20 µS. A deep breath, a sudden sound, or mental arithmetic should produce a phasic bump (SCR) rising within ~1–3 s.
TinyGSR gsr(0x49); // explicit address always wins over the revision default
gsr.begin(TINYGSR_REV_V1);The v2/v3 board carries a precision Rcal = 100 kΩ (= 10.00 µS) behind the jumper marked SHORT FOR CAL (open in normal use). To verify or calibrate:
- Remove the subject and close the jumper
- Call
calibrate()— the reading should be 10.00 µS, and the scale factor is stored so R_f, V_exc and ADC-gain tolerances are folded out - Open the jumper before measuring a subject
See the 02-Self-Check-Calibration example. There is no Rcal on a v1 board, so calibrate() is a no-op there.
| Method | Description |
|---|---|
TinyGSR(addr = TINYGSR_ADDR_AUTO, wire = &Wire) |
Constructor. AUTO lets begin() pick the address for the revision. |
begin(rev = TINYGSR_REV_V3) |
Configure the ADC for the revision; returns false if it does not ACK. |
isConnected() |
Whether the ADC ACKs on the bus. |
revision() / address() |
What begin() selected. |
| Method | Returns | Description |
|---|---|---|
readConductance() |
float |
Absolute skin conductance, µS. NAN on v1. |
readFiltered() |
float |
8-tap moving-average conductance, µS. NAN on v1. |
readResistance() |
float |
Skin resistance, ohms (INFINITY when open). NAN on v1. |
readVoltage() |
float |
Raw differential front-end voltage, V. |
readCounts() |
int16_t |
Signed 12-bit ADC result — every revision. |
readCountsFiltered() |
float |
8-tap moving-average ADC counts — every revision. |
conductanceFromVoltage(v) |
float |
µS from a differential voltage (custom / 16-bit front end). |
| Method | Returns | Description |
|---|---|---|
isContact() |
bool |
Electrodes appear connected. |
isOverRange() |
bool |
Reading is saturating near full scale. |
calibrate(known_us) |
void |
One-point cal against the on-board Rcal. No-op on v1. |
setCalibration(scale) / getCalibration() |
Get or set the stored scale factor. | |
setExcitation(v) / setFeedbackResistor(ohms) |
Override the front-end constants. |
| Constant | Value | Description |
|---|---|---|
TINYGSR_REV_V3 / TINYGSR_REV_V1 |
0 / 1 |
Board revision passed to begin() |
TINYGSR_ADDR_AUTO |
0xFF |
Resolve the I²C address from the revision |
TINYGSR_DEFAULT_ADDRESS_V3 / _V1 |
0x48 / 0x49 |
Per-revision ADC address |
TINYGSR_RCAL_US |
10.0 |
On-board calibration resistor, in µS |
TINYGSR_VEXC_DEFAULT |
0.5007 |
Excitation voltage, V |
TINYGSR_RF_DEFAULT |
39200.0 |
TIA feedback resistor, Ω |
| Example | Description |
|---|---|
01-Basic-Conductance-Read |
Print absolute µS and resistance with contact / over-range flags |
02-Self-Check-Calibration |
Verify against the on-board Rcal and store a one-point calibration |
03-OpenView |
Stream to the OpenView app — select "tinyGSR Breakout" from the Board dropdown |
04-V1-Legacy-Board |
Read an original v1 board in ADC-count mode |
The OpenView example emits the ProtoCentral v3 frame (0x0A 0xFA | LEN | 0x02 | 8-byte payload | 0x00 0x0B) over USB serial at 57600 baud — deliberately different from the 115200 the other examples use. Its payload's resistance slot is an int16 in ohms, which EDA skin resistance overflows, so it is left at 0 and the ADC count carries the signal; absolute µS stays available through the API.
- Ag/AgCl electrodes are strongly recommended; the biggest real-world accuracy limits are electrode half-cell offset and E1-node leakage, not the circuit.
- EDA bandwidth is DC – ~5 Hz (phasic SCRs ~0.05 – 1 Hz); the front end low-passes at ~18 Hz.
- Safety: 0.5 V, ≤ 50 µA into skin. Non-medical — for research and education only.
| Hardware design files (CERN-OHL-P v2) | https://github.com/Protocentral/protocentral_tinygsr_hardware |
| MicroPython / Raspberry Pi driver | https://github.com/Protocentral/protocentral-micropython-tinygsr |
| OpenView companion app | https://github.com/Protocentral/protocentral_openview |
| Getting-started guide | https://protocentral.com/product/protocentral-tinygsr-gsr-eda-digital-output-sensor-board-qwiic-stemma-qt/docs/getting-started/ |
MIT — see LICENSE. The tinyGSR hardware design files are licensed CERN-OHL-P v2.
Copyright (c) 2026 ProtoCentral Electronics.
