chipKIT® Development Platform

Inspired by Arduino™

Help with I2C

Created Thu, 29 Aug 2013 01:44:51 +0000 by unexpectedly


unexpectedly

Thu, 29 Aug 2013 01:44:51 +0000

Hey all. Resident newbie here. I'm porting my current project from Arduino to chipKIT and it has been about 5 times more difficult than I was expecting. The only code so far that has ported is blink(). No one already associated with chipKIT is ever allowed to say or imply that working Arduino code will transfer over here without a fight...

I think I got a handle on SPI.

And now I'm working on the extreme most easy gizmo I have ever played with in Arduino, an I2C real time clock. My code worked in Arduino. Worked. On the 1st try. Now I'm 3 or 4 hours into banging my head against chipKIT again...

I'm using NKC Electronics arduino proto shield on my uC32. I like this one because it breaks out I2C from A4 and A5 in a grid in bottom corner. I used that as a chance to put 2.2k pull-up resistors on the C and D lines.

I tried it first with 0x68 and then I read about how uC32 doesn't use I2C addressing and the secret, undocumented, thing to do is /2 or >>1.

Here's the code:

#include <Wire.h>

char date[30];
#define I2C_DS1307_ADDRESS 0x68

byte bcdToDec(byte val){ return ( (val/16*10) + (val%16) ); }
byte decToBcd(byte val){ return ( (val/10*16) + (val%10) ); }
void getDate( char * buffer ){
	int address = I2C_DS1307_ADDRESS >> 1;
	// From the exmaple SFRRanger_reader.pde ...
	// transmit to device #112 (0x70)
	// the address specified in the datasheet is 224 (0xE0)
	// but i2c adressing uses the high 7 bits so it's 112
	Serial.println("Starting transmission...");
	Wire.beginTransmission( address ); // Reset the register pointer
	Wire.send(0x00);
	Wire.endTransmission();
	delay(70);	//	check datasheet for wait time?
	int second, minute, hour, weekDay, monthDay, month, year;
	Serial.println("sending request");
	Wire.requestFrom( address , 7);
	delay(70);	//	check datasheet for wait time?
	    Serial.println("Getting bytes...");
		second = bcdToDec(Wire.receive());
		minute = bcdToDec(Wire.receive());
		hour = bcdToDec(Wire.receive() & 0b111111); //24 hour time
		weekDay = bcdToDec(Wire.receive()); //0-6 -> sunday - Saturday
		monthDay = bcdToDec(Wire.receive());
		month = bcdToDec(Wire.receive());
		year = bcdToDec(Wire.receive());
	sprintf( buffer, "20%d-%02d-%02d %02d:%02d", year, month, monthDay, hour, minute );
}

void setup(){
	Serial.begin(9600);
	//  Real Time Clock
	Wire.begin();
	//	setDateTime();  // only used once, in theory... ;)

}

void loop() {
	getDate(date);
	Serial.println(date);
	delay(10000);
}

And the ouput is always:

Starting transmission...
sending request
Getting bytes...
200-00-00 00:00

When the RTC loses its date, it does not return all zeroes. Putting o'scope on and this is the only changes on pins 4 and 5 (confirmed 4 is top and 5 is bottom). It happens with the begin transmission. There is no other activity on the pins.

Pics of the setup... [attachment=2]rtc_scope.jpg[/attachment]

[attachment=1]rtc_i2c.jpg[/attachment]

[attachment=0]i2c_pull_ups.jpg[/attachment]

Any help would be greatly appreciated. I'm beaten down pretty hard by fighting with chipKIT with such "easy" code and want to get back to actual work. Sadly, there is more to get working after this, too. If you look at what this project is, I'm hoping something goes well for me soon... The SPI TFT and the I2C RTC were "slam dunks" in Arduino... :?

Thanks, Chris


unexpectedly

Thu, 29 Aug 2013 01:48:16 +0000

Oh, those resistors are 2.7k. Just took the shield out and measured to make sure...

Here's pic of that proto shield: [attachment=0]nkc_electronics_proto_shield.jpg[/attachment]


majenko

Thu, 29 Aug 2013 09:41:21 +0000

Hmmm... The last time I did any Wire work was to take an Adafruit library (for the MCP23017) and convert it for the chipKIT and to change it to be an LED display library.

