@Desan can you run the following Arduino project, please?
#include <stdio.h>
#include <array>
#include <cmath>
#include <limits>
// more reasonably-named macros that won't cause conflict when naming something max
// or calling some max() method
#define ar_max(a, b) a > b ? a : b
#define ar_min(a, b) a < b ? a : b
#ifdef ARDUINO
#include <Trill.h>
#undef max
#undef min
#define microsleep(a) delayMicroseconds(a);
static char mystr[100];
// after printing the string we place a null char at the beginning.
// Not doing so may cause a string to be repeatedly printed out. Not sure why
#define printf(...) snprintf(mystr, sizeof(mystr), __VA_ARGS__), Serial.print(mystr), mystr[0] = 0
#define TOCHAR(a) a
Trill::Device trillProbe(Trill& trill, int address)
{
return trill.probe(address);
}
int trillSetup(Trill& trill, Trill::Device device, int address)
{
return trill.setup(device, address);
}
template<typename T>
int trillReadAndStore(Trill& trill, T& reads, unsigned int n) {
if(!trill.requestRawData())
return 1;
for(size_t c = 0; c < trill.getNumChannels(); ++c) {
while(!trill.rawDataAvailable())
;
reads[c][n] = trill.rawDataRead();
}
return 0;
}
#else // linux
#include <libraries/Trill/Trill.h>
// macros to simplify sharing code with Arduino
#define TRILL_NONE NONE
#define microsleep(a) usleep(a)
#define TOCHAR(a) a.c_str()
const int i2cBus = 1;
Trill::Device trillProbe(Trill& trill, int address)
{
return trill.probe(i2cBus, address);
}
int trillSetup(Trill& trill, Trill::Device device, int address)
{
return trill.setup(i2cBus, device, address);
}
template<typename T>
int trillReadAndStore(Trill& trill, T& reads, unsigned int n)
{
if(trill.readI2C())
return 1;
for(size_t c = 0; c < trill.getNumChannels(); ++c)
reads[c][n] = trill.rawData[c] * 4096.f + 0.5f;
return 0;
}
#endif
template<size_t N, typename T>
class Stat
{
public:
T min;
T max;
T worst = std::numeric_limits<T>::min();
double avg = 0;
unsigned int count = 0;
int range() {
int range = max - min;
range = range > 0 ? range : -range;
return range;
}
double stdev() {
double deviations = 0;
for(auto v : vals) {
double dev = v - avg;
deviations += dev * dev;
}
double var = deviations / vals.size();
return std::sqrt(var);
}
void push(double v) {
if(shouldReset) {
min = std::numeric_limits<T>::max();
max = std::numeric_limits<T>::min();
avg = 0;
// do not reset worst
shouldReset = false;
next = 0;
}
min = ar_min(v, min);
max = ar_max(v, max);
worst = ar_max(max, worst);
acc += v;
count++;
avg = acc / (double)count;
vals[next++] = v;
if(next >= vals.size())
next = 0;
}
void reset() {
shouldReset = true;
}
private:
std::array<T, N> vals;
double acc = 0;
size_t next;
bool shouldReset = true;
};
constexpr size_t kNumReads = 1000;
constexpr size_t kMaxNumChannels = 30;
std::array<std::array<uint16_t, kNumReads>,kMaxNumChannels> reads;
std::array<Stat<kNumReads, uint16_t>,kMaxNumChannels> stats;
int main() {
Trill trill;
bool found = false;
for(uint8_t n = 0x20; n <= 0x50; ++n) {
Trill::Device device = trillProbe(trill, n);
if(device != Trill::TRILL_NONE) {
printf("%#4x (%3d) | %s\n", n, n, TOCHAR(Trill::getNameFromDevice(device)));
found = true;
trillSetup(trill, device, n);
break;
}
}
if(!found) {
printf("Error: no device found\n");
return 1;
}
microsleep(10000);
int prescaler = 2;
trill.setPrescaler(prescaler);
microsleep(8000);
// Unsure whether noise threshold and baseline matter when raw, but why not
trill.setNoiseThreshold(0);
microsleep(10000);
trill.updateBaseline();
microsleep(200000);
trill.setMode(Trill::RAW);
microsleep(10000);
size_t numChannels = trill.getNumChannels();
const unsigned int kSleepTime = 7000;
// spin a while in case there's anyhting that needs stabilising
for(unsigned int n = 0; n < 5; ++n) {
#ifdef ARDUINO
trill.requestRawData();
while(!trill.rawDataAvailable())
;
#else
trill.readI2C();
#endif
microsleep(kSleepTime);
}
int verbose = 0;
printf("Starting (should take approx %.1fs)\n", kSleepTime * kNumReads / 1000000.f);
for(unsigned int n = 0; n < kNumReads; ++n) {
if(verbose) {
if(n % 100 == 0)
printf("%d\n", n);
}
trillReadAndStore(trill, reads, n);
microsleep(kSleepTime);
}
verbose && printf("c=[\n");
for(size_t c = 0; c < numChannels; ++c) {
for(auto r : reads[c]) {
verbose && printf("%d ", r);
stats[c].push(r);
}
verbose && printf("\n");
}
verbose && printf("]\n");
printf("trill = [\n");
printf("%%ch count min avg max range std\n");
int worstrange = 0;
int worstrangeat = -1;
double worstdev = 0;
double totalstdev = 0;
int worstdevat = -1;
for(unsigned int n = 0; n < 2; ++n) {
// one dry run to find the worst cases followed by one run
// where we print and hihglight them
for(unsigned int c = 0; c < numChannels; ++c) {
auto& stat = stats[c];
double stdev = stat.stdev();
int range = stat.range();
if(0 == n) {
totalstdev += stdev;
worstdev = ar_max(stdev, worstdev);
worstrange = ar_max(range, worstrange);
}
if(1 == n) {
if(worstrange == range)
worstrangeat = c;
if(worstdev == stdev)
worstdevat = c;
printf("%3d %6d %8d %8.1f %8d ", c, stat.count, stat.min, stat.avg, stat.max);
printf("%8d%c %7.3f%c\n", range, range == worstrange ? '*' : ' ', stdev, stdev == worstdev ? '*' : ' ');
}
}
}
printf("];\n");
printf("%% %s, fw_rev %d, prescaler: %d, worstrange[%d]: %d, worstdev[%d]: %.3f, avstdev: %.3f\n",
TOCHAR(trill.getNameFromDevice(trill.deviceType())), trill.firmwareVersion(), prescaler,
worstrangeat, worstrange,
worstdevat, worstdev, totalstdev / numChannels);
return 0;
}
#ifdef ARDUINO
void setup() {
Serial.begin(115200);
#ifdef ESP32
// pick your pins here
Wire.setPins(47, 21);
// give some time to the host to open the USB port
delay(1000);
#endif // ESP32
printf("BEGIN\n");
main();
}
void loop() {
}
#endif // ARDUINO
I tested this on an ESP32-S3, hopefully it will work without issues on your Arduino Nano 33 BLE.
Run this without the flex PCB attached and with Trill powered from the 3.3V rail and run it on both the rev A and the rev C you have there. Btw, what is the digit after C in the revision number?