CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

i2c between RaspberryPi and PIC

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
rovtech



Joined: 24 Sep 2006
Posts: 270

View user's profile Send private message AIM Address

i2c between RaspberryPi and PIC
PostPosted: Sat Apr 19, 2025 2:01 pm     Reply with quote

I have been using i2c between PICs for years. However I cannot get a RaspberryPi 4b to receive data from a PIC 16F1938.
Here is my PIC software:
Code:
/* Pre-processor directives */
 #include <16F1938.H>
 #fuses INTRC_IO, NOWDT, PUT, NOPROTECT
 #use delay (clock=16000000)
 #use i2c (SLAVE, FORCE_HW, SCL=PIN_C3, SDA=PIN_C4, address=0x14)
 #byte portc = getenv ("SFR:PORTC")
 #bit CKP=getenv("BIT:CKP")

// Global variables
   int status = 0xc1;
   int ct_req = 0x00;

// Interrupt on I2C
#INT_SSP
void ssp_interrupt ()          // have an interrupt
   {
    int incoming, state;                 // variables
    state = i2c_isr_state ();           // get state
     if (state < 0x80)                     // master is sending data
      {
       incoming = i2c_read ();       // throw away device address if state = 0
       if (state == 1)                       // first data received
       ct_req = incoming;
       }
     if (state >= 0x80)                 // master is requesting data from slave
      {
       i2c_write (status);
       CKP = TRUE;
      }
  }

// ****************************************************************************
/* The main function */
void main(void)
 {

// initialize I2C. These did not help:
//  i2c_init(100000);         // baud = 100,000
//  # define read_port  0xff      // all bus pins input
//  # define write_port 0x00      // all bus pins output
 
// Initialize port directions
  set_tris_c(0b00011000);               // i2c as inputs

// setup interrupts
    enable_interrupts (INT_SSP);        // enable I2C interrupt
    enable_interrupts (GLOBAL);

// *******************************************************************************
  while (1)            // loop continuously
  {
    delay_ms (250);                     // wait
    output_toggle(PIN_C5);      // flash LED if IRC not hung
  }            // end of while loop
 }                                // end of main function

Here is my Python software:
(sudo i2cdetect -y 1 returns address 0x0a)

Code:
from smbus import SMBus
import time
i2cbus = SMBus(1)       # create a new i2c bus
i2caddress = 0x0A       # address of Curve Tracer
status = 0xf0
status = i2cbus.read_byte(i2caddress)   # read the status
print(status)


Here is my schematic:
[img]https://drive.google.com/file/d/1u70PVtwvevMCdCCHkvuvc9dFPeL8fnu9/view?usp=sharing[/img]
Problems:
• The PIC address is 0x14 or 0001 0100 but the RaspberryPi reads it as 0x0A or 0000 1010. See explanation below.
• How does the RaspberryPi send the address for a Read or Write?
• How do I tell the RaspberryPi to be Master?
• The PIC uses 5v on the i2c bus whereas the RaspberryPi and other devices use a 3.3v bus. This problem is solved by using a level shifter as seen in the schematic.
• The PIC requires pullup resistors, the RaspberryPi does not. Corrected with the circuit.

The I2C addresses are 7 bits. When sending out the 7 bit address, we still always send 8 bits. The extra bit is used to inform the slave if the master is writing (0) to it or reading from it (1). The 7 bit address is placed in the upper 7 bits of the byte and the Read/Write (R/W) bit is in the LSB (Least Significant Bit).
The address of the PIC is declared as 0x14 which is 0x0a if the LSB is removed.

These are the signals on the i2c bus:
I don’t understand the first group. This does not always happen.
The second group sends 000101010 which is 0x14 with the direction 1 for a read then the 9th clock has SDA held low. So far so good but the PIC does not return the data or end the transaction.
I have an LED blinking every time through the while loop but it stops when the RPi sends the request.
The PIC is hanging the i2c bus. HELP

Waveforms
[img]https://drive.google.com/file/d/1vPvl56nYrz-NLs6C4nHMCqNe7dbPbABf/view?usp=sharing[/img]
Ttelmah



Joined: 11 Mar 2010
Posts: 19782

View user's profile Send private message

PostPosted: Sun Apr 20, 2025 4:26 am     Reply with quote

Since you are trying to do the read without sending a register address,
you need to _preload_ the byte to be sent, when the device address is
received with the read bit set.
The byte has to be already 'in' the PIC I2C data register when the read
is performed, otherwise it has nothing to send......
Normally when doing a standard read when a register address has been sent,
this is done by doing a read(0) to read the address, and then the write
in the same INT routine.. You need to do the same for the device address
since you are not sending a register address.
temtronic



