• AVR Freaks

AnsweredHot!DS1307 Read Write operation

Page: < 12 Showing page 2 of 2
Author
ric
Super Member
  • Total Posts : 26159
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: online
Re: DS1307 Read Write operation 2020/01/04 01:08:29 (permalink)
+1 (1)
I suspect the code in post#13 has been cribbed from an application note for an 8051 based MCU.
Presumably one that didn't have an SSP/SPI peripheral.
 
 

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#21
abhi143
Junior Member
  • Total Posts : 110
  • Reward points : 0
  • Joined: 2018/05/20 09:06:52
  • Location: 0
  • Status: offline
Re: DS1307 Read Write operation 2020/01/04 07:34:32 (permalink)
0
ric
abhi143, you have not yet revealed what PIC device you are using.
It will be easier to give correct low level code if you do.
 

ric
abhi143
I work with pic16f877a and I am trying to write bit bang code only just to understand i2c communication protocols 

Why not use the built in SSP peripheral to do it for you?
I warn you now, you are going to have RMW (read-modify-write) problems caused by the operation of the PIC16F877 PORT registers.


so where should I start if use SSP peripheral
#22
ric
Super Member
  • Total Posts : 26159
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: online
Re: DS1307 Read Write operation 2020/01/04 15:58:14 (permalink)
+1 (1)
abhi143
so where should I start if use SSP peripheral

The PIC16F877A datasheet
http://ww1.microchip.com/...Doc/39582C.pdf#page=80
 
and the I2C specification
https://en.wikipedia.org/wiki/I%C2%B2C
https://www.nxp.com/docs/en/user-guide/UM10204.pdf
 

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#23
ric
Super Member
  • Total Posts : 26159
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: online
Re: DS1307 Read Write operation 2020/01/04 18:42:14 (permalink) ☼ Best Answerby abhi143 2020/01/04 19:13:48
+2 (2)
Here's some code using the MSSP peripheral off the top of my head.
It's totally untested, so use at your own risk. You might learn something debugging it. :)
Note, I did NOT do a REPEATED START when setting the read register address. It's perfectly legal to do seperate write then read transactions instead.
I'm assuming a 20MHz oscillator.
// PIC16F877A Configuration Bit Settings

// 'C' source line config statements

// CONFIG
#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
#pragma config BOREN = ON       // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF        // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#include <xc.h>

#define _XTAL_FREQ 20000000
#define DS1307_ADDR 0xD0    //I2C slave address of DS1307 (8 bit format)
#define SECONDS_REG 0   //offset of the "seconds" register in the DS1307

void i2c_init(void)
{
    TRISCbits.TRISC3 = 1;   // SCL as input
    TRISCbits.TRISC4 = 1;   // SDA as input
    SSPCONbits.SSPM = 0b1000;  // Master mode using SSPADD as baud control
    SSPADD = 49;    //100kHz clock @ 20MHz Fosc
    SSPCONbits.SSPEN = 1;  //enable SSP
}

// Send an I2C START
// Return 0 if all ok, 1 if bus collision
__bit i2c_start(void)
{
    BCLIF = 0;  //Clear 'Bus collision" flag
    SEN = 1;    //initiate a START cycle
    while (SEN);    //wait until it has been sent
    return BCLIF;   //return value of BCLIF flag
}

// Send an I2C STOP
void i2c_stop(void)
{
    PEN = 1;    //initiate a STOP cycle
    while (PEN);    //wait until it has been sent
}

// Send an I2C REPEATED START
void i2c_restart(void)
{
    RSEN = 1;    //initiate a REPEATED START cycle
    while (RSEN);    //wait until it has been sent
}

//Send one byte. Return 0 if ACK received, or 1 if NAK received
__bit i2c_sendbyte(unsigned char dat)
{
    SSPBUF = dat;
    while (R_W);    //wait until byte sent and ACK/NAK received
    return ACKSTAT;
}

//Receive one byte. ackflag=0 to send ACK, or 1 to send NAK in reply
unsigned char i2c_recvbyte(unsigned char ackflag)
{
    RCEN = 1;   // initiate a RECEIVE cycle
    ACKDT = ackflag;    //specify if we should send ACK or NAK after receiving
    while (RCEN);   //wait until RECEIVE has completed
    ACKEN = 1;  //initiate an ACK cycle
    while (ACKEN);  //wait until it has completed
    return SSPBUF;
}

