SD2405 on Beaglebone Black

Hi All
Have 2 of these on order and looking for Linux command line examples to set / get Date & Time only using i2c-tools. Only intend to get Date/Time once per day when I perform a reboot at midnight.

Extensive Googling does not bring up much on this device, but recall reading somewhere that
Date/Time has to be set in one transaction.??

Regards

Hi Jan,

The datasheet for the chip and DFRobot’s Arduino Library are probably good references to start with.

Regards,
Oliver
Support | Core Electronics

Hi All

Not everybody uses an Arduino or R.pi or wants to use their library.
The manufacturer of this device surely has a generic programming sequence
that is available to users.

Reading the doc’s I can only ascertain the following procedure.

  1.  Write 128h to address 10h to enable WRTC1
    
  2.  Write 132h to address 0Fh to enable WRTC2 & 3
    
  3.  Write Date time setting values.
    
  4.  Write 0h to address 0Fh to disable WRTC2 & 3
    
  5.  Write 0h to address 10h to disable WRTC1
    

There is no information as to the return values.
I get a confirmation (0) of opening of the device
and a Handle to use.
Reading the device shows incrementing numbers on the sec’s
and mins. So the link is working, but I simply can’t get
to set the current time on the device.
The enable commands return a (1)
The Time write command returns: Remote I/O Error
The disable commands return (1) as well.

Do I assume that 1 means Error (instead of -1)
If so, can I get the correct writing sequence from the manufacturer please.

Regards

Hi All

I could really use some help here.
It appears that either the docs are wrong or I am misinterpreting them.
Doc’s state that to enable the write mode:
(1) WRITE RTC ENABLE BIT (WRTC1 ,WRTC2,WRTC3):
Registers (00H ~ 1FH) RTC
write enable bits. When the three bits are set to “1”,
RTC is enable to be written.
Write enable: Setting the three bits must follow the sequencing: Set the WRTC1 bit to
“1” first,
then set the WRTC2 and WRTC3 to “1”.
Write disable: Setting the three bits must follow the sequencing: Set the WRTC2
and WRTC3 bits to “0” first, then set the WRTC1 to “0”.

To prove this I did:
==========dev Addr reg value
i2cset -f -y 0x02 0x32 0x10 0x10
Then immediately did a i2cdump:
i2cdump 0x02 0x32
This shows that setting the WRTC1 did NOT change location 0x10.
It doesn’t matter what value I write to that location, it simply does not change.

That I think is the reason why I can’t write to change the time.
EDIT: Just for fun I wrote &Hff to the WRTC1,2 registers and now I can change data, although something
still not right with the numbers, but will perservere if no-one here can clarify.

1 Like

Should the last 0x10 be 0x80?

Is the data being clocked MSB or LSB first from the board? Perhaps try 0x01 as the data instead of 0x80 to prove/disprove this.

1 Like

Hi All

The last 0x10 was simply to prove I could write to the SD2405.
It turned out that random bytes in the area of the control register were the cause. Overwriting them
with 0x00 allowed me to write to the 0x00 to 0x06 date time area.

Have made some progress, but still can’t write to set the date/time from within my program.

From within a compiled program (using Library iobb for i2c) I can read
without issues with the following partial FreeBasic code.
It should logically be readable even if you are not familiar with Freebasic.
'================================================

    .Result = iolib_init()                          'initialize the library iobb.
    configure_i2c_pins(19,20)
    .PortNbr = 2: .Addr = &H32                      'P9-19 & P9-20 the pins to use (no feedback)
    .Handle = i2c_open(.PortNbr,.Addr)              'Open the port and get a handle.
    .Result = i2c_read(.Handle, pBuffer,7)          'attempt a read of 7 bytes using Handle
        '----Then break up the pBuffer----
        If .Result > -1 Then                            'prints error if -1
                For Xq = 0 to 6                         'for 6 registers
                    xChr = *(pBuffer + Xq)              'get uByte from buffer.
                    xChr = xChr And &B01111111          'Clear Bit 7 for Year,and all others don't care.
                    Upper = xChr shr 4                  'Create Upper uByte from upper 4 bits
                    Lower = xChr And &B00001111         'Create Lower uByte by clearing upper 4 bits.
                    Select case Xq
                        Case 0                          'upper 4 bit Values are 0,40,20,10
                            .Secs  = (Upper * 10) + Lower
                        Case 1
                            .Mins  = (Upper * 10) + Lower
                        Case 2
                            .Hours = (Upper * 10) + Lower
                        Case 3
                            .wDay  = Lower
                        Case 4
                            .Days  = (Upper * 10) + Lower
                        Case 5
                            .Mnths = (Upper * 10) + Lower
                        Case 6
                            .Years = (Upper * 10) + Lower
                    End Select
                Next
            Else
        EndIf
        deallocate(pBuffer)                             'finished with Buffer
        '----------------------------
        .Result = i2c_close(.Handle)
        iolib_free()                                    'finished with Library
        '================================================

