This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Accessing DS1307 RTC Addresses with nrf52 DK Through TWI and nrf_drv_twi_rx Function

I'm trying to read the values from the DS1307 RTC through TWI.  I've established a connection with the device but am not sure I'm using the nrf_drv_twi_rx() function correctly.    When the log is viewed it prints that there was a device successfully detected at the given address and that 7 bytes are received over TWI to the rx_data array which is an array with 7 uint8_t. 

From what I read about the nrf_drv_twi_rx() function I thought that passing it an initialized twi instance, device address, buffer to hold data, and amount of data to receive that it would automatically read from the correct device registry locations.  The problem is that the outputs I get are not related to the clock time and vary from 0 to 80. I'm not sure why these values are not the clock values.  From the DS1307 datasheet the memory addresses are listed as follows:

I'm not sure what the 00H-3FH address notion means as I would expect a binary or hex address for a memory location, so any help in understanding what these addresses mean would be helpful as well. The following paragraph from the datasheet describes how the data is to be accessed:

"The time and calendar information is obtained by reading the appropriate register bytes. The contents of the time and calendar registers are in the BCD format. Bit 7 of register 0 is the clock halt (CH) bit. When this bit is set to a 1, the oscillator is disabled. When cleared to a 0, the oscillator is enabled."  

I attached the full datasheet if you would like any extra information.

Another thing I noticed while debugging is that the values received to rx_data change every time the device is reset and occasionally hold the expected correct month/day/year etc. data but usually do not.  This makes me think there is an inconsistency with how the data is being accessed from the DS1307 addresses and that different information from the registry is being accessed each time the program runs for some reason, but I don't know why.

Here is my code that I've developed so far based on the twi_scanner_pca_10040 example in SES.

#include <stdio.h>
#include "boards.h"
#include "app_util_platform.h"
#include "app_error.h"
#include "nrf_drv_twi.h"



#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"


/* TWI instance ID. */

#define TWI_INSTANCE_ID 0

static const nrf_drv_twi_t m_twi = NRF_DRV_TWI_INSTANCE(TWI_INSTANCE_ID);

void twi_init(void) //configure twi connection
{
  ret_code_t err_code; 

  const nrf_drv_twi_config_t twi_config = {
    .scl = 22, //configure pin 22 to scl
    .sda = 23, //configure pin 23 to sda
    .frequency = NRF_DRV_TWI_FREQ_100K, //nrf freq 100k 250k or 400k
    .interrupt_priority = APP_IRQ_PRIORITY_HIGH, //if using a soft device this has to be changed accordingly
    .clear_bus_init = false 

    };

    err_code = nrf_drv_twi_init(&m_twi, &twi_config, NULL, NULL); //can pass this an interrupt handler
    APP_ERROR_CHECK(err_code);

    nrf_drv_twi_enable(&m_twi);

}


int main(void)
{

    ret_code_t err_code;
    uint8_t address = 0x68; //address of DS1307
    uint8_t rx_data[7]  = {0}; //buffer for rx twi info. array of 7 uint8_t to hold 7 bytes received over twi

    APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
    NRF_LOG_DEFAULT_BACKENDS_INIT();

    NRF_LOG_INFO("Application Started");

    NRF_LOG_FLUSH();

    twi_init();

    //read data from the slave register to show successful communication

    err_code = nrf_drv_twi_rx(&m_twi, address, &rx_data, sizeof(rx_data)); //receive data from the device registry and send to rx_data

    if(err_code == NRF_SUCCESS)
    {
      NRF_LOG_INFO("Successfully detected a device at address: 0x%x", address);

      for(int i = 0; i < 8; ++i) //display the data obtained from the rx
      {
        NRF_LOG_INFO("Data %d obtained from registry: %x", (i+1), rx_data[i]);
      }

    }
    
    else
    {

    NRF_LOG_INFO("No device detected at address 0x%x", address);

    }


    NRF_LOG_FLUSH();






    while (true)
    {
        /* Empty loop. */
    }
}

Datasheet for DS1307 RTC: /cfs-file/__key/communityserver-discussions-components-files/4/DS1307_5F00_Datasheet.pdf