All I had to do was change #include <Arduino.h> to #include <WProgram.h> and add my LED display code. All the wire stuff just worked as is. It already had the code in to switch between Wire.write() and Wire.send() depending on ARDUINO being >= 100.

I don't know what they're on about in those comments. I2C specifies that the first 7 bits of the first byte are the address, and the 8th bit is the read/write bit. To create a whole address bytre from an address ID you left-shift by one bit and OR in the read/write bit. And anyway, the Wire.h library deals with all that side of things for you:

Wire.beginTransmission(MCP23017_ADDRESS | i2caddr); // This sets "READ"
  Wire.send(MCP23017_GPIOA);
  Wire.endTransmission();

  Wire.requestFrom(MCP23017_ADDRESS | i2caddr, 2);  // This sets "WRITE"
  a = Wire.receive();
  ba = Wire.receive();

unexpectedly

Thu, 29 Aug 2013 19:54:19 +0000

Hi majenko, thanks for always trying to help me. :)

Yeah, I studied the I2C protocol last night. It would seem I am about the ten thousandth engineer to make a PIC talk to an 1307 RTC. I think I'm going to be stubborn and declare that I will not hand-roll I2C for PIC when it is supposed to be in the Libs and supposed to work.

My code was done in Arduino-land. No need to redo the wheel.

Let us consider your analogy that the Arduino is a saloon car with automatic transmission and chipKIT is rugged 4x4 with multiple gearboxes (and I imagine a PTO on rear axle).

Then why is the chipKIT also like the 1948 Packard Super 8? In that to use I2C, I need to know that by slowing down using the engine, I just drained the carburetor of all its fuel and that to begin running again, I need a gasoline container handy to pour some into the throat of the carburetor whilst someone else is starting the engine and pumping the throttle? Aren't we a little bit past this by 1985? I mean 2005? And yes, the code if I implement I2C manually for this particular cause is from 2005.

A .NET "arduino compatible" came in today. I forgot that I ordered it, actually! I wonder how long it will take for me to get the 1.8TFT and I2C RTC working?

Sooooo, yeah, someone please get back to me when the attached hello world works as it is supposed to (without excuses or hidden procedures required from a reference manual I cannot find). I think I'm going to stubbornly put my foot down and say, "no, sorry, I am above implementing yet another I2C". chipKIT isn't worth my time in this regard. For this I am sorry.

Just did it again on Arduino UNO; I took that proto shield with the RTC soldered up to it and put it on an Uno R3. Worked on the 1st try.

2013-08-29 12:43:42
2013-08-29 12:43:47
2013-08-29 12:43:52
2013-08-29 12:43:57
2013-08-29 12:44:02
2013-08-29 12:44:07
2013-08-29 12:44:12
2013-08-29 12:44:17
2013-08-29 12:44:22
2013-08-29 12:44:27
2013-08-29 12:44:32
2013-08-29 12:44:37

majenko

Thu, 29 Aug 2013 20:34:48 +0000

Alas I don't appear to have a DS1307 to hand. Everything else - DS1306 aplenty, DS1302, even an old MC146818, but no DS1307. Strange, I was sure I ordered some samples ages ago to experiment with. Ah well, not to worry - I'll have one here in a few days... good ol' Maxim.


unexpectedly

Thu, 29 Aug 2013 20:59:02 +0000

This is the specific gizmo I'm trying to talk to.

Thanks, Chris

PS - to help quantify my frustration, I have sworn off microsoft my whole life... I just install MSVC# and .NET. I feel dirty.


majenko

Thu, 29 Aug 2013 21:09:00 +0000

Good man. I knew you were sensible really :)


unexpectedly

Sun, 01 Sep 2013 23:05:32 +0000

As written above, that code does not compile with the pre-1.0-ArduinoIDE derived mpide.

