Wire.read() returns only 7-bit bytes - arduino

I'm a newbie to both Arduino programming and I2C in general. I'm using an Arduino Micro to extract data from the capacitance sensor AD7150.
Now in trying to answer my question myself, I've seen the basic setup of the Wire I2C communication a lot, and I feel like I have it down. But for some reason, Wire.read() only ever returns 7-bit bytes to me when it should be 8 bits from all that I see and understand. Another problem is that even if I read out a register that should be stable, i.e. the Chip ID register, the output "wobbles" over time. Google hasn't helped so far. Maybe one of you has the magic answer?
#include <Wire.h>
#define AD 0x48
#define ID 0x17
byte data1;
byte data2;
uint16_t data_combined;
void setup() {
analogReference(EXTERNAL);
Wire.begin();
Serial.begin(9600);
}
void loop()
{
Wire.beginTransmission(AD);
Wire.write(ID);
Wire.endTransmission(); // I checked the output; is successful
delay(10);
Wire.requestFrom(0x48,2); // Unsure whether to ask for 1 or 2 bytes here; the ChipID, as far as I understand, should only be one byte, but I've been told that I2C transmissions always include at least 2 bytes
data1 = Wire.read(); // so I just save both bytes separately here.
data2 = Wire.read();
data_combined = word(data1,data2);
Serial.print("First byte from Chip ID register: ");
Serial.print(data1,BIN);
Serial.print(" | Second byte from Chip ID register: ");
Serial.print(data2,BIN);
Serial.print(" | Combined to make: ");
Serial.println(data_combined,BIN);
Serial.println("---");
delay( 200);
}

Related

How can i use SPI on Arduino Due to communicate with AD7124-8 correctly

