Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

I2C(MSSP) Woes

Status
Not open for further replies.

UTMonkey

Member
Dear All,

Well actually not woes, I feel as if I have made a lot of progress but I am currently having difficulties with my 18F2550 -> I2C -> RTC project.

I have successfully been able to set the relevant START condition and transmitted the various bytes of data (I have the ACK's to show for it!;) ) and then successfully sent a STOP condition to the MSSP which appears to work as the SSPSTAT has the P bit set.

I now want to read the area of the RTC that I have written to, so according to the datasheet (DS1307) I reset the register pointer by:-

1. Sending a start condition
2. Perform a write with the address of the I2C slave (with the RW set at 0)
3. Perform a write of memory address (0x00).
4. Send a Stop.

The problem is that my program is stuck at step 1 waiting for SSPIF to be set, the start routine basically
1. Waits for no activity (no RW or other SSPSTAT activities )
2. Clear SPIF bit
3. Set SEN bit
4. Wait for SPIF bit to set (where it loops)

The strange thing is this "start" routine is the same routine that was run previously which worked fine.

I wondered if there were any bits set from the previous (succesful) write sequence that may disable a start condition from continuing.

The only thing I have noticed is that prior to the 2nd start sequence running is that SSPSTAT is 0b1001000 (basically SLEW = Disabled and P (stop bit) = enabled .

Perhaps the presence of the STOP bit stops a START sequence?

I could submit my code, but I would like to tidy it up first....

Hope this all makes sense.

Regards

Mark
 
Have you tried powering down your circuit. If you break during a transfer the bus can hang. To fix it you can manually check for data being low and clock the bus until the data line is high.

Mike.
 
Thanks for the tip, I shall have a look at how SDA and SCL are left (don't know why i didnt check it earlier).

I'll let you know how I get on.

Mark
 
Managed to get it working.

After the STOP sequence I noticed SCL was still "ticking", I had a look through the 18F2550 datasheet just to confirm that I did all the necessary stuff to correctly perform a "STOP" and it looked ok, apart from that I knew the STOP was OK because the "P" bit was set in SSPSTAT telling me so.

In the documentation it says that the only way the "P" bit can be cleared is by a RESET or by disabling the MSSP (clear SSPEN).

So thats it, after the first STOP I clear the SSPEN bit and then reset it. the SCL stops "ticking", and then my next START instruction works ok.

So yes it works, but do I really have to toggle SSPEN to do it??

Cheers for the advice so far!

Mark
 
You don't state what language you are codeing in. Here is my C file for a 4550 which is identical to the 2550.
Code:
#include <p18f4550.h>

void InitI2C();
void WaitSSP();
void SendStart();
void SendStop();
void SendRestart();
char SendByte(char);
char ReceiveByte();
void SendNack();
void SendAck();
char WriteByte(int,char);
char ReadByte(int);

//initialise the MSSP module
void InitI2C(){
    TRISBbits.TRISB0=1;
    TRISBbits.TRISB1=1;
    SSPCON1=0b00101000;
    SSPCON2=0;
    SSPSTAT=0b10000000;
    SSPADD=50;  //20000/(4*100);   //Fosc/(4*baud)
    PIR1bits.SSPIF=0;
    PIR2bits.BCLIF=0;
}

//Wait for the module to finish it's last action.
void WaitSSP(){
    while(PIR1bits.SSPIF==0);
    PIR1bits.SSPIF=0;
}

//send start bit
void SendStart(){
    SSPCON2bits.SEN=1;
    WaitSSP();
}

//Send stop bit.
void SendStop(){
    SSPCON2bits.PEN=1;
    WaitSSP();
}

//Send restart bit
void SendRestart(){
    SSPCON2bits.RSEN=1;
    WaitSSP();
}

//Send byte and return ack bit - 1=Ack  0=NAck
char SendByte(char Byte){
    SSPBUF=Byte;
    WaitSSP();
    return(!SSPCON2bits.ACKSTAT);
}

//Get a byte from the slave
char ReceiveByte(){
    SSPCON2bits.RCEN=1;
    WaitSSP();
    return(SSPBUF);
}

//Send a Not Acknowledge (NAck) to the slave
void SendNack(){
    SSPCON2bits.ACKDT=1;
    SSPCON2bits.ACKEN=1;
    WaitSSP();
}

//Send an Acknowledge (Ack) to the slave
void SendAck(){
    SSPCON2bits.ACKDT=0;
    SSPCON2bits.ACKEN=1;
    WaitSSP();
}

//Sends the start and device address.
//If the device is busy then it resends until accepted.
void SendID(char DeviceID){
    SendStart();
    if(SendByte(DeviceID)==1)
        return;
    do{
        SendRestart();
    }while(SendByte(DeviceID)==0);
}

//Write a byte to 24LC256
char WriteByte(int Address, char Byte){
    SendID(0b10100000);
    if(SendByte(Address>>8)==0)
        return(0);
    if(SendByte(Address&0xff)==0)
        return(0);
    if(SendByte(Byte)==0)
        return(0);
    SendStop();
    return(1);
}

//Read a byte from a 24LC256
char ReadByte(int Address){
char Byte;
    SendID(0b10100000);
    if(SendByte(Address>>8)==0)
        return(0);
    if(SendByte(Address&0xff)==0)
        return(0);
    SendRestart();
    if(SendByte(0b10100001)==0)
        return(0);
    Byte=ReceiveByte();
    SendNack();
    SendStop();
    return(Byte);
}

The last two routines show how to use the code.

Mike.
 
Hi Pommie,

I'm using ASM, I have to say C looks much more pleasing on the eye.

Looking at your code, functionally it is setting the same bits as my code.

in theory my code in C would be like:-
Code:
;First transmission
    SendID(0b10100000);
    if(SendByte(Address>>8)==0)
        return(0);
    if(SendByte(Address&0xff)==0)
        return(0);
    SendStop();


;Second transmission
    SendStart();	**** PIF would never set *****
    if(SendByte(0b10100001)==0)
        return(0);
    Byte=ReceiveByte();
    SendNack();
    SendStop()

perhaps I should "RESTART"?

I could always compile your C code.....

Thanks for your help.
 
For the 1307 you should only be sending 1 address byte.

This is my Swordfish code for reading the DS1307. (don't have it in C)
Code:
Public Function ReadDS1307(Address As Byte) As Byte
    SI2C.Start
    SI2C.WriteByte(%11010000)   //Write to DS1307
    SI2C.WriteByte(Address)           //address
    SI2C.Restart
    SI2C.WriteByte(%11010001)   //read from DS1307
    ReadDS1307=SI2C.ReadByte()
    SI2C.Stop
End Function
To read the seconds location, address would be zero. Hope that makes sense.

Mike.
BTW, Swordfish basic and the C18 compiler are both free.
 
Last edited:
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top