The script that sets the WRTC bits and calls program to write.
`
        '----writei2c.sh----
        #!/bin/sh
        sudo i2cset -y 2 0x32 0x10 0x80
        sleep 2                                         'sleeps are needed, setting one after the other
        sudo i2cset -y 2 0x32 0x0f 0x84                 'fails frequently
        sleep 2

        sudo ./i2csettime                               'compiled program shown below.

        sleep 2
        #sudo i2cset -y 2 0x32 0x0f 0x00
        #sleep 2
        #sudo i2cset -y 2 0x32 0x10 0x00
        #sleep 2
        sudo i2cdump -y 2 0x32
        '-------------------

        '================================================
        '-------Compiled program----------Creates a -1 Write Error reported by iobb library.
        .Result = iolib_init()                          'initialize the library iobb.
        configure_i2c_pins(19,20)                       'P9-19 & P9-20 the pins to use (no feedback)
        .PortNbr = 2: .Addr = &H32
        .Handle = i2c_open(.PortNbr,.Addr)              'Open the port and get a handle.
       '--------Test Date time values---
        If .Result > -1 Then                            'prints error if -1
            *(pBuffer + 0) = toBCD(.Secs)
            *(pBuffer + 1) = toBCD(.Mins)
            .Hours = toBCD(.Uur)                        'convert Hours that are less then 100 to BCD
            .Uur   = .Hours OR &B10000000               'then set 12/24 bit
            *(pBuffer + 2) = .Uur                       'put into pBuffer
            *(pBuffer + 3) = toBCD(.wDay)
            *(pBuffer + 4) = toBCD(.Days)
            *(pBuffer + 5) = toBCD(.Mnths)
            *(pBuffer + 6) = toBCD(.Years)
            Sleep 20                                    'wait 20 mSec after Port opening.
            .Result = i2c_write(.Handle, pBuffer, .Length)
        EndIf
        '---------------------------------
        '=================================================

The doc's state that all 7 bytes must be written at once, but that is not correct.
I can set the date/time quite nicely by doing the following from console in Linux.

        sudo i2cset -y 2 0x32 0x10 0x80                 'set the WRTC bits
        sudo i2cset -y 2 0x32 0x0f 0x84

        sudo i2cset -y 2 0x32 0x00 0x10                 'set seconds
        sudo i2cset -y 2 0x32 0x00 0x14                 'set minutes
        sudo i2cset -y 2 0x32 0x00 0x91                 'set Hours (11am)
        sudo i2cset -y 2 0x32 0x00 0x01                 'set Week day (they want Sunday as Day 1)
        sudo i2cset -y 2 0x32 0x00 0x05                 'set days
        sudo i2cset -y 2 0x32 0x00 0x07                 'set Month
        sudo i2cset -y 2 0x32 0x00 0x20                 'set Year

        sudo i2cset -y 2 0x32 0x0f 0x00                 'set the WRTC bits
        sudo i2cset -y 2 0x32 0x10 0x00
    sudo i2cdump 2 0x32                             'show values.

0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
'00: 15 14 91 01 05 07 20 00 00 00 00 00 00 00 00 00 ??? …?
'10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ?..0???7??? …

Regards

Hey Jan, interesting project. I’ve got some stuff to do today but I’m going to have a dig and see if I can help.

Hi All
Thanks Oliver.
An example of writing date/time is of course desirable.
Particularly if they use delays between commands, or set other bits in the control register prior
to sending date/time.
Note that the code of the previous post was only a snippet.
I checked a lot of things to prove I was not sending dud data and the correct number of bytes.

As I have set a unit correctly manually, I will install it on site on Tuesday and prove reliability
and accuracy. Running it in my office has proved reliable so far.

Regards

Hi All

Below some results of trying to write 7 bytes at once as required by docs.
Before Program dump.
Where did all these values after 0x6 come from ?

    0  1  2  3   4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: 21 42 89 04 22 14 35 0a 05 10 07 20 00 00 00 84    !B??"?5???? ...?
10: 80 00 00 39 90 03 08 07 20 20 00 00 00 00 00 00    ?..9????  ......

Start of Program to write Date/Time
-----i2cSetTime-----
Time wDay: Date
2:40:10 3: 8-7-20
BCD
2:64:10 3 8-7-32

Init Result = 0
Open Handle = 4

Buffer before write;
00000010      Secs ;2
01000000      Mins ;40
10010000      Hrs  ;144
00000011      dWeek ;3
00001000      Day  ;8
00000111      Mnth ;7
00100000      Year ;20

Result of Time Write = 7
Buffer after write;

00000010      Secs ;2
01000000      Mins ;40
10010000      Hrs  ;144
00000011      Week ;3
00001000      Day  ;8
00000111      Mnth ;7
00100000      Year ;20
Close Result =  0

End of Program dump.

00: 28 42 00 00 03 08 07 20 05 10 07 20 00 00 00 84    (B..??? ??? ...?
10: 80 00 00 39 90 03 08 07 20 20 00 00 00 00 00 00    ?..9????  ......

Result of Time write shows 7, which I assume is 7 bytes written.
BUT, look what happened in the dump after write.
28 secs should be no more then 4 or 5, so it incremented from before (21)
42 Mins has not changed, should be 40.
00 Hrs should be 144 (1001 0000) 10 o’clock.
After that it looks like the fields have shifted to the right by 1 byte.

So now I clear the bytes from 0x11 to 0x19 manually and from 0x07 to 0x0e,
then run the program again.
`
Dump before write