[color=#BF80BF]Simply converting the write to send and reads to receive, the above code hangs when trying to receive because the mpide wire.h does a blocking call waiting on the reply. For whatever reason, this hardware never reacts in chipKIT-land, however runs without change in arduino world and also .NET's Netduino.[/color] ... update in reply below.

My first thought was to just grab the post-1.0-Arduino Wire library over, change it to Wire1 and drop it in my Libraries folder. That doesn't work either. There are overloads of print::write() that I'm a tad afraid to go mess with.

In file included from tft_rtc.cpp:55:0:
C:\Users\chris\Documents\mpide\libraries\Wire1/Wire1.h:60:20: error: conflicting return type specified for 'virtual size_t TwoWire::write(uint8_t)'
C:\Users\chris\Documents\mpide-0023-windows-20130715\hardware\pic32\cores\pic32/Print.h:50:15: error:   overriding 'virtual void Print::write(uint8_t)'
C:\Users\chris\Documents\mpide\libraries\Wire1/Wire1.h:61:20: error: conflicting return type specified for 'virtual size_t TwoWire::write(const uint8_t*, size_t)'
C:\Users\chris\Documents\mpide-0023-windows-20130715\hardware\pic32\cores\pic32/Print.h:52:15: error:   overriding 'virtual void Print::write(const uint8_t*, size_t)'

This fellow's post on Arduino.cc talks about it some...


unexpectedly

Sun, 01 Sep 2013 23:18:00 +0000

Whooooooo boy, that made mpide mad.

There's some real classism to sort out!! My programming training from EE-land was light on the classes and overloading, so this isn't really my area.

In file included from C:\Users\chris\Documents\mpide-0023-windows-20130715\hardware\pic32\cores\pic32/HardwareSerial.h:54:0,
                 from C:\Users\chris\Documents\mpide-0023-windows-20130715\hardware\pic32\cores\pic32/WProgram.h:20,
                 from C:\Users\chris\Documents\mpide-0023-windows-20130715\.\hardware\pic32\libraries\SPI/SPI.h:53,
                 from tft_rtc.cpp:7:
C:\Users\chris\Documents\mpide-0023-windows-20130715\hardware\pic32\cores\pic32/Print.h:54:20: error: 'virtual size_t Print::write(uint8_t)' cannot be overloaded
C:\Users\chris\Documents\mpide-0023-windows-20130715\hardware\pic32\cores\pic32/Print.h:50:15: error: with 'virtual void Print::write(uint8_t)'
C:\Users\chris\Documents\mpide-0023-windows-20130715\hardware\pic32\cores\pic32/Print.h:55:12: error: 'size_t Print::write(const char*)' cannot be overloaded
C:\Users\chris\Documents\mpide-0023-windows-20130715\hardware\pic32\cores\pic32/Print.h:51:15: error: with 'virtual void Print::write(const char*)'
C:\Users\chris\Documents\mpide-0023-windows-20130715\hardware\pic32\cores\pic32/Print.h:59:20: error: 'virtual size_t Print::write(const uint8_t*, size_t)' cannot be overloaded
C:\Users\chris\Documents\mpide-0023-windows-20130715\hardware\pic32\cores\pic32/Print.h:52:15: error: with 'virtual void Print::write(const uint8_t*, size_t)'
C:\Users\chris\Documents\mpide-0023-windows-20130715\hardware\pic32\cores\pic32/Print.h: In member function 'size_t Print::write(const char*)':
C:\Users\chris\Documents\mpide-0023-windows-20130715\hardware\pic32\cores\pic32/Print.h:57:53: error: void value not ignored as it ought to be
In file included from tft_rtc.cpp:55:0:
C:\Users\chris\Documents\mpide\libraries\Wire1/Wire1.h: At global scope:
C:\Users\chris\Documents\mpide\libraries\Wire1/Wire1.h:60:20: error: conflicting return type specified for 'virtual size_t TwoWire::write(uint8_t)'
C:\Users\chris\Documents\mpide-0023-windows-20130715\hardware\pic32\cores\pic32/Print.h:50:15: error:   overriding 'virtual void Print::write(uint8_t)'
C:\Users\chris\Documents\mpide\libraries\Wire1/Wire1.h:61:20: error: conflicting return type specified for 'virtual size_t TwoWire::write(const uint8_t*, size_t)'
C:\Users\chris\Documents\mpide-0023-windows-20130715\hardware\pic32\cores\pic32/Print.h:52:15: error:   overriding 'virtual void Print::write(const uint8_t*, size_t)'

majenko

Sun, 01 Sep 2013 23:27:16 +0000

Ah yes, that's expecting the version 1.0.x print class, not the 0023 version. There are some big changes - not least an extra overloaded write() function that allows writing of an array of bytes.


unexpectedly

Sun, 01 Sep 2013 23:43:30 +0000

Simply converting the write to send and reads to receive, the above code hangs when trying to receive because

I didn't run Wire.begin() in Setup() :oops:

I'm pretty sure I didn't make that goof the very first time through as I very :geek: the first several tries.


majenko

Sun, 01 Sep 2013 23:48:15 +0000

Hey... don't sweat it. I did the exact same thing today but with SPI. Had something working as a sketch - converted it to a library, kept hanging at the first SPI.transfer(). Couldn't work it out. Finally realized that I'd forgotten the SPI.begin()!!!


unexpectedly

Mon, 02 Sep 2013 00:08:40 +0000

So yeah, to confirm, my I2C problem is no more. Not sure what happened the very first time I tried exactly this. But to confirm, this code compiled and it told me the ti,e is right now, so this part works!

majenko, do you know of any good menu manager framework? I need something to work for my joystick and TFT. This library is close but I think I want simpler, like a linked list of call backs to handle position or something?

Oh, the code that worked:

//  Real Time Clock using I2C pins
#include &lt;Wire.h&gt;

#define I2C_DS1307_ADDRESS 0x68
byte bcdToDec(byte val){ return ( (val/16*10) + (val%16) ); }
byte decToBcd(byte val){ return ( (val/10*16) + (val%10) ); }

char date[30];
void getDate( char * buffer ){
	Wire.beginTransmission(I2C_DS1307_ADDRESS);
	Wire.send(0x00);
	Wire.endTransmission();
	Wire.requestFrom(I2C_DS1307_ADDRESS, 7);
	int second = bcdToDec(Wire.receive());
	int minute = bcdToDec(Wire.receive());
	int hour = bcdToDec(Wire.receive() &amp; 0b111111); //24 hour time
	int weekDay = bcdToDec(Wire.receive()); //0-6 -&gt; sunday - Saturday
	int monthDay = bcdToDec(Wire.receive());
	int month = bcdToDec(Wire.receive());
	int year = bcdToDec(Wire.receive());
	//print the date EG   3/1/11 23:59:59
	sprintf( buffer, "20%d-%02d-%02d %02d:%02d:%02d", year, month, monthDay, hour, minute, second );
}

void setup(){
	Wire.begin();
}

// use getDate(date); and date will have current time in from the sprintf above.

unexpectedly

Wed, 04 Sep 2013 00:49:06 +0000

majenko, I just found your RTCC library!

Hmmm, was thinking about writing a DS1307 library, then found your lib, now I'm kind of torn. For a lot of folks, using the Sparkfun RTC is preferred, so they leave their chipKIT board completely alone. If I weren't porting my code over ... and had a crystal, I'd probably just solder it on and use internal RTC. (does it save the time?)

So then I was going to write SFRTC class since it's really just for that product (and I'm not sure all DS1307 use I2C 0x68). I'm thinking if my programs knows what time it is, shouldn't it tell the processor?


