Executive Summary:
Try doing {Wire.end(); Wire.begin();} after turning Vext back on with sensors which are powered from Vext if you are having problems.
Explanation:
Sorry if this is written up somewhere else. I had no problems with the ESP32 boards using Vext so this was sort of unexpected on CubeCell. I recently found on a prototype using the CubeCell Board that two I2C sensors powered by Vext would not behave correctly after cycling Vext off and back on. They would work sometimes, but it was intermittent, and changing timing would affect that. This same sort of behavior seems to be in a couple other forum topics. Once you turn turn off Vext then you can’t reliably read the sensor when you repower it. Very annoying. And, just calling Wire.begin() won’t fix it.
In my debugging I checked pullup resisters on SDA/SCL and could see they were fine except when Vext powers off I can see SDA gets pulled down to ground. That doesn’t look healthy and was the first clue. Unfortunately, I’m looking for a low power design and don’t want to install pull up resisters that are active all the time. There needs to be a better answer.
After more testing I found that a 4 second long LowPower sleep with Vext powered on would totally fix the problem while a simple delay(4000) would not. That’s pretty awkward, but it was reliable. Again, not a low power design, and the 4 seconds seems to be variable based on some unknown factor. Once you do low power sleep long enough it always works. More testing also found that calling HW_Reset(0) would do it, which is simple, but even more awkward. It would be really nice if someone could really document what’s really happening as we enter and exit the low power sleeps.
This all gave me the clue that something in the boot sequence and in LowPower recovery is doing a reliable init on the I2C state, and simply re-executing Wire.begin() isn’t good enough. The clue was in looking at the Wire.cpp code I find there actually is an I2C_Start() call in TwoWire::begin(). That implies there might be an I2C_Stop() needed sometimes, which is conveniently called from TwoWire::end(). Could it be that doing a stop, and then doing a start is enough to get the I2C state back on track? Yes!! But, it cost me a couple of evenings thinking I’d wired things wrong.
Postscript: I think the Heltec designs are really excellent pieces of work and I haven’t had a single board fail unless I did something really gross. Unfortunately, I think the CubeCell is far more opaque than the ESP32 boards were, and it’s taking much more effort than it should to get simple stuff to work. More exposure on the embedded firmware would be a great help. Really.