00: 12 05 01 00 03 08 07 00 00 00 00 00 00 00 00 84    ???.???........?
10: 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ?...............

Program prints same data here as shown above.

Result of Time Write = -1
Buffer after write;

01010011      Secs ;53
00000010      Mins ;2
10010001      Hrs  ;145
00000011      Week ;3
00001000      Day  ;8
00000111      Mnth ;7
00100000      Year ;20
Close Result =  0

End of Program

Buffer after write (even though an error -1 was reported.

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: 19 05 01 00 03 08 07 00 00 00 00 00 00 00 00 84    ???.???........?
10: 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ?...............

I don’t know if the fault lies with the iobb library command

.Result = i2c_write(.Handle, pBuffer, .Length)

or with the SD2405

Regards

Hi All

I have done some tests and posted cro pictures here:
https://www.element14.com/community/community/designcenter/single-board-computers/next-genbeaglebone/blog/2019/08/15/beaglebone-black-bbb-io-gpio-spi-and-i2c-library-for-c-2019-edition

Please scroll to bottom of page

Regards

1 Like

Hi All

Conclusion:
Just so that any others can save themselves some head aches, the listing below (in FreeBasic)
works very well.
So I set the correct date & time from within my main program and then call this to set the correct
values in the SD2405. The only other change I will make is to reduce the pullup resistors
so that the rise time of the SCL is faster.Either by adding a 4.7k in parrlel
or removing the 10k and replacing it with 2.7k.

    '-------Start of Program----------------
    With i2c
        #Define toBCD(v)    ( CUByte( (v) \ 10 Shl 4 + (v) Mod 10 ) )
        Dim PBuffer as uByte Ptr
        '-----------------------------------
        .Years = Val(Right(Date,4)) - 2000
        .Mnths = Val(Left(Date,2))
        .Days  = Val(Mid(Date,4,2))
        .wDay  = DayOfWeek                              'call Function that will querie system for value.
        .Uur   = Val(Left(Time,2))                      'Hours (Uur) will be manipulated below before write.
        .Mins  = Val(Mid(Time,4,2))
        .Secs  = Val(Right(Time,2))
        '------------------------------------
        pBuffer = callocate(8,Sizeof(uByte))            '1 Byte for Start addr & 7 bytes for SD2405 time data.
        '-----Initialize------
        configure_i2c_pins(19,20)                       'P9-19 & P9-20 (on BeagleBone Black)
        .Result  = iolib_init()                         'initialize the library iobb.
            If .Result < 0 Then
                Print "Must be run as sudo ./Seti2cTime"
                .Errer = 1
                Exit Sub
            EndIf
        .PortNbr = 2: .Addr = &H32                      'PortNbr specified by Linux, Addr by (i2cdetect -y -r 2)
        .Handle  = i2c_open(.PortNbr,.Addr)             'Open the port and get a handle.
        '''''''Now fill the buffer--------
        *(pBuffer) = &H10                               'WRTC1 address must be set first.
        *(pBuffer + 1) = &H80                           'set bit 7, must be set first, and reset last
        .Result = i2c_write(.Handle,pBuffer,2)          'write it
            If .Result < 0 Then
                Print "Write to WRTC1 failed"
                .Errer = 2
                Goto Err_Exit
            EndIf
        *(pBuffer) = &H0f                               'WRTC2 & WRTC3 address must be second.
        *(pBuffer + 1) = &H84                           'write both
        .Result = i2c_write(.Handle,pBuffer,2)          'on Error .Result = -1
            If .Result < 0 Then
                Print "Write to WRTC2 & 3 failed"
                .Errer = 3
                Goto Err_Exit
            EndIf
       '----Fill Buffer with Date time values---
        If .Result > -1 Then                            'If no Error
            *(pBuffer)     = &H00                       'Starting Address
            *(pBuffer + 1) = toBCD(.Secs)
            *(pBuffer + 2) = toBCD(.Mins)
            .Hours = toBCD(.Uur)                        'convert Uur to BCD Hours
            .Uur   = .Hours OR &B10000000               'then set 12/24 bit.
            *(pBuffer + 3) = .Uur                       'put into pBuffer
            *(pBuffer + 4) = toBCD(.wDay)               'day of week number (Monday = 1)
            *(pBuffer + 5) = toBCD(.Days)
            *(pBuffer + 6) = toBCD(.Mnths)
            *(pBuffer + 7) = toBCD(.Years)              'last 2 digits only (ie:20 for 2020)
            '--------------------------------
            .Length= 8:.Addr = &H32                     'Length of 8 = 1 for Start Address and 7 for Data
            .Result = i2c_write(.Handle, pBuffer,.Length)
                If .Result < 0 Then
                    Print "Date/Time data write failed"
                    .Errer = 4
                    Goto Err_Exit
                EndIf
            .Length= 2:.Addr = &H32
            *(pBuffer) = &H0f                           'First cancel WRTC2 & 3
            *(pBuffer + 1) = &H00                       'by writing 0 into them.
            .Result = i2c_write(.Handle, pBuffer,.Length)
                If .Result < 0 Then
                    Print "WRTC1 reset Failed, it is left ON"
                    .Errer = 5
                    Goto Err_Exit
                EndIf
            .Length= 2:.Addr = &H32                     'Next cancel WRTC1
            *(pBuffer) = &H10
            *(pBuffer + 1) = &H00
            .Result = i2c_write(.Handle, pBuffer,.Length)
                If .Result < 0 Then
                    Print "WRTC2 & 3 reset Failed, it is left ON"
                    .Errer = 6
                EndIf
        EndIf
Err_Exit: '--------------------------------
        .Result = i2c_close(.Handle)
        Print "Close Result = ";.Result
        iolib_free()                                    'finished with Library
    End With
End Sub```

Now to get the time from the SD2405
```Sub i2cGetTime
    With i2c
        pBuffer = callocate(7,Sizeof(uByte))            '7 bytes for SD2405 time data.
        '-----Initialize------
        .Result = iolib_init()                          'initialize the library iobb.
        If .Result < 0 Then ErrNbr = 1:Goto Err_Exit
        configure_i2c_pins(19,20)
        .PortNbr = 2: .Addr = &H32                      'P9-19 & P9-20 the pins to use (no feedback)
        .Handle = i2c_open(.PortNbr,.Addr)              'Open the port and get a handle.
        If .Handle = 0 Then ErrNbr = 2:Goto Err_Exit
        '--------------------------------
        .Result = i2c_read(.Handle, pBuffer,7)          'attempt a read of 7 bytes using Handle
        If .Result > -1 Then                            'prints error if -1
                For Xq = 0 to 6                         'for 6 registers
                    xChr = *(pBuffer + Xq)              'fill buffer with register content
                    xChr = xChr And &B01111111          'Clear Bit 7 for Year,but others don't use it.
                    Upper = xChr shr 4                  'Create Upper uByte from upper 4 bits
                    Lower = xChr And &B00001111         'Create Lower uByte by clearing upper 4 bits.
                    Select case Xq
                        Case 0                          'upper 4 bit Values are 0,40,20,10
                            .Secs  = (Upper * 10) + Lower
                        Case 1
                            .Mins  = (Upper * 10) + Lower
                        Case 2
                            .Hours = (Upper * 10) + Lower
                        Case 3
                            .wDay  = Lower
                        Case 4
                            .Days  = (Upper * 10) + Lower
                        Case 5
                            .Mnths = (Upper * 10) + Lower
                        Case 6
                            .Years = (Upper * 10) + Lower
                    End Select
                Next
            Else
                ErrNbr = 3:Goto Err_Exit
        EndIf
        deallocate(pBuffer)                        'finished with Buffer
        '----------------------------
        .Result = i2c_close(.Handle)
        iolib_free()                                'finished with Library
    End With
    Exit Sub
Err_Exit:
    Print "Error ;";ErrNbr
End Sub

I know this has been basically a one sided conversation, but at least the subject is visible on Google.

Regards

2 Likes

Hi Jan,

Thanks so much for posting the story! Sorry we weren’t able to be a lot of help on this, but you may now be one of the most knowledgeable people on the planet on the SD2405 chips!

We really appreciate you taking the time to make it available to the world!

Regards,
Oliver
Support | Core Electronics