majenko

Wed, 04 Sep 2013 08:51:06 +0000

The internal RTCC of the PIC32 is alright, but a bit pointless really. There is no facility for a battery backup, so as soon as the chip/board loses power it forgets the time. Great if you're never going to lose power, pointless for all other situations.

I do use the RTCC, but only when I get the actual time from another source (e.g., the internet), or when I just want a regular interrupt with greater accuracy than millis() gives me over a longer period than timers are effective for.

Other than that I use a DS13xx chip typically.


Jacob Christ

Tue, 25 Feb 2014 21:01:48 +0000

The internal RTCC of the PIC32 is alright, but a bit pointless really. There is no facility for a battery backup, so as soon as the chip/board loses power it forgets the time. Great if you're never going to lose power, pointless for all other situations.

I always thought that a good use would be to get time using NTP then use the rtc module to keep track locally.

Also, I believe some PIC32's have the ability to power the rtc without the processor running but the current draw is so great that you probably still want an external rtc chip.

Jacob


majenko

Tue, 25 Feb 2014 21:18:47 +0000

That kind of comes under the heading of "never losing power", in that you're not relying on the RTCC to maintain any functionality while the main power is off, like you would with a real RTC chip.

I mainly use it for longer period alarms, if I want an event to trigger over periods of minutes, or hours, for instance - better than trying to bend a timer into that kind of period, and you don't have to worry about absolute time, only relative.