Alternating between I2C and A4/A5 analog inputs (Arduino Nano 33 IoT)

Hi all. I know the A4/A5 analog inputs in the Nano 33 IoT are also used for I2C SDA/SCL and one should choose which one to use. However I have a project that uses the IMU and crypto units via I2C and I could use those two analog inputs. Never mind the 4.7k pull-ups, I can make it work via either an analog MUX or using analog sources with high output impedance and correcting in software.
My problem is that reading A4/A5 with analogRead(), even once, breaks the I2C. See code below:

//////////////////////////////////////////////////////////////////
//
// Example of analogRead() breaking I2C
// AP2023.
//
//////////////////////////////////////////////////////////////////

#include <Arduino.h>
#include <Arduino_LSM6DS3.h>

void setup(void) {
  Serial.begin(9600);
  while (!Serial)
    yield();
  if (IMU.begin())
    Serial.println("IMU started");
  else
    Serial.println("IMU start failed");
}

void loop(void) {
  while (!IMU.accelerationAvailable())
    ;
  float ax, ay, az;
  IMU.readAcceleration(ax, ay, az);
  Serial.print("Acceleration = (");
  Serial.print(ax, 3);
  Serial.print(", ");
  Serial.print(ay, 3);
  Serial.print(", ");
  Serial.print(az, 3);
  Serial.println(")");
  float temp = analogRead(A4);
  delay(1000);
}

The first call to IMU.readAcceleration() works fine, the second fails due to analogRead() messing up the pins' configuration. Here is the output:

IMU started
Acceleration = (0.010, 0.026, 1.031)
Acceleration = (0.024, 1.000, 3.994)
Acceleration = (0.024, 1.000, 3.994)
Acceleration = (0.024, 1.000, 3.994)
Acceleration = (0.024, 1.000, 3.994)
Acceleration = (0.024, 1.000, 3.994)
...

The first output (0.010, 0.026, 1.031) is the actual XYZ acceleration, the subsequent (0.024, 1.000, 3.994) are corrupted values.
Surely there is a way to restore those two pins to their pristine state after analogRead()? I just don't know how. I tried using pinMode() after analogRead() but that didn't work. Thanks!
Andrea

You have to disconnect the analog sources and call Wire.begin() or IMU.begin() again.

Would it be good, possible or beneficial to call IMU.end(), or Wire.end() beforehand?

It won't hurt :wink:

Actually, adding IMU.begin() just before IMU.readAcceleration() did the trick. Thanks!!!
I may have to deal with some overhead but that's a huge improvement already.
For reference, here is the fix:

void loop(void) {
  while (!IMU.accelerationAvailable())
    ;
  float ax, ay, az;
  IMU.begin();
  IMU.readAcceleration(ax, ay, az);
  ...

Will this work with I2C disabled?

It did for that one test, but I guess it was dumb luck. My guess is that accelerationAvailable() happens to return 1 when the I2C readout is corrupted. Thanks for pointing it out!

Update: I was able to use both the I2C and the A4/A5 without an analog multiplexer. Just isolate the analog voltage source from the A4/A5 pin with a medium-value resistor (I picked 22k, but anything between 10k-100k will work). Then compensate in software for the 4.7k/22k voltage divider. And of course call IMU.begin() before reading the IMU, and ECCX08.begin() before using the crypto chip since reading A4/A5 messes up the wire interface.
Thanks again for your help!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.