Notifications
Clear all

[Solved] Help needed with I2C and wire.h

18 Posts
3 Users
1 Likes
8,295 Views
(@pugwash)
Sorcerers' Apprentice
Joined: 5 years ago
Posts: 923
Topic starter  

I decided recently to bypass the DS3231 library and communicate directly with the DS3231 module with I2C and wire.h.

Setting the registers was a pretty easy task but when reading the registers I came up against a problem.

The registers were being read, but not starting at register 0x00.

This is the code I was using.

#include <Wire.h>

int ds3231_address = 0x68; //ds3231 address

// create an array to hold the values of the DS3231 register
char mByte[0x13];

void setup() {
Serial.begin(9600);
Wire.begin();

}

void loop() {

// request 19 bytes from the DS3231 and release the I2C bus
Wire.requestFrom(ds3231_address, 0x13, true);

int idx = 0;

// read the bytes into an array
while(Wire.available()) {

byte input = Wire.read(); // read each byte from the register
mByte[idx] = input; // store each single byte in the array
idx++;
}

for(int i = 0; i < 0x13; i++){

int ab = mByte[i];
Serial.print("Register: ");Serial.print(i, HEX);Serial.print(" ");Serial.println(ab, HEX);
}

delay(1000);

}

And this is the result.

Register: 0 0
Register: 1 59
Register: 2 15
Register: 3 47
Register: 4 60
Register: 5 15
Register: 6 29
Register: 7 10
Register: 8 B
Register: 9 0
Register: A 1B
Register: B FFFFFFC0
Register: C 50
Register: D 10
Register: E 22
Register: F 7
Register: 10 29
Register: 11 6
Register: 12 19

 

The content of register 0 should be 50h, this is in register C. Apart from that the register content is in the correct order just offset.

If anybody has any ideas about how to remedy this, I would be grateful.


   
Quote
Robo Pi
(@robo-pi)
Robotics Engineer
Joined: 5 years ago
Posts: 1669
 

I have no clue if this will work for you, but a while back I was using a PCA9685 servo controller board that also used wire I2C.  I too did away with the library and nothing would work.  The solution was extremely simple.   All I had to do was change int to uint16_t.  And that solved everything. 

Hopefully this might work in your case as well.

DroneBot Workshop Robotics Engineer
James


   
ReplyQuote
jscottbee
(@jscottbee)
Member
Joined: 5 years ago
Posts: 107
 

Yeah, there is a lot of mixed data types there. I would use just the byte type since that's was the what the I2c read returns.  If I remember, that part passes BCD data back and forth as well. None of this still may not be your issue though. If you can a logic analyzer, you may be able to see the raw of what it's sending.  I do love the knockoff Saleae Logic ones found on eBay.

Scott


   
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 5 years ago
Posts: 923
Topic starter  

I read somewhere that some I2C slave modules actually hold the SCL low, until all the registers have been fully updated, after receiving the data request interrupt. This module obviously doesn't.

I was wondering whether I could drop the SCL pin to low on the Arduino for a few microseconds in the sketch, before sending the Wire.read() command.


   
ReplyQuote
jscottbee
(@jscottbee)
Member
Joined: 5 years ago
Posts: 107
 

Worth a try. Are you using pull-ups on the I2C bus? I have learned by lots of errors that it's better to than not. 


   
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 5 years ago
Posts: 923
Topic starter  

I've got 10k pullup resistors on both SCL and SDA lines.


   
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 5 years ago
Posts: 923
Topic starter  

One thing I have noticed is that when I remove and reinsert the battery, the register contents are returned correctly. Only after I reset the registers to the actual time, this problem returns.


   
ReplyQuote
jscottbee
(@jscottbee)
Member
Joined: 5 years ago
Posts: 107
 

Try this before your requestFrom call in loop ( ):

  Wire.beginTransmission (ds3231_address);
// Set device to start read reg 0
Wire.write ((byte) 0x00);
Wire.endTransmission ( );
This post was modified 5 years ago by jscottbee

   
Pugwash reacted
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 5 years ago
Posts: 923
Topic starter  

Thanks, Scott

that worked a treat.

Doing something like that was whirling around in the back of my head, but I guess I couldn't see the wood for the trees.


   
ReplyQuote
jscottbee
(@jscottbee)
Member
Joined: 5 years ago
Posts: 107
 

Glad it worked. After you said it worked on startup and not after, I had an oh yeah moment. 


   
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 5 years ago
Posts: 923
Topic starter  

I should have seen it myself but worthwhile keeping that sort of trick in my bag of ....

Now for the fun stuff, filling the registers with values without a library, using bit shift and compound or, to fill the four high bits and the four low bits.

I just wonder what these guys were smoking when they came up with the idea to use hexadecimal for these registers.


   
ReplyQuote
jscottbee
(@jscottbee)
Member
Joined: 5 years ago
Posts: 107
 

These are macros I did for bcd translation from a pic controller project I did. They should work.

#define bcd2dec(bcd_in) (bcd_in >> 4) * 10 + (bcd_in & 0x0f)
#define dec2bcd(dec_in) ((dec_in / 10) << 4) + (dec_in % 10)

 


   
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 5 years ago
Posts: 923
Topic starter  

Thanks, I'll give them a try. I was going to just write a function() to do the conversion.


   
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 5 years ago
Posts: 923
Topic starter  

Oh! Just one more thing.

How do you implement these macros?

Never dealt with them before!


   
ReplyQuote
jscottbee
(@jscottbee)
Member
Joined: 5 years ago
Posts: 107
 

Just place them under you include section then just use them like you would a function.

i.e.

int dec_val = bcd2dec (0x25);

   
ReplyQuote
Page 1 / 2