1
\$\begingroup\$

I'm trying to implement read and write routines using Polling method for a PIC18LF24K40, write seems to work, but not read. I cannot figure out what i am doing wrong.

EDIT: Reading a byte stored in a register on a slave chip:

   void read_LDC_reg(U8 *dest_addr)
   {
      U8 temp=0;   

      if( ( check_for_bus_free_iic() == 1) )   
      send_start();

      PIR3bits.SSP1IF=0;
      I2C_wait();  

      send_address(U8_LDC_I2C_ADDRESS,READ_BIT);

      send_start();
      SSP1CON2bits.RCEN1=1;

      while(SSP1STATbits.BF==0);
      temp=read_from_slave();

      PIR3bits.SSPIF = 0;

      dest_addr =  &temp;

      send_stop();

}

send_start() looks like this:

void send_start()
{
    while(SSP1STATbits.RW);          // wait for write to complete
    SSP1CON2bits.SEN=1;              //set start enable bit

    if(PIR3bits.BCLIF==1)
        PIR3bits.BCLIF =0;  //Clear collision bit in PIR register

    while(SSP1CON2bits.SEN);         //waits to get cleared by hardware 
}  

I2C_wait looks like this:

void I2C_wait(void)
{
    while( (SSP1STAT & 0x04) | (SSP1CON2 & 0x1F) );

    PIR3bits.BCL1IF=0;

}

send_address() looks like this:

void send_address(unsigned char addr,unsigned char ReadWrite_bit)
{
    unsigned char temp=0;
    temp = ( (addr <<1u ) | (ReadWrite_bit & (unsigned char)0x01) ); 
    write_to_bus(temp);


}

write_to_bus() looks like this:

void write_to_bus(unsigned char data)
{

    send_start();
    I2C_wait();

    send_byte(data);
    I2C_wait(); 

    send_stop();        
}

read_from_slave() looks like this:

unsigned char read_from_slave(void)
{  
    unsigned char rcvd_byte=0;   

    rcvd_byte = SSP1BUF;     
    return rcvd_byte;    
}

I am getting unexpected values from the slave register, i do not know why i believe i have initialised correctly, i can see the SCL and SDA waveforms on Oscilloscope.

EDIT: Hardware is fine, I2C works perfectly when i use the I2C Driver code generated from MCC(MPLAB Code Generator), i want to reduce the overhead caused by MCC in my project, thats the reason im going for I2C using Polling option.

\$\endgroup\$
1
  • \$\begingroup\$ How do you know the writes are working if you can't read? Do you have access to registers on the other device? \$\endgroup\$
    – user4574
    Commented Jan 8, 2021 at 17:10

3 Answers 3

1
\$\begingroup\$

Your problem may have very little to do with I2C and much more to do with your use of the stack and pointers.

I see some issues with the following code.

   void read_LDC_reg(U8 *dest_addr)
   {
      U8 temp=0;
      ...
      temp=read_from_slave();
      ...
      dest_addr =  &temp;
      ...
  }

It looks like you are attempting to store a byte into temp and then return the address of temp from the function. There are two problems with this.

  • Temp is stored on the stack. So when you return it no longer exists. The compiler can re-use that stack space for other stuff, which would over-write your value.

  • You are not actually returning the address of temp properly. dest_addr is a pointer to an 8 bit integer. It lives on the stack. When you return from the function it no longer exists.

What you should be doing is...

  • Allocating temp somewhere outside of the read_LDC_reg function.
  • Passing the address of temp into the function.
  • Dereferencing the pointer address to store the value into temp.

The code is shown below.

void main(){
    U8 temp=0;
    read_LDC_reg(&temp);
    //At this point temp contains the byte read from I2C
}

void read_LDC_reg(U8 *temp){
      ...
      *temp=read_from_slave();
      ...
      send_stop();   
}
\$\endgroup\$
0
\$\begingroup\$

Load test values in a dummy MCU and try simulating with the Proteus design suite, but i agree with Buhra with checking the flag for successful reception from the slave, and if possible check necessary flags that indicate a free buffer and transmission-ready state.

\$\endgroup\$
-1
\$\begingroup\$
unsigned char read_from_slave(void)
{  
    unsigned char rcvd_byte=0;   
   <----------- Check Flag ------------>
    rcvd_byte = SSP1BUF;     
    return rcvd_byte;    
}

In this function you are not check any flag for successfull reception from slave,Check datasheet again

\$\endgroup\$
5
  • \$\begingroup\$ I have not enabled ACKEN bit so I'm not sure if i need to check if ACKDT bit is set on Receive. Probably i have to set ACKEN \$\endgroup\$
    – Abel Tom
    Commented Oct 24, 2017 at 6:03
  • \$\begingroup\$ what do you mean by I have not enabled ACKEN bit . Check previous reception is complete or not using flag,there is no matter of ACK. \$\endgroup\$
    – Bhura
    Commented Oct 24, 2017 at 6:41
  • \$\begingroup\$ I modified the read from register routine, i check if the buffer is now full, but i receive 0xFF for some reason, always. \$\endgroup\$
    – Abel Tom
    Commented Oct 24, 2017 at 6:50
  • \$\begingroup\$ ReCheck your connections, I2C Master SDA -> Slave SDA and SCK -> SCK with pull ups 1K'oms -> 4.7k'oms and what freq you are using for I2C communication can you provied whole code. \$\endgroup\$
    – Bhura
    Commented Oct 24, 2017 at 7:08
  • \$\begingroup\$ Pullups are around 2.2K, Clock frequency is set to 100KHz. Hardware is fine, I2C works perfectly when i use the I2C Driver code generated from MCC(MPLAB Code Generator), i want to reduce the overhead in my project, thats the reason im going for I2C using Polling option. \$\endgroup\$
    – Abel Tom
    Commented Oct 24, 2017 at 7:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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