2
\$\begingroup\$

I am using a Master PIC18F4620, Slave DS1307. All I am doing is setting the seconds to (0) at the beginning of the program, then I read it. I can't seem to read correctly, the value that is being returned from the SSPBUF register is the Slave+Writebit Address.

Everything is perfect on HW & Simulation, how is so? I used an I2C Debugger on Proteus and it is all working fine, I am indeed writing and reading CORRECT values, I then checked using my PicKit3 Debugger HW, and I found out something very interesting. The SSPBUF DOES transmit and receive, therefore its value changes, but the assignment statement from the SSPBUF to a variable FAILS.

#include "18F4620_Config.h"
#include "I2C.h"
#include "Generic_LCD.h"
#include "stdio.h"

#define _XTAL_FREQ 16e6
#define _RTC_WRITE 0xD0
#define _RTC_READ 0xD1 
#define SEC_ADDRESS   0x00 // Address to access Ds1307 SEC register
#define CONTROL 0x07       // Address to access Ds1307 CONTROL register

unsigned char seconds;
char myString[6] = {0};

void main(void)
{
    LCD_Init();
    LCD_Clear();
    LCD_Print("Read:");

    I2C_Master_Init();
    
    DS1307_Set_Seconds(35);
    while (1)
    {

        seconds = DS1307_Read_Seconds();

        LCD_Goto(6, 1);
        sprintf(myString,"%x ",seconds);
        LCD_Print(myString);

        __delay_ms(1000);
    }
}

As for the two used functions.

void DS1307_Set_Seconds(unsigned char secs)
{
    if (secs <= 60)
    {
        unsigned char higher = (secs / 10) << 4;
        unsigned char lower = (secs % 10);
        unsigned data = higher | lower;
        I2C_Start();
        I2C_Write(_RTC_WRITE);
        I2C_Write(0x00);
        I2C_Write(data);
        I2C_Stop();
    }
}

unsigned char DS1307_Read_Seconds(void)
{
    unsigned char sec;
    I2C_Start();
    I2C_Write(_RTC_WRITE);
    I2C_Write(SEC_ADDRESS);
    I2C_Restart();
    I2C_Write(_RTC_READ);
    sec = I2C_Read_Byte();
    I2C_NACK();
    I2C_Stop();
    return (sec);
}

The only thing that is being printed right now is (D1) on the LCD. I noticed another strange behavior, if instead of assigning SSPBUF value to a variable, I pass the SSPBUF as a parameter to the sprintf function, IT WORKS!. Like this

while (1)
        {
    
            seconds = DS1307_Read_Seconds();
    
            LCD_Goto(6, 1);
            sprintf(myString,"%x ",SSPBUF);
            LCD_Print(myString);

            __delay_ms(1000);
        }

Edit 1: Solution As mentioned in the comments, the solution is to read from the SSPBUF AFTER the I2C Communication has stopped entirely.

Therefore these are the code changes

void I2C_Read_Byte(void)
{
    //---[ Receive & Return A Byte ]---
    RCEN = 1; // Enable & Start Reception
    while (!SSPIF); // Wait Until Completion
    SSPIF = 0; // Clear The Interrupt Flag Bit
}

unsigned char DS1307_Read_Seconds(void)
{
    I2C_Start();
    I2C_Write(_RTC_WRITE);
    I2C_Write(SEC_ADDRESS);
    I2C_Restart();
    I2C_Write(_RTC_READ);
    I2C_Read_Byte();
    I2C_NACK();
    I2C_Stop();
    return (SSPBUF);
}

while (1)
    {

        seconds = DS1307_Read_Seconds();

        LCD_Goto(6, 1);
        sprintf(myString, "%x ", seconds);
        LCD_Print(myString);
        
        __delay_ms(1000);
    }
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Can you pinpoint the problem a bit more? Are you sure that the var “sec” gets filled with the i2c data, or is that the question? \$\endgroup\$ – Ananas_hoi Sep 19 '20 at 7:23
  • \$\begingroup\$ The problem is that the var "sec" gets filled with the I2C Slave Address? The question is why? \$\endgroup\$ – Abd-AlRahman Muhammad Sep 19 '20 at 13:03
1
\$\begingroup\$

I can't be sure, but I suspect the PIC is latching the address into SSPBUF, and once you read that it will then put the data there. So if you read it a second time, you'll get the data. Note that in your second example, you call DS1307_Read_Seconds(), which tries to read it, and then you read SSPBUF which would be a second read from that register.

\$\endgroup\$
1
  • \$\begingroup\$ That was worth a try, and it is indeed the correct answer. I probed into why this would be the right answer, and it seems that I only get the data from the SSPBUF, IF and ONLY IF, I read its value AFTER stopping the I2C Communication. so after the I2C_Stop() Thank you very much! \$\endgroup\$ – Abd-AlRahman Muhammad Sep 19 '20 at 13:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.