//Send an array of data to an I2C device.
//Return 0 if all OK, 1 if bus error, 2 if slave address NAK, 3 if slave register NAK, 4 if slave data NAK
unsigned char i2c_writeblock(unsigned char slave_address, unsigned char start_reg, unsigned char buflen, unsigned char * bufptr)
{
    if (i2c_start() )   //send a start, and check if it succeeded
        return 1;   //abort if bus collision
    //send the I2C slave address (force R/W bit low)
    if (i2c_sendbyte(slave_address & 0xFE))
    {
        i2c_stop(); //if address was NAKed, terminate the cycle
        return 2;   //and return error code
    }
    //send the device register index
    if (i2c_sendbyte(start_reg))
    {
        i2c_stop(); //if register was NAKed, terminate the cycle
        return 3;   //and return error code
    }
    //send the data. buflen might be zero!
    for (; buflen>0; --buflen)
    {
        if (i2c_sendbyte(*bufptr++))
        {
            i2c_stop(); //if register was NAKed, terminate the cycle
            return 4;   //and return error code
        }
        
    }
    i2c_stop();
    return 0;   //no error
}

//Receive an array of data from an I2C device.
//Return 0 if all OK, 1 if bus error, 2 if slave address NAK, 3 if slave register NAK
unsigned char i2c_readblock(unsigned char slave_address, unsigned char start_reg, unsigned char buflen, unsigned char * bufptr)
{
    //do a dummy zero length write cycle to set the register address
    unsigned char retval = i2c_writeblock(slave_address, start_reg,0,0);
    if (retval)
    {
        return retval;  //abort if there was an error
    }
    //now start the READ cycle
    if (i2c_start() )   //send a start, and check if it succeeded
        return 1;   //abort if bus collision
    //send the I2C slave address (force the R/W bit high)
    if (i2c_sendbyte(slave_address | 0x01))
    {
        i2c_stop(); //if address was NAKed, terminate the cycle
        return 2;   //and return error code
    }
    //receive the data.
    for (; buflen>0; --buflen)
    {
        unsigned char ackflag = (buflen == 1);   //1 if this is the last byte to receive => send NAK
        *bufptr++ = i2c_recvbyte(ackflag);
    }
    i2c_stop();
    return 0;   //no error
}

const unsigned char rtc_data[] =
{
    0x56,   //56 seconds
    0x34,   //34 minutes
    0x12,   //12 hours & 24 hour mode
    0x01,   //01 day=Sunday
    0x03,   //03 date
    0x12,   //12 month=dec
    0x01,   //01 year=2001
};

unsigned char rd_buf[7];

void main(void) {
    i2c_init();
    
    //write some dummy fixed data to the RTC chip
    if (i2c_writeblock(DS1307_ADDR, SECONDS_REG, sizeof(rtc_data), rtc_data) )
    {
        // here if failed
    } else
    {
        // here if succeeded
    }
    
    //read data back from the RTC chip
    if (i2c_readblock(DS1307_ADDR, SECONDS_REG, sizeof(rd_buf), rd_buf) )
    {
        // here if failed
    } else
    {
        // here if succeeded
    }
    while(1);   //endless loop to avoid exiting main() function)
}

post edited by ric - 2020/01/04 21:18:55

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#24
ric
Super Member
  • Total Posts : 26159
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: online
Re: DS1307 Read Write operation 2020/01/04 21:20:17 (permalink)
+1 (1)
I've corrected the code to change
        unsigned char ackflag = (buflen < 1);   //1 if this is the last byte to receive => send NAK

to
        unsigned char ackflag = (buflen == 1);   //1 if this is the last byte to receive => send NAK


I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#25
ric
Super Member
  • Total Posts : 26159
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: online
Re: DS1307 Read Write operation 2020/01/07 13:48:08 (permalink)
0
abhi143, did you try my code yet?
 

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#26
Page: < 12 Showing page 2 of 2
Jump to:
© 2020 APG vNext Commercial Version 4.5