Joined: 01 Jul 2010
Posts: 9458
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sun Apr 20, 2025 6:09 am     Reply with quote

curious..
The Pi has ...i2cbus = SMBus(1) .
soooo...

would the PIC have to have it's I2C port configured for SMBus as well ??

never worked with Pies,so don't know what their 'I2C port' is.
Ttelmah



Joined: 11 Mar 2010
Posts: 19782

View user's profile Send private message

PostPosted: Sun Apr 20, 2025 6:33 am     Reply with quote

Shouldn't matter. Smbus, and I2C are 99% compatible. Smbus allows
lower voltage thresholds, and has a timeout on a transaction, but the basic
protocols are pretty much the same.
However he should select SMBUS on the PIC. One key is that the Pi
I2C bus is pulled up to 3.3v inside the unit. He says he is using level
translation, so he should be getting 5v at the PIC, but better to be safe
on this.

His state==0x80, need to perform an i2c_read(0), then an I2Cwrite.
He will never get a state below this, since he is starting with the address
write with the read bit set.
rovtech



Joined: 24 Sep 2006
Posts: 270

View user's profile Send private message AIM Address

PostPosted: Sun Apr 20, 2025 9:00 am     Reply with quote

Thanks Ttelmah. I did not fully understand your reply about sending the register address. However it did jog my memory and I realized I was not using the same ISR that had worked in the past. I normally use i2c_read(2) but because I left it blank ( ) it defaulted to (1). I don't understand why it held the SCL line low because i2c_read(2) indicates do not release clock. Since SCL is controlled by the RaspberryPi Master the default i2c_read(1) does an ACK. I'm obviosly confused.

However muddling through I changed my ISR to
Code:
// Interrupt on I2C
#INT_SSP
void ssp_interrupt ()         // have an interrupt
   {
    int incoming, state;                // variables
    state = i2c_isr_state ();          // get state
     if (state <= 0x80)                 // master is sending data
      {
      if(state==0x80)      // throw away device address
         incoming = i2c_read (2);   // but do not release i2c bus
      else
       incoming = i2c_read();
        if (state == 1)                  // first data received
         ct_req = incoming;
       }
     if (state >= 0x80)                 // master is requesting data from slave
      {
      i2c_write (status);
      CKP = TRUE;
      }
  }

and now it works and I get the reply I expected and the bus behaves and closes.
https://drive.google.com/file/d/1oe7T8ukD8uBrNVG7DYbWFySW8CnviSRn/view?usp=sharing

Perhaps you can explain the stream parameter in i2c_read(stream,ack) and how I would use it.
There are a couple of other things in my code that bother me. Should the
Code:
if(state>=0x80)

be
Code:
if(state>0x80)
Ttelmah



Joined: 11 Mar 2010
Posts: 19782

View user's profile Send private message

PostPosted: Sun Apr 20, 2025 11:02 am     Reply with quote

Good.
Yes that is right.
Shows the importance of looking at what you used before.... Very Happy

The pont about streams is the same as for serial. On chips with multiple
I2C peripherals, or if you use one software and one hardware I2C, you can
have multiple #use I2C setups, with different stream names. You then use
this names in the read, write or state commands so that the compiler knows
which of the ports you want to talk to.
rovtech



Joined: 24 Sep 2006
Posts: 270

View user's profile Send private message AIM Address

PostPosted: Mon Apr 21, 2025 8:11 am     Reply with quote

I need to send an array[512] from slave PIC to master RaspberryPi.
Am I correct in assuming that the Pi has to make 512 requests in a loop?
Is there a way that the PIC can simply send 512 writes in a loop?
I am just learning Python and I see there is a read_i2c_block_data(addr,cmd) but I have no idea how to use it.
Looking at Ttelmah's last post in https://www.ccsinfo.com/forum/viewtopic.php?t=59131&highlight=i2c+array
he seems to be incrementing the array for each request from the master, so 16 transactions.
Code:
#INT_SSP
void ssp_interrupt(){

   int8 incoming, state;
   static int8 count=0;

   state = i2c_isr_state();
   
   if(state < 0x80)
   {     // Master is sending data
      incoming = i2c_read();
   }

   if(state == 0x80)
   {
       count=0;
       incoming = i2c_read(2);  //perform the read on state==0x80
       //note special read that does not release the CKP
   }

   if (state>=0x80)
   {   // Master is requesting data from slave
      i2c_write(sensorArray[count++]);
  }
}

But the master is not a Pi running Python so may not be as versatile.
I don't understand how count can be incremented if it is reset to 0 each interrupt.
I started a new thread:
https://www.ccsinfo.com/forum/viewtopic.php?p=245698#245698
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group