Bus Pirate I2C / I²C interface with a DS1307 RTC

2014-Nov-30

I picked up a Bus Pirate and cable to help with troubleshooting and future projects.     Conveniently, I am using an Adafruit Data Logging Shield for Arduino for a current project – which makes a perfect easy introduction to some of the communication with the Real Time Clock over I2C because the shield already has all of the supporting bits and pieces needed for the RTC.

# dmesg
[4946101.032737] usb 10-1: new full-speed USB device number 11 using uhci_hcd
[4946101.231682] usb 10-1: New USB device found, idVendor=0403, idProduct=6001
[4946101.231687] usb 10-1: New USB device strings: Mfr=1, Product=2, SerialNumber=X
[4946101.231691] usb 10-1: Product: FT232R USB UART
[4946101.231694] usb 10-1: Manufacturer: FTDI
[4946101.231696] usb 10-1: SerialNumber: AXXXXXXX
[4946101.238748] ftdi_sio 10-1:1.0: FTDI USB Serial Device converter detected
[4946101.238850] usb 10-1: Detected FT232RL
[4946101.238854] usb 10-1: Number of endpoints 2
[4946101.238857] usb 10-1: Endpoint 1 MaxPacketSize 64
[4946101.238861] usb 10-1: Endpoint 2 MaxPacketSize 64
[4946101.238864] usb 10-1: Setting MaxPacketSize 64
[4946101.240884] usb 10-1: FTDI USB Serial Device converter now attached to ttyUSB0

/dev/ttyUSB0 is the place to be

Bus Pirate Self Test
Jumper, Jumper, find a cable with USB Mini-B plug end.

# screen -L /dev/ttyUSB0 115200

?
General					Protocol interaction
---------------------------------------------------------------------------
?	This help			(0)	List current macros
=X/|X	Converts X/reverse X		(x)	Macro x
~	Selftest			[	Start
#	Reset				]	Stop
$	Jump to bootloader		{	Start with read
&/%	Delay 1 us/ms			}	Stop
a/A/@	AUXPIN (low/HI/READ)		"abc"	Send string
b	Set baudrate			123
c/C	AUX assignment (aux/CS)		0x123
d/D	Measure ADC (once/CONT.)	0b110	Send value
f	Measure frequency		r	Read
g/S	Generate PWM/Servo		/	CLK hi
h	Commandhistory			\	CLK lo
i	Versioninfo/statusinfo		^	CLK tick
l/L	Bitorder (msb/LSB)		-	DAT hi
m	Change mode			_	DAT lo
o	Set output type			.	DAT read
p/P	Pullup resistors (off/ON)	!	Bit read
s	Script engine			:	Repeat e.g. r:10
v	Show volts/states		.	Bits to read/write e.g. 0x55.2
w/W	PSU (off/ON)		/<x= >/	Usermacro x/assign x/list all
HiZ>~
Disconnect any devices
Connect (Vpu to +5V) and (ADC to +3.3V)
Space to continue
Ctrl
AUX OK
MODE LED OK
PULLUP H OK
PULLUP L OK
VREG OK
ADC and supply
5V(4.96) OK
VPU(4.96) OK
3.3V(3.35) OK
ADC(3.28) OK
Bus high
MOSI OK
CLK OK
MISO OK
CS OK
Bus Hi-Z 0
MOSI OK
CLK OK
MISO OK
CS OK
Bus Hi-Z 1
MOSI OK
CLK OK
MISO OK
CS OK
MODE and VREG LEDs should be on!
Any key to exit
Found 0 errors.
HiZ>

 

Wire up the Datalogging shield, will use the Bus Pirate to provide 5V and communicate directly with the RTC.   No Arduino involved yet.

# screen -L /dev/ttyUSB0 115200

HiZ>m
1. HiZ
2. 1-WIRE
3. UART
4. I2C
5. SPI
6. 2WIRE
7. 3WIRE
8. LCD
9. DIO
x. exit(without change)

(1)>4
Set speed:
 1. ~5KHz
 2. ~50KHz
 3. ~100KHz
 4. ~400KHz

(1)>3
Ready

The ‘mode’ light on the Bus Pirate lights up.
Bad things might happen if you have another power source and then turn on this power. (or if you have the pins wired to the wrong locations)

IMG_0846_markup

Four hookup points. GND label should be a bit more to the right.

Check that the RTC is there and responding, read out the current clock registers:

I2C>W
Power supplies ON
I2C>(0)
 0.Macro menu
 1.7bit address search
 2.I2C sniffer
I2C>(1)
Searching I2C address space. Found devices at:
0xD0(0x68 W) 0xD1(0x68 R)

I2C>[0xD0 0x00[0xD1 r:8]
I2C START BIT
WRITE: 0xD0 ACK 
WRITE: 0x00 ACK 
I2C START BIT
WRITE: 0xD1 ACK 
READ: 0x38  ACK 0x29  ACK 0x22  ACK 0x01  ACK 0x30  ACK 0x11  ACK 0x14  ACK 0x00 
NACK
I2C STOP BIT 

It took a bit to figure out the read command.    The I2C protocol calls for the master to say a device’s address, followed by a read/write bit.  The DS1307 7-bit I2C address is (binary) 1101000.  Appending the read/write bit gives two addresses (11010000, 11010001) – which are the two addresses returned by the ‘7bit address search’ macro – 0xD0 and 0xD1.

I WAS doing only a [0xD1 r:8] – and it was returning seemingly random values.  Turns out that the way to set the address pointer is to do a WRITE to the start address, but do another start “[” instead of specifying a value.   hence “[0xd0 0x00″ – write to address 0x00, but interrupt it with “[0xd1 r:8]”  – read 8 values from 0xd1.

 

From the datasheet [mouser.com]:
Datasheet-Time-RegistersReading the returned bytes backwards and referencing the datasheet – we can see that the RTC is set for (20)14-11-30 WeekDay#1 22:29:38, the clock is enabled (Bit7 at address 0x00h is 0), and none of the control bits are set (address 0x07h = 0x00h).   I’ve decided to call Sunday WeekDay#1, but the assignment is arbitrary.

The DAY register simply increments by one when the HOUR rolls over to the next day.

Note the year is only stored in one byte (two sets of 4 bits).  It is presumed that the actual year is <value> + 2000.

This BCD format [wikipedia.org] was new to me.  It’s nice being able to (mostly) read the time straight out of the hex values.
Try setting the time:

I2C>[0xd0 0x00 0x00 0x35 0x22 0x01 0x30 0x11 0x14 0x00]
I2C START BIT
WRITE: 0xD0 ACK 
WRITE: 0x00 ACK 
WRITE: 0x00 ACK 
WRITE: 0x35 ACK 
WRITE: 0x22 ACK 
WRITE: 0x01 ACK 
WRITE: 0x30 ACK 
WRITE: 0x11 ACK 
WRITE: 0x14 ACK 
WRITE: 0x00 ACK 
I2C STOP BIT

I2C>[0xd0 0x00[0xd1 r:8]
I2C START BIT
WRITE: 0xD0 ACK 
WRITE: 0x00 ACK 
I2C START BIT
WRITE: 0xD1 ACK 
READ: 0x07  ACK 0x35  ACK 0x22  ACK 0x01  ACK 0x30  ACK 0x11  ACK 0x14  ACK 0x00 
NACK
I2C STOP BIT

 

Nice! This Bus Pirate is going to be a handy tool to have around.

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>