Parents
  • Through some further troubleshooting I changed the rx_data array to hold 63 uint8_t and to get 63 bytes from the nrf_drv_twi_rx() function.  The correct date and time info (7 bytes holding info about sec, min, hour, month, etc) is all contiguous, but each time the program runs the group of correct information moves down one space in the rx_data array (ie: if sec, min, hour are in spaces 0, 1, and 2 the first build/run, the second build/run they are now in spaces 1,2,3 respectively). 

    The datasheet says that: "During a multi-byte access, when the address pointer reaches 3Fh, the end of RAM space, it wraps around to location 00h, the beginning of the clock space." 

    Based on this, it seems that the address pointer is not correctly resetting to the beginning of the clock space each run which is causing the offset.  

    I can't find information in the development library about how the nrf_drv_twi_rx() function knows what to use for the address pointer to read data from the slave device, or how this pointer is controlled.  Could someone explain how to alter the address pointer being used by the nrf_drv_twi_rx() function?  Or let me know if you think there is some other problem.  Thanks!

  • "The DS1307 then begins to transmit data starting with the register address pointed to by the register pointer. If the register pointer is not written to before the initiation of a read mode the first address that is read is the last one stored in the register pointer. The register pointer automatically increments after each byte are read."

    Expected operation is to transmit the required address to read - 0x00 in this case if wanting to read the time - before each read of the time. That requires a single byte write nrf_drv_twi_tx() before each nrf_drv_twi_rx() or better a combined write of 0x00 followed by a read in the same twi/i2c function; this is possible with the i2c driver but I don't use that so can't advise.

    Using wrap-around is not reliable; in any case 56 bytes RAM plus 8 bytes time = 64 bytes, so using an array of 63 bytes explains why the data moves 1 bytes each read of 63 bytes. 64 bytes would work but is not recommended ..

  • This worked perfectly, thank you so much!  Could you link to where you found the information about transmitting the read address?  I couldn't find where this info was but I'd like to read a bit more about how the TWI functions work. 

    Also here is my final code for anyone in the future that wants to see how I fixed this issue, sorry it's a bit messy.

    #include <stdio.h>
    #include "boards.h"
    #include "app_util_platform.h"
    #include "app_error.h"
    #include "nrf_drv_twi.h"
    
    
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    
    /* TWI instance ID. */
    
    #define TWI_INSTANCE_ID 0
    
    static const nrf_drv_twi_t m_twi = NRF_DRV_TWI_INSTANCE(TWI_INSTANCE_ID);
    
    void twi_init(void) //configure twi connection
    {
      ret_code_t err_code; 
    
      const nrf_drv_twi_config_t twi_config = {
        .scl = 22, //configure pin 22 to scl
        .sda = 23, //configure pin 23 to sda
        .frequency = NRF_DRV_TWI_FREQ_100K, //nrf freq 100k 250k or 400k
        .interrupt_priority = APP_IRQ_PRIORITY_HIGH, //if using a soft device this has to be changed accordingly
        .clear_bus_init = false 
    
        };
    
        err_code = nrf_drv_twi_init(&m_twi, &twi_config, NULL, NULL); //can pass this an interrupt handler
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_twi_enable(&m_twi);
    
    }
    
    
    int main(void)
    {
    
        ret_code_t err_code;
        uint8_t address = 0x68; //address of DS1307
        uint8_t rx_data[7]  = {0}; //buffer for rx twi info. array of 7 uint8_t to hold 7 bytes received over twi
        uint8_t startAddress = 0x00;
    
        APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    
        NRF_LOG_INFO("Application Started");
    
        NRF_LOG_FLUSH();
    
        twi_init();
    
    
        //Line 61 through 66 is what I changed from the original code
        
        err_code = nrf_drv_twi_tx(&m_twi, address, &startAddress, 1, true); //transmit to designate the start address
    
        if (NRF_SUCCESS == err_code) //if the starting address was successfully transmitted receive the 7 bytes for the clock time
        {
            err_code = nrf_drv_twi_rx(&m_twi, address, &rx_data, sizeof(rx_data));
        }
    
    
        if(err_code == NRF_SUCCESS) //if the rx was successful log the info
        {
          NRF_LOG_INFO("Successfully detected a device at address: 0x%x", address);
    
          for(int i = 0; i < 7; ++i) //display the data obtained from the rx
          {
            NRF_LOG_INFO("Data %d obtained from registry: %x", (i+1), rx_data[i]);
          }
    
        }
        
        else
        {
    
        NRF_LOG_INFO("No device detected at address 0x%x", address);
    
        }
    
    
        NRF_LOG_FLUSH();
    
    
    
    
    
    
        while (true)
        {
            /* Empty loop. */
        }
    }

  • Good news indeed! And thanks for posting the working code, this really helps other users in the future and makes engineers like me more likely to keep helping out :-)

    Here's the location:

    DS1307 64 x 8, Serial, I2C Real Time Clock (Hidden on page 13)
    Figure 6. Data Read (Write Pointer, Then Read) Slave Receive and Transmit

    DS1307.pdf

Reply Children
No Data
Related