In a previous post Bee Healthy - Blog 6: Hardware Development - Lora Module, I had described the interface between the NIcla Sense ME and the MKR WAN 1310 board. Using the Nicla Vision with the MKR WAN 1310 uses an identical piggyback mounting, but the software setup is slightly different. The Nicla Sense uses the Arduino_BHY2 and Arduino_ BHY2Host libraries to handle the I2C transactions (they provide the interface to the Wire library). For the Nicla Vision I will need to configure the Wire interface directly with the MKR WAN 1310 as the controller and the NIcla Vision as the peripheral. Should be a simple exercise, but it's always a good idea to try modifying some working example code first.
I am going to try using the Nicla Vision and Nicla Sense on the same I2C bus with the Nicla Vision piggybacked on the MKR WAN 1310 and the Nicla Sense at the end of a 12"-18" extension cable. I saw in the Nicla Shield code that its I2C address is defined as 0x1A. I think this is a fairly arbitrary assignment, so to avoid conflict I going to assign the Nicla Vision address to be 0x1B. As a test, I'm going to send readings from the Proximity Sensor to the Things Stack console using the I2C interface to the MKR WAN 1310.
Note added April 21 2023 - Nicla Vision did not work as a piggyback on MKR WAN 1310. When both boards powered up the MKR WAN 1310 Reset pin was being held asserted by the Nicla Vision D3 pin on J2-5. It seems to be configured as an input with a weak pulldown (must be the default). I'll need to figure this out later, but because I am short on time - I just cut the pin off the Nicla male header and things are working.
Nicla Vision does not work as I2C peripheral!!
Well as in all development, sometimes things that you assume will work - don't...
I've been taking baby steps with this project because there is a lot of different software to integrate. I had wriiten the code I described above to program the Nicla Vision as an I2C peripheral to send proximity sensor data upon request to the MKR WAN 1310 which is programmed as the I2C controller and it forwards this data to the Things console. I plugged the boards together, powered up and the MKR WAN 1310 connected through the gateway to the Things console - but there was no data being received. I immediately assumed that I had plugged the boards together incorrectly, but luckily everything was correct and I hadn't smoked anything...
I decided to separate the two boards and plug them into a breadboard, so that I would have better debug access to the signals and could have both of the boards connected simultaneously to the host computer via USB for program updates (even though it is probably safe - I never like to connect the power from two different USB ports together).
Since the Nicla Sense was working correctly, my next guess was that there was a difference between the the two boards in terms of I2C pullups - and sure enough the schematics showed that the Nicla Sense had 10K pullups and the Nicla Vision had none. Since I am testing first with only the Nicla Vision on the bus, there would be no pullups.
Nicla Sense
Nicla Vision
It was simple enough to add 10K resistors on the breadboard - but that didn't fix it. Time to start probing.
A quick look with the oscilloscope showed that the signals looked okay - I even removed the 10K resistors and the levels looked fine (I have to figure that one out). I decided that to eliminate possible coding errors, that I would just try some examples that come with the Arduino Wire library (master_reader for the MKR WAN 1310 and slave_sender for the Nicla Vision).
It is interesting that Wire library examples don't show up for the nicla_mbed boards but they do for the MKR WAN 1310.
The examples are a simplified version of what I want to do. Basically, the controller (master) is requesting a six byte string ("hello ") from the peripheral (slave) at address 2 using a requestFrom().
Wire.requestFrom(2, 6); // request 6 bytes from slave device #2
master_reader.ino
// Wire Master Reader
// by Nicholas Zambetti <http://www.zambetti.com>
// Demonstrates use of the Wire library
// Reads data from an I2C/TWI slave device
// Refer to the "Wire Slave Sender" example for use with this
// Created 29 March 2006
// This example code is in the public domain.
#include <Wire.h>
void setup()
{
Wire.begin(); // join i2c bus (address optional for master)
Serial.begin(9600); // start serial for output
}
void loop()
{
Wire.requestFrom(2, 6); // request 6 bytes from slave device #2
while(Wire.available()) // slave may send less than requested
{
char c = Wire.read(); // receive a byte as character
Serial.print(c); // print the character
}
delay(500);
}
slave_sender.ino
// Wire Slave Sender
// by Nicholas Zambetti <http://www.zambetti.com>
// Demonstrates use of the Wire library
// Sends data as an I2C/TWI slave device
// Refer to the "Wire Master Reader" example for use with this
// Created 29 March 2006
// This example code is in the public domain.
#include <Wire.h>
void setup()
{
Wire.begin(2); // join i2c bus with address #2
Wire.onRequest(requestEvent); // register event
}
void loop()
{
delay(100);
}
// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent()
{
Wire.write("hello "); // respond with message of 6 bytes
// as expected by master
}
These programs are pretty simple as you can see from the code, but they did not work. Time to see what's happening on the oscilloscope. I also decided to try out a logic pirate logic analyzer that I got at a Black Friday sale a few years ago. Here's my setup:
Here's the scope capture:
The I2C clock was running at 100KHz, so that shouldn't stress the timing.
And the protocol analysis from the logic analyzer:
The problem is quite blatant, so I guess the scope picture is sufficient. The Nicla_Vision is not acknowledging (NACK) the address read that is generated by the requestFrom().
The byte sent from the MKR WAN 1310 is 0x05 which is the address 2 (0x2) followed by the read bit (0x1). The next bit should have been an ACK (0x0), but it high because the Nicla Vision did not assert its SDA line.
As a quick experiment, I programmed a Seeed Xiao with the same slave_sender code and it worked correctly acknowledging and sending the requested string.
Here are captures of that response:
The NACK occurs after the string has been sent.
MKR WAN 1310 I2C clock cannot be programmed correctly to less than 100KHz using the Wire library
One possible way to mitigate timing issues is to slow down the I2C clock. The clock is currently running at the default 100KHz. First, I programmed it to a higher frequency (400KHz) and the problem persisted. I then tried to program the frequency to 10KHz, but the frequency instead increased to over 100KHz. In fact, other frequencies like 20KHz, 50KHz, 80KHz also caused the clock to be some value above 100KHz. Programming values above 100KHz would produce the correct frequency (the clock is only spec'ed to 400KHz - at 1MHz it produced 800KHz). So, there is some algorithm problem in the Wire library for values under 100KHz (using function Wire.setClock()).
I did verify that I am using the latest board libraries (which include the Wire library). For the MKR WAN 1310, I am using version 1.8.13 of the Arduino SAMD boards. For the Nicla Vision, I am using version 4.0.2 of the Arduino Mbed OS Nicla Boards. I am using version 1.8.13 of the standalone IDE. I guess I should really try using the Web compiler, but I've had problems with the Create Agent. Or maybe move to IDE 2.0, but I don't want to encounter a new learning curve at the moment unless someone knows if that would fix these problems. I'm sure the problems are associated with the specific versions of the board libraries I am using. I've tried asking for help on the Arduino forum, but there isn't a lot of response for Nicla boards.
Since I don't really want to start modifying libraries and the IDE version that I'm using really doesn't support debug very well anyway, I need to find a different approach.
Nicla Vision does work as an I2C controller
So, I tried to send data over I2C using the Nicla Vision as the controller and the MKR WAN 1310 as the peripheral using the other I2C example pair (master_writer and slave_receiver) and that worked. So, I tried sending proximity data from the Nicla Vision and that also worked. The problem with this configuration is that I can't share the bus with the Nicla Sense which is using the BHY2 and BHY2Host libraries with the Nicla Sense as the peripheral.
Switch to contingency setup
I had planned a contingency in case I couldn't get the Nicla Sense and Nicla Vision to coexist on the same I2C bus. I have a second MKR WAN 1310 and I will create an independent module for each sensor. I'm pretty sure that configuration will work with both the Things Stack and my Node-Red setup with MQTT. I'll try that next.