I want to read data from AD7124-8 with arduino Due via SPI. I found several libraries, but i dont get anything back from my ADC modul. By using an Oscilloscope i made sure my Arduino sends data via MOSI, SCK and CS work aswell. Just the MISO dataline doesnt get me anything back.
I first used this library (https://github.com/NHBSystems/NHB_AD7124), but decided to use a much easier Code to just make sure everything is working fine. I tried to to talk to the communication register to get the ID of my device from the ID register. You can find the registers on page 39 of the datasheet :https://www.analog.com/en/products/ad7124-8.html .
Im sending 0x00 and 0x05 to get back the 0x14 which should be the correct ID. Just zeros arriving (shown by Osci).
I found a solution in a Forum, but im not sure about why it differs with the data sheet:
https://ez.analog.com/data_converters/precision_adcs/f/q-a/24046/ad7124-8-for-arduino-due
when i use it the code stops running at the Line: value[0] = SPI.transfer(0x00);
They send 0x40 at the beginning, too.
Here my simple Code:
#include <SPI.h>
// Physical Pins
const int csPin = 10;
int value[7] {0};
void setup() {
Serial.begin (9600);
pinMode(10,OUTPUT);
SPI.begin(10);
SPI.setClockDivider(10, 128);
SPI.setDataMode(SPI_MODE3);
}
void loop() {
digitalWrite(csPin, LOW);
//SPI.transfer(csPin, 0x00);
SPI.transfer(csPin,0x00,SPI_CONTINUE); //Tell Communication Register you are going to read ID register
SPI.transfer(csPin,0x05);
//SPI.transfer(csPin,0x00); //Get data from Communication Register
delay(1);
digitalWrite(csPin, HIGH);
delay(1);
Serial.print(value[0],HEX);
}
I hope someone can help me out.
Greetings
First of all, this may not related to your question, but you are using old SPI methods setClockDivider(), setDataMode(), and setBitOrder() that has been deprecated since 2014. It is recommend to use use transactional SPI APIs which I have some explanation here.
Secondly, according to datasheet page 85, to access the ID register, you send one-byte to specific which register that you need to communicate with. Your code send two bytes, 0x00 and 0x05, which is incorrect.
Furthermore, based on page 78 of the datasheet, in order to read a register, bit 6 need to be set to 1 for a read operation, and 0 for a write operation.
Try the following code:
#include <SPI.h>
#define READ_REGISTER 0B01000000 // bit 6 set to 1 for read operation
#define ID_REGISTER 0x05
const int csPin = 10;
void setup() {
Serial.begin (9600);
digitalWrite(csPin, HIGH); // set csPin to HIGH to prevent false trigger
pinMode(csPin,OUTPUT);
SPI.begin();
}
void loop() {
SPI.beginTransaction(SPISettings(84000000/128, MSBFIRST, SPI_MODE3));
digitalWrite(csPin, LOW);
SPI.transfer(READ_REGISTER | ID_REGISTER); // read register 5
uint8_t id = SPI.transfer(0x00); // get the id
digitalWrite(csPin, HIGH);
SPI.endTransaction();
Serial.print(id,HEX);
}

I2C Data Conversion -- Arduino

Im trying to read the pressure from a sensor using I2C. Per the datasheet, I am writing a start command (0xAA) and then reading the data in the pressure registers as bytes. (Reference picture below):
Registers of Pressure Data
Here is the code that I am using:
#include <Adafruit_I2CDevice.h>
#define I2C_ADDRESS 0x29
Adafruit_I2CDevice i2c_dev = Adafruit_I2CDevice(I2C_ADDRESS);
void setup() {
while (!Serial) { delay(10); }
Serial.begin(115200);
Serial.println("I2C device read and write test");
if (!i2c_dev.begin()) {
Serial.print("Did not find device at 0x");
Serial.println(i2c_dev.address(), HEX);
while (1);
}
Serial.print("Device found on address 0x");
Serial.println(i2c_dev.address(), HEX);
}
void loop(){
uint8_t buffer[7];
buffer[0] = 0xAA;
i2c_dev.write_then_read(buffer, 1, buffer, 2, false);
Serial.println();
Serial.print(buffer[0], HEX);
Serial.print(" ");
Serial.print(buffer[1]);
Serial.print(" ");
Serial.print(buffer[2]);
Serial.print(" ");
Serial.print(buffer[3]);
Serial.println();
delay(500);
}
The first Register (buffer[0]) is the status register, which is supposed to return 0x40 if the operation succeeded without any errors. However, I am getting 0x60 when I read the first register. Is my code incorrect?
Here is the datasheet for the pressure sensor: https://www.farnell.com/datasheets/3208001.pdf
0x40 is completed reading without error.
In datasheet you can read that "When the Busy bit in the Status byte is zero, this indicate that valid data is ready, and a full Data Read of all 7 bytes may be performed"
So i think you just need to wait some time (and poll status bit) and then read data.
Hi Stephen are you aware the 0x40 is written out in binary 01000000 and 0x60 01100000?
If you look at table 3 you can find the relevant bits in that return byte. The first 0 is bit 7. The first 1 bit 6 etc to bit 0 (the utmost right 0)
Bit 5 (the second 1 from the left) is 1, so that means the device is busy.
Sometimes i use a binary to hex calculator.
You could read out the value per x time and check if it will become 0x40 and then process the other data bytes.

SPI Arduino Interface with Absolute Encoder

I am trying to retrieve data from an RLS absolute rotary encoder via SPI through Arduino Uno. I have managed to learn the basics of SPI, but I can't seem to get this working. I keep printing the transfer data and keep getting 255.
I also use the recommended pins for Arduino Uno here: https://www.arduino.cc/en/reference/SPI
Here is the link to the Absolute Encoder DataSheet: https://resources.renishaw.com/en/details/data-sheet-orbis-true-absolute-rotary-encoder--97180
Any help is appreciated.
Here is my code I have been trying:
#include <SPI.h>
unsigned int data;
int CS = 10; //Slave Select Pin
// The SS pin starts communication when pulled low and stops when high
void setup() {
Serial.begin(9600);
RTC_init();
}
int RTC_init() {
pinMode(CS, OUTPUT);
SPI.begin();
SPI.setBitOrder(LSBFIRST); // Sets Bit order according to data sheet (LSBFIRST)
SPI.setDataMode(SPI_MODE2); // 2 or 3, Not sure (I have tried both)
digitalWrite(CS, LOW); // Start communications
/*
Commands List:
Command "1" (0x31) – position request (total: 3 bytes) + 4 for multi-turn
Command "3" (0x33) – short position request (total: 2 bytes) + 4 for multi-turn
Command "d" (0x64) – position request + detailed status (total: 4 bytes) + 4 for multi-turn
Command "t" (0x74) – position request + temperature (total: 5 bytes) + 4 for multi-turn
Command "v" (0x76) – serial number (total: 7 bytes)
*/
unsigned int data = SPI.transfer(0x33); // Data
digitalWrite(CS, HIGH); // End communications
return(data);
}
void loop() {
Serial.println(RTC_init());
}
First, you forgot to set your CS pin to output. That won't help.
void setup()
{
Serial.begin(9600);
digitalWrite(CS, HIGH); // set CS pin HIGH
pinMode(CS, OUTPUT); // then enable output.
}
SPI is a two way master/slave synchronous link, with the clock being driven by bytes being sent out by the master. This means that when transacting on SPI, you are expected to send out as many bytes as you want to receive.
As shown on the timing diagram on page 14 of the datasheet, you are expected to send one byte with the command, then as many null bytes as the response requires minus 1.
The diagram shows the clock being low at idle, and input bits being stable when the clock goes low, that's SPI mode 1.
To read the position, for a non-multiturn encoder.
unsigned int readEncoderPos()
{
// this initialization could be moved to setup(), if you do not use
// the SPI to communicate with another peripheral.
// Setting speed to 1MHz, but the encoder can probably do better
// than that. When having communication issues, start slow, then set
// final speed when everything works.
SPI.beginTransaction(SPISettings(1'000'000, MSBFIRST, SPI_MODE1));
digitalWrite(CS, LOW);
// wait at least 2.5us, as per datasheet.
delayMicroseconds(3);
unsigned int reading = SPI.transfer16(0x3300); // 0x3300, since we're sending MSB first.
digitalWrite(CS, HIGH);
// not needed if you moved SPI.beginTransaction() to setup.
SPI.endTransaction();
// shift out the 2 status bits
return reading >> 2;
}

Raspi I2C communication with Arduino issues with wiringPi

I'm experiencing unexpected results using wiringPi's wiringPiI2CWriteReg16() function, and I'm not sure if it's due to incorrect usage, or something else. This is the declaration for the function:
extern int wiringPiI2CWriteReg16 (int fd, int reg, int data);
There are notes within the wiringPiI2C.c file that state it resembles Linux's SMBus code, if that helps.
On my Arduino (both an Uno R3 and a Trinket Pro), I am running this pared-down sketch:
#include <Wire.h>
#define SLAVE_ADDR 0x04
void receive_data (int num_bytes){
Serial.print("bytes in: ");
Serial.println(num_bytes);
while(Wire.available()){
int data = Wire.read(); // tried char, uint8_t etc
Serial.println(data);
}
Serial.print("\n");
}
void setup() {
Serial.begin(9600);
Wire.begin(SLAVE_ADDR);
Wire.onReceive(receive_data);
}
void loop() {
delay(500);
}
I would think that Wire.read() would break things apart at the byte boundary, but that's not occurring in my case. Perhaps this is my issue... a misunderstanding.
Nonetheless, I have this C code (requires wiringPi v2.36+ to be installed):
// word.c
#include <wiringPiI2C.h>
void main (){
int fd = wiringPiI2CSetup(0x04);
wiringPiI2CWriteReg16(fd, 0x00, 255);
wiringPiI2CWriteReg16(fd, 0x01, 256);
}
Compiled like this:
gcc -o word word.c -lwiringPi
When run, ./word, I receive the following on my Arduino's serial output:
bytes in: 3
0
255
0
bytes in: 3
1
0
1
In the first call to wiringPiI2CWriteReg16(), I expect the first byte in the output to be zero (0x00) as that's the register address I'm requesting. The second byte (255) is also correct. The third byte (0) is meaningless from what I can tell (as I'm only sending in one byte as data).
However, in the second call to that function, I do get the correct output for the register (first byte as 0x01 == 1), but the second byte is zero, and the third byte has what appears to be the correct remainder (255 == one byte, + 1). The problem is, is that the second byte is 0.
The exact same effect happens if I pass in 511 or for that matter, any number as the data in the call.
My question is whether I'm missing something glaringly obvious (I'm relatively new to C and Arduino), and/or if I can get some pointers on how to troubleshoot this more thoroughly.
I found that the problem was in my Arduino code. In the official Raspi forums, Gordon tipped me off that the bytes are read in separately, LSB first. Throughout all of my searching, I hadn't come across that, and really didn't quite understand what was happening. After changing my I2C read loop code in my Arduino sketch to this:
while(Wire.available()){
Wire.read(); // throw away register byte
int16_t data = Wire.read(); // LSB
data += Wire.read() << 8; // MSB
Serial.print("data: ");
Serial.println(data);
}
...everything works. In effect, that's at least one way to read two-byte values over I2C on the Arduino and put the bytes back together.

Freescale Pressure Sensor MPL3115A2 I2C communication with Arduino

Does anyone have experience with the MPL3115A2 Freescale I2C pressure sensor?
I need to use it in a project concerning Arduino UNO r3, but I can't get communication between them correctly. Here is my code:
#include <Wire.h>
void setup(){
Serial.begin(9600);
/*Start communication */
Wire.begin();
// Put sensor as in Standby mode
Wire.beginTransmission((byte)0x60); //0x60 is sensor address
Wire.write((byte)0x26); //ctrl_reg
Wire.write((byte)0x00); //reset_reg
Wire.endTransmission();
delay(10);
// start sensor as Barometer Active
Wire.beginTransmission((byte)0x60);
Wire.write((byte)0x26); //ctrl_reg
Wire.write((byte)0x01); //start sensor as barometer
Wire.endTransmission();
delay(10);
}
void getdata(byte *a, byte *b, byte *c){
Wire.beginTransmission(0x60);
Wire.write((byte)0x01); // Data_PMSB_reg address
Wire.endTransmission(); //Stop transmission
Wire.requestFrom(0x60, 3); // "please send me the contents of your first three registers"
while(Wire.available()==0);
*a = Wire.read(); // first received byte stored here
*b = Wire.read(); // second received byte stored here
*c = Wire.read(); // third received byte stored here
}
void loop(){
byte aa,bb,cc;
getdata(&aa,&bb,&cc);
Serial.println(aa,HEX); //print aa for example
Serial.println(bb,HEX); //print bb for example
Serial.println(cc,HEX); //print cc for example
delay(5000);
}
The data I receive is : 05FB9 (for example). When I change the register address (see Wire.write((byte)0x01); // Data_PMSB_reg address), I expect the data to change, but it doesn't! Can you explain this to me?
You can find the documentation and datasheets on the NXP website.
I can't properly understand how they communicate with each other. I got communication between Arduino and some other I2C sensors with same communication protocol without any problem.
Your problem is likely due to the fact that the Freescale part requires Repeated-Start I2C communication to do reads. The original Arduino two-wire library (TWI library used by Wire), did not support Repeated-Start.
I know this because I had to rewrite TWI for one of my projects to support Repeated-Start (interrupt driven, both Master and Slave). Unfortunately I've never gotten around to uploading my code, but someone else did essentially the same thing here (at least for Master which is what you need):
http://dsscircuits.com/articles/arduino-i2c-master-library.html
Lose the Wire library and use their I2C library instead.

Resources