I2C communication
Hi all,
I have a MetaWear RG device:
Model Number: 1
Firmware Revision: 1.2.5
Hardware Revision: 0.3
I use the Metawear-SampleAndroid App with metawear library version 2.6.5 to communicate with the MetaWear RG device.
The goal is to send commands to a NFC device, which is attached to the MetaWear over the I2C bus.
The electrical connection seems to be OK. If I write 0x01and read 1 byte, then I get a 0x00.
System.out: Device: 0x24 Register: 0x00
System.out: Write CMD with length: 1
System.out: Try to read:
System.out: Result: 0x00 0x80 0x80 0x80 0x80 0x80 0x80
Now, when I try to send a real command to the device, I get nothing back, there is simply no response.
This is the code I use:
http://pastebin.com/yLXH6Yq6
This resulting output is:
10-19 20:54:37.265 19738-19738/com.mbientlab.metawear.app I/System.out: Device: 0x24 Register: 0x00
10-19 20:54:37.265 19738-19738/com.mbientlab.metawear.app I/System.out: Write CMD with length: 9
10-19 20:54:37.770 19738-19738/com.mbientlab.metawear.app I/System.out: Try to read:
I've tested the NFC device with my Raspberry, so the NFC device is working fine. On the Raspberry I used a small NodeJS script to send the same command to the NFC device over I2C.
var sleep = require('sleep');
var util = require('util');
var pn532 = require('pn532');
var i2c = require('i2c');
function toBuffer(bytes) {
return new Buffer(bytes);
}
var wire = new i2c(pn532.I2C_ADDRESS, {device: '/dev/i2c-1'});
// firmware
var byteArray = [0x00, 0x00, 0xff, 0x02, 0xfe, 0xd4, 0x02, 0x2a, 0x00];
console.log("Write Bytes: ", toBuffer(byteArray));
function cmdFw() {
wire.write(byteArray , function(err) {
console.error("Error: " + err);
});
}
function ack() {
wire.read(7, function(err, res) {
// result contains a buffer of bytes
console.log("Read Ack: ", toBuffer(res));
});
}
function resFw() {
wire.read(20, function(err, res) {
// result contains a buffer of bytes
console.log("Read FW: ", toBuffer(res));
});
}
cmdFw();
setTimeout(function() {
ack();
setTimeout(resFw, 100);
}, 100);
The resulting output is:
Write Bytes: <Buffer 00 00 ff 02 fe d4 02 2a 00>
Error: null
Read Ack: <Buffer 81 00 00 ff 00 ff 00>
Read FW: <Buffer 81 00 00 ff 06 fa d5 03 32 01 06 07 e8 00 00 00 00 00 00 00>
This is also the expected output as documented in:
https://cdn-shop.adafruit.com/datasheets/PN532C106_Application+Note_v1.2.pdf
1. send the command
2. read acknowledge
2. read the result of the command
I would like to know how to debug the issue?
I look forward to receiving your continued support.
I have a MetaWear RG device:
Model Number: 1
Firmware Revision: 1.2.5
Hardware Revision: 0.3
I use the Metawear-SampleAndroid App with metawear library version 2.6.5 to communicate with the MetaWear RG device.
The goal is to send commands to a NFC device, which is attached to the MetaWear over the I2C bus.
The electrical connection seems to be OK. If I write 0x01and read 1 byte, then I get a 0x00.
byte[] cmd = new byte[]{0x01,};The resulting output is:
System.out.println("Write CMD with length: " + cmd.length);
i2cModule.writeData(deviceAddr, registerAddr, cmd);
Thread.sleep(100);
System.out.println("Try to read: ");
i2cModule.readData(deviceAddr, registerAddr, (byte) 7).onComplete(new CompletionHandler<byte[]>() {
@Override
public void success(byte[] result) {
System.out.println("Result: " + arrayToHexString(result));
}
});
System.out: Device: 0x24 Register: 0x00
System.out: Write CMD with length: 1
System.out: Try to read:
System.out: Result: 0x00 0x80 0x80 0x80 0x80 0x80 0x80
Now, when I try to send a real command to the device, I get nothing back, there is simply no response.
This is the code I use:
http://pastebin.com/yLXH6Yq6
This resulting output is:
10-19 20:54:37.265 19738-19738/com.mbientlab.metawear.app I/System.out: Device: 0x24 Register: 0x00
10-19 20:54:37.265 19738-19738/com.mbientlab.metawear.app I/System.out: Write CMD with length: 9
10-19 20:54:37.770 19738-19738/com.mbientlab.metawear.app I/System.out: Try to read:
I've tested the NFC device with my Raspberry, so the NFC device is working fine. On the Raspberry I used a small NodeJS script to send the same command to the NFC device over I2C.
var sleep = require('sleep');
var util = require('util');
var pn532 = require('pn532');
var i2c = require('i2c');
function toBuffer(bytes) {
return new Buffer(bytes);
}
var wire = new i2c(pn532.I2C_ADDRESS, {device: '/dev/i2c-1'});
// firmware
var byteArray = [0x00, 0x00, 0xff, 0x02, 0xfe, 0xd4, 0x02, 0x2a, 0x00];
console.log("Write Bytes: ", toBuffer(byteArray));
function cmdFw() {
wire.write(byteArray , function(err) {
console.error("Error: " + err);
});
}
function ack() {
wire.read(7, function(err, res) {
// result contains a buffer of bytes
console.log("Read Ack: ", toBuffer(res));
});
}
function resFw() {
wire.read(20, function(err, res) {
// result contains a buffer of bytes
console.log("Read FW: ", toBuffer(res));
});
}
cmdFw();
setTimeout(function() {
ack();
setTimeout(resFw, 100);
}, 100);
The resulting output is:
Write Bytes: <Buffer 00 00 ff 02 fe d4 02 2a 00>
Error: null
Read Ack: <Buffer 81 00 00 ff 00 ff 00>
Read FW: <Buffer 81 00 00 ff 06 fa d5 03 32 01 06 07 e8 00 00 00 00 00 00 00>
This is also the expected output as documented in:
https://cdn-shop.adafruit.com/datasheets/PN532C106_Application+Note_v1.2.pdf
1. send the command
2. read acknowledge
2. read the result of the command
I would like to know how to debug the issue?
I look forward to receiving your continued support.
This discussion has been closed.
Comments
Write Bytes: <Buffer 00 aa ff 02 fe d4 02 2a ff>
Error: null
Read Ack: <Buffer 00 80 80 80 80 80 80>
Read FW: <Buffer 00 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80>
This is the same pattern as with MetaWear sending a My experiments with MetaWear I2C show if I send: the result is:
System.out: Device: 0x24 Register: 0x00
System.out: Write CMD with length: 3
System.out: Try to read:
System.out: Result: 0x00 0x80 0x80 0x80 0x80 0x80 0x80
if I send then there is no response and I need to disconnect the MetaWear from the NFC and connect it again to get a successful communication with the NFC device.
My conclusion is that there is some problem with sending 0xFF.
http://pastebin.com/yLXH6Yq6
see my code in line 33
i2cModule.readData(deviceAddr, registerAddr, (byte) nBytes).onComplete(new CompletionHandler<byte[]>()
first write data, then read data
this is what I did
Using an RPro board, I wrote 2 config registers (0xf4, & 0xf5) and read it back with no issues as well.
I could only look briefly at the spec for the NFC chip. They seem to have tunneled a custom protocol through i2c in an unconventional manner.
The big difference between your node code and the MetaWear API code, is that the MetaWear API Read performs a register read and not a raw read.
Basically, the register read operation first writes an address to read from, and then it reads. This is how i2c sensors normally work. A cursory look at the NFC datasheet suggests that the write should be ignored, but it would be best to verify the behavior is the same on the Raspberry.
Could you try writing a single byte of 0x00 before your ack read to see how the NFC chip responds?
I think you are right, if I write single byte 0x00 before ACK in RPi it fails as with MetaWear API
I hope I understood you right, please see the nodejs code to verify:
var sleep = require('sleep');
var util = require('util');
var pn532 = require('pn532');
var i2c = require('i2c');
function toBuffer(bytes) {
return new Buffer(bytes);
}
var wire = new i2c(pn532.I2C_ADDRESS, {device: '/dev/i2c-1'});
// firmware
var byteArray = [0x00, 0x00, 0xff, 0x02, 0xfe, 0xd4, 0x02, 0x2a, 0x00];
console.log("Write Bytes: ", toBuffer(byteArray));
function cmdFw() {
console.log("Write Cmd FW");
wire.write(byteArray , function(err) {
if (err){
console.error("Error: " + err);
}
});
}
function ack() {
console.log("Read ACK");
wire.read(7, function(err, res) {
// result contains a buffer ofbytes
console.log("Ack: ", toBuffer(res));
});
}
function resFw() {
console.log("Read FW");
wire.read(20, function(err, res) {
// result contains a buffer ofbytes
console.log("FW: ", toBuffer(res));
});
}
function writeZero() {
var zeroByteArray = [0x00];
console.log("Write Zero");
wire.write(zeroByteArray , function(err) {
if (err) {
console.error("Write Zero Error: " + err);
}
});
}
cmdFw();
setTimeout(function() {
writeZero();
setTimeout(function () {
ack();
setTimeout(resFw, 200);
}, 200);
}, 200);
The resulting output after two executions is:
first:
Write Bytes: <Buffer 00 00 ff 02 fe d4 02 2a 00>
Write Cmd FW
Write Zero
Read ACK
Ack: <Buffer >
Read FW
FW: <Buffer >
second:
Write Bytes: <Buffer 00 00 ff 02 fe d4 02 2a 00>
Write Cmd FW
Error: Error: Cannot write to device
Write Zero
Write Zero Error: Error: Cannot write to device
Read ACK
Ack: <Buffer >
Read FW
FW: <Buffer >
Which options do I have now? As I understand, the MetaWear API do more than it should, but because the NFC-Chip has custom protocol it's not possible to use MetaWear API to cummunicate with the NFC-Chip.
Do you have a hint for a workaround?
Would it be feasible to provide rawRead and rawWrite methods in MetaWear API?
The simplest option would be to switch to the SPI bus for communication. The protocol they are using is really meant for a UART and poorly adapted for I2C and SPI. It should work with our SPI API which handles more raw operations which are typical to SPI protocols.
A second option would be to further investigate the chips behavior in response to the I2C read format, to see if there is a workaround to get the chip to accept it. According to statements in the datasheet the write should be ignored, but the behavior you are observing does not match. This will require detailed study of the datasheet and experimentation. From my brief look at the datasheet it is not among the most straightforward, I would avoid this option if possible.
Removing the register-centric nature of MetaWear I2C would require modifications to our stack spanning several abstraction layers. The existing implementation works for every native driver we have, as well as nearly all I2C based sensors. Unfortunately, that means adding raw methods would be both high cost and low impact. It would be more appropriate for us to release a UART implementation than rework I2C, but your best option is to switch to SPI.
could you tell me where I can find documentation for SPI and how to connect the sensor to the MetaWear RG board?
so far I've found the SW API under: https://mbientlab.com/androiddocs/latest/spi.html
but where do get the doc for electrical interface, currently I use "Product Specification v0.8" as the reference but there is nothing about SPI
For a SPI bus you need to connect four signals:
On the MetaWear side, you can assign any GPIO to any of these functions. So if you just connect the four target signals to MetaWear, you can assign their functions via the API.
There are some differences with slaves as to when they expect the clock and data to change. MetaWear follows the ARM standard definition for "SPI Mode" that is described here: https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus#Mode_numbers . MetaWear can create any of the timing modes as necessary.