Main Site Documentation

SoftwareI2CBus with DS3231 RTC


#1

I use the latest version of the SoftwareI2CBus which is part of the firmware of the CerbuinoBee firmware.
I have a problem reading out the DS3231. The read-function shows data that is out of sync with the internal registers (I see however valid DS3231 values).
In order to syncronise I would like to have access to the clock and data signal, but the driver prevents access to the pins…or…

            Cpu.Pin SCA = GHI.Pins.Generic.GetPin('B', 3); //pull up resistor attached
            Cpu.Pin SDA = GHI.Pins.Generic.GetPin('B', 4);  //pull up resistor attached
            SoftwareI2CBus Rtc1 = new SoftwareI2CBus(SCA, SDA);
            Rtc1.CreateI2CDevice(0x68); //address slave
            byte[] Wbuf =   {0x00,0x00,0x15,0x1,0x01,0x11,0x14}; //set initial values DS3231: seconds, minutes,hours, dow, dom, month, year after 2000
            byte[] Rbuf = new byte[30];
            int Wd , Rd = 0;     
            Rtc1.WriteRead(0x68, Wbuf, 0x00, Wbuf.Length, Rbuf, 0, 0x00, out Wd, out Rd);
            while (1 == 1)
            {
                Wd = Rd = 0;         
                // force DS3231 to an initial state (see quote from data sheet
                Rtc1.WriteRead(0x68, Wbuf, 0, 0, Rbuf, 0x0, 0x13, out Wd, out Rd);
                for ( int i=0; i< 0x13; i++ ) {
                    int BcdLow, BcdHigh = 0;
                    BcdHigh = (Rbuf[i]>>4) & 0x0f;
                    BcdLow = (Rbuf[i]) & 0x0f;
                    Debug.Print("Reg("+ i.ToString() + ") = "+ BcdHigh.ToString("D1") + BcdLow.ToString("D1"));
                    Thread.Sleep(1000);
                }
            }
 

QUOTE datasheet DS3231:
When the microcontroller
resets, the DS3231 I2C interface may be placed into a
known state by toggling SCL until SDA is observed to
be at a high level. At that point the microcontroller
should pull SDA low while SCL is high, generating a
START condition[quote]


#2

Unlikely but did you try it on hardware iic to make sure it works otherwise?


#3

No, I did not because I would like to use I2C on any pare of IO-pins…but I will give it a try

Did you “review” my code; are the functions used as it should?

Remark: the master address used twice, both in the creation of the I2C-object and read and write functions…why is that?


#4

@ freeck - I never used this feature but looking at the documentation, of you are using the write function on the bus directly then you do not need to create an i2c device. So just remove that or use the write functions in the device class, not the bus.


#5

@ Gus - The hardwareI2C works perfectly! The DS3231 works fine.
So there must be some difference in the implementation of SoftwareI2C…
What strikes me is that function WriteRead contains a var called WriteOffset declared as an int. I do’nt know how this variable is handled by the driver, but should’nt it be a byte declaration?


#6

@ freeck - WriteOffset just specifies how far into the passed buffer you want to start writing from.

It looks like you are trying to get the device into the proper initial state using the I2C driver. That may put the driver in an incorrect state. I would manually declare an OutputPort and InputPort on the SCL and SDA lines respectively to implement the needed behavior, then dispose of them and create the SoftwareI2C bus and use the functions on the I2CDevice returned by CreateI2CDevice.


#7

@ John - Like this? I still observe wrong behaviour; on my osscilloscope I miss the read-offset byte , that the master is supposed to send to the slave. The slave address is sent correctly.
Perhaps easier: is there anywhere a good example? I found many examples but none is a SoftwareI2C version NETMF 4.3…

            int Wd, Rd;
            TristatePort SCA = new TristatePort(GHI.Pins.Generic.GetPin('B', 3), false, false, Port.ResistorMode.PullUp);
            TristatePort SDA = new TristatePort(GHI.Pins.Generic.GetPin('B', 4), false, false, Port.ResistorMode.PullUp);
            SCA.Dispose();
            SDA.Dispose();
            SoftwareI2CBus Rtc1 = new SoftwareI2CBus(GHI.Pins.Generic.GetPin('B', 3), GHI.Pins.Generic.GetPin('B', 4));
            byte[] Rbuf = new byte[30];
            byte[] Wbuf = { 0x00, 0x00, 0x15, 0x01, 0x03, 0x11, 0x14 }; //set initial values DS3231: seconds, minutes,hours, dow, dom, month, year after 2000
            // use the next line only once in order to set the clock at an initial value
            // Rtc1.WriteRead(SlaveAddress, Wbuf, 0x00, Wbuf.Length, Rbuf, 0, 0x00, out Wd, out Rd); 
            Rtc1.CreateI2CDevice(SlaveAddress);
            while (1 == 1)
            {
                Wd = 0;  Rd = 0;
                Rtc1.WriteRead(SlaveAddress, Wbuf, 0x00, 0, Rbuf, 0x00, 0x08, out Wd, out Rd);
                    Thread.Sleep(100);
            }

#8

@ freeck - you miss the read-offset byte that the master is supposed to send to the slave? The read and write offset parameters in the WriteRead function only deal with the number and location of the bytes in the write and read buffer you pass to it.


#9

@ John - Yes of course : :wall:

I reduced the code: the CreateI2CDevice-function is’nt doing anything it seems… and the tristate of both SDA and SCL are not needed in my case (I have pull ups installed).
And everything works fine now. Thanks.

            byte DS3231Address = 0x68;
            int Wd, Rd;
            SoftwareI2CBus Rtc1 = new SoftwareI2CBus(GHI.Pins.Generic.GetPin('B', 3), GHI.Pins.Generic.GetPin('B', 4));
            byte[] Rbuf = new byte[0x13]; //total/max size DS3231 registers
            //set initial values DS3231: offset DS3231 registers, seconds, minutes,hours, dow, dom, month, year after 2000 (all coded to BCD values)
            byte[] Wbuf = { 0, 0x45, 0x59, 0x23, 0x01, 0x31, 0x12, 0x14 }; // 
            // use the next line only once in order to set the clock at an initial value
            Rtc1.WriteRead(DS3231Address , Wbuf, 0x00, Wbuf.Length, Rbuf, 0, 0x00, out Wd, out Rd); 
            while (1 == 1)
            {
                Wd = 0; Rd = 0; byte ReadOffset = 0; // read-offset (of DS-register) that the master is supposed to send to the slave
                Wbuf[0] = ReadOffset; int writeLength = 1; int readLength = 7;
                Rtc1.WriteRead(SlaveAddress, Wbuf, 0x00, writeLength, Rbuf, 0x00, readLength, out Wd, out Rd);
                Thread.Sleep(100);
            }