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 support@ccsinfo.com

PIC16F18346 to PIC16F18346 I2C Communication
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
L.T.



Joined: 24 Jul 2020
Posts: 62

View user's profile Send private message

PIC16F18346 to PIC16F18346 I2C Communication
PostPosted: Fri Jul 02, 2021 5:39 am     Reply with quote

Hello,

I am working on a code. I need to communicate 2 PIC16F18346 microcontrollers with I2C. I coded the C3 pin to be SCL and the C4 pin to be SDA and set up my circuit. It is connected to a 3.3V supply voltage with both SCL and SDA pull-up resistors.

I haven't written any complicated code yet. I wanted only the master to send a command, and the slave to read the command sent and flash the led connected to the A2 pin after each value it reads.

Code:

//Master
#include <16F18346.H>
#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT

/* Delay for 4 mhz crystal */
#use delay (clock=4000000)
/* Setup I2C */
#use I2C(MASTER, sda=PIN_C4, scl=PIN_C3, SLOW)

main()
{
   int8 i2c_command = 66;

   while (true)
   {
      /* Master */
      i2c_start();      // Start condition
      i2c_write(0xa0);   // Device address
      i2c_write(i2c_command);   // Write Command
      i2c_stop();      // Stop condition

   }
}


Code:

//Slave
#include <16F18346.H>
#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT

/* Delay for 4 mhz crystal */
#use delay (clock=4000000)

/* Setup I2C */

#pin_select SCL1OUT = PIN_C3
#pin_select SCL1IN  = PIN_C3

#pin_select SDA1OUT = PIN_C4
#pin_select SDA1IN  = PIN_C4

#use i2c(SLAVE, I2C1, address=0xa0, SLOW, FORCE_HW)

#INT_SSP
void ssp_interupt ()
{
   byte incoming;
   incoming = i2c_read();
   output_high(pin_A2);
   incoming = i2c_read();
   output_low(pin_A2);
}


main()
{
      delay_ms(1000);
     
      enable_interrupts(GLOBAL);
      enable_interrupts(INT_SSP);
      while (true)
   {

   }
}


When I wanted to examine the signals with the oscilloscope, I could not observe any signal. Even the clock signal!

I have debugged. The master code comes to the "i2c_write(0xa0)" line after the "i2c_start()" command. However, when I say skip to the next line, it goes back to the line "#use I2C(MASTER, sda=PIN_C4, scl=PIN_C3, SLOW)" and gets stuck here.

I really need your help. Thank you.
dyeatman



Joined: 06 Sep 2003
Posts: 1910
Location: Norman, OK

View user's profile Send private message

PostPosted: Fri Jul 02, 2021 6:47 am     Reply with quote

I don't see PPS lines in the master code but I do in the slave.
Since they are the same chip both need PPS lines
_________________
Google and Forum Search are some of your best tools!!!!
L.T.



Joined: 24 Jul 2020
Posts: 62

View user's profile Send private message

PostPosted: Fri Jul 02, 2021 7:06 am     Reply with quote

dyeatman wrote:
I don't see PPS lines in the master code but I do in the slave.
Since they are the same chip both need PPS lines


Hello,

I updated the code as below. The problem is still the same.

Code:

#include <16F18346.H>
#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT

/* Delay for 4 mhz crystal */
#use delay (clock=4000000)

/* Setup I2C */
#pin_select SCL1OUT = PIN_C3
#pin_select SCL1IN  = PIN_C3

#pin_select SDA1OUT = PIN_C4
#pin_select SDA1IN  = PIN_C4

#use I2C(MASTER, I2C1, SLOW)

main()
{
   int8 i2c_command = 66;

   while (true)
   {
      /* Master */
      i2c_start();      // Start condition
      i2c_write(0xa0);   // Device address
      i2c_write(i2c_command);   // Write Command
      i2c_stop();      // Stop condition

   }
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19195

View user's profile Send private message

PostPosted: Fri Jul 02, 2021 7:07 am     Reply with quote

First thing. This is a PPS chip. Currently the compiler will be setting up
software I2C for the master. Software will work for a master, but not for
a slave. Ideally use pin_select on both chips to use the hardware port.
Look at the sticky at the top of the forum about this. So use I2C1, rather
than the pin numbers after setting up the PPS.
You are doing this on the slave. Do the same on the master,

Then a comment. What resistor values are you using?. On 3.3v,
something like 3.3K should be used. A larger value than is normally
used on 5v.

Then this chip is an ANSEL supporting chip. This means it defaults to
having all pins setup as analog. Add:
set_analog_pins();
This sets all the chip pins to digital operation.

Have your chips got 4MHz crystals between pins A4, and A5, with suitable
load capacitors?. Your oscillator setup is saying you do. Unless you have
change your clock setup to use the internal oscillator.

Get rid of 'slow' in the slave. The slave device does not have a 'speed',
only the master does. Setting this can result in incorrect setups on some
chips.

Then your approach to the interrupt is wrong. The interrupt says that
_one_ byte is available to be read. Not two. You need to use I2c_isr_state
in the interrupt to detect that the first byte is the address and then the
second reception is the data. Only when this arrives, do your flash.
Currently your flash would be too fast too see. Even at 100KHz.
You need to allow a pause in the master. Currently the stuff would send
'non stop', with no time for the slave to do anything.

First start by verifying your master and slave are both running. Simple
flash an LED on each, and check it flashes at the specified speed. Only
once this is working, move on to I2C.
L.T.



Joined: 24 Jul 2020
Posts: 62

View user's profile Send private message

PostPosted: Fri Jul 02, 2021 7:40 am     Reply with quote

Hi Ttelmah,

Ttelmah wrote:

First thing. This is a PPS chip. Currently the compiler will be setting up
software I2C for the master. Software will work for a master, but not for
a slave. Ideally use pin_select on both chips to use the hardware port.
Look at the sticky at the top of the forum about this. So use I2C1, rather
than the pin numbers after setting up the PPS.
You are doing this on the slave. Do the same on the master,


I updated the code like you said as I shared in the post above.

Ttelmah wrote:

Then a comment. What resistor values are you using?. On 3.3v,
something like 3.3K should be used. A larger value than is normally
used on 5v.


I used 1K but I change now as 3.3K instead of 1K.


Ttelmah wrote:

Then this chip is an ANSEL supporting chip. This means it defaults to
having all pins setup as analog. Add:
set_analog_pins();
This sets all the chip pins to digital operation.

Have your chips got 4MHz crystals between pins A4, and A5, with suitable
load capacitors?. Your oscillator setup is saying you do. Unless you have
change your clock setup to use the internal oscillator.

Get rid of 'slow' in the slave. The slave device does not have a 'speed',
only the master does. Setting this can result in incorrect setups on some
chips.


I updated my code as you said.

Ttelmah wrote:

Then a comment. What resistor values are you using?. On 3.3v,
something like 3.3K should be used. A larger value than is normally
used on 5v.


I used 1K but I change now as 3.3K instead of 1K.


Ttelmah wrote:

Then your approach to the interrupt is wrong. The interrupt says that
_one_ byte is available to be read. Not two. You need to use I2c_isr_state
in the interrupt to detect that the first byte is the address and then the
second reception is the data. Only when this arrives, do your flash.
Currently your flash would be too fast too see. Even at 100KHz.
You need to allow a pause in the master. Currently the stuff would send
'non stop', with no time for the slave to do anything.

First start by verifying your master and slave are both running. Simple
flash an LED on each, and check it flashes at the specified speed. Only
once this is working, move on to I2C.


But I didn't understand what you said here. Below is the code after making the edits you mentioned. Could you please fix what you mean on the code?

Code:

//Slave
#include <16F18346.H>
#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT


/* Setup I2C */

#pin_select SCL1OUT = PIN_C3
#pin_select SCL1IN  = PIN_C3

#pin_select SDA1OUT = PIN_C4
#pin_select SDA1IN  = PIN_C4

#use i2c(SLAVE, I2C1, address=0xa0, FORCE_HW)

#INT_SSP
void ssp_interupt ()
{
   byte incoming;
   incoming = i2c_read();
   output_high(pin_A2);
   incoming = i2c_read();
   output_low(pin_A2);
}


main()
{
      set_analog_pins(PIN_C3,PIN_C4,pin_A2);
      enable_interrupts(GLOBAL);
      enable_interrupts(INT_SSP);
      while (true)
   {

   }
}


Code:

//Master
#include <16F18346.H>
#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT

/* Delay for 24 mhz internal oscillator */
#use delay(clock = 24MHz)

/* Setup I2C */
#pin_select SCL1OUT = PIN_C3
#pin_select SCL1IN  = PIN_C3

#pin_select SDA1OUT = PIN_C4
#pin_select SDA1IN  = PIN_C4

#use I2C(MASTER, I2C1, SLOW)

main()
{
   setup_oscillator(OSC_HFINTRC_24MHZ,OSC_CLK_DIV_BY_16);
   set_analog_pins(PIN_C3,PIN_C4);
   int8 i2c_command = 66;
   
   while (true)
   {
      /* Master */
      i2c_start();      // Start condition
      i2c_write(0xa0);   // Device address
      i2c_write(i2c_command);   // Write Command
      i2c_stop();      // Stop condition

   }
}


Thank you so much
Ttelmah



Joined: 11 Mar 2010
Posts: 19195

View user's profile Send private message

PostPosted: Fri Jul 02, 2021 8:17 am     Reply with quote

Have you checked both chips are actually running?. Flash an LED on both.
As I said, you need to check this first.

Code:

#INT_SSP
void ssp_interupt ()
{
   byte itemp;
   temp=i2c_isr_state();
   if (temp==0)
   {
        temp=i2c(read); //read the address
        return; //and exit
   }
   if (temp==1)
   {
        temp = i2c_read(); //now read the command
        output_toggle(pin_A2); //signal we have seen this.
   }
}


This will toggle A2 on each command from the master.
L.T.



Joined: 24 Jul 2020
Posts: 62

View user's profile Send private message

PostPosted: Fri Jul 02, 2021 8:28 am     Reply with quote

Ttelmah wrote:
Have you checked both chips are actually running?. Flash an LED on both.
As I said, you need to check this first.

Code:

#INT_SSP
void ssp_interupt ()
{
   byte itemp;
   temp=i2c_isr_state();
   if (temp==0)
   {
        temp=i2c(read); //read the address
        return; //and exit
   }
   if (temp==1)
   {
        temp = i2c_read(); //now read the command
        output_toggle(pin_A2); //signal we have seen this.
   }
}


This will toggle A2 on each command from the master.


Hey there,
I checked, they works. I mean, I can toggle leds. But I upload code like you said, it still didn't work.

Code:
#include <16F18346.H>
#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT


/* Setup I2C */

#pin_select SCL1OUT = PIN_C3
#pin_select SCL1IN  = PIN_C3

#pin_select SDA1OUT = PIN_C4
#pin_select SDA1IN  = PIN_C4

#use i2c(SLAVE, I2C1, address=0xa0, FORCE_HW)

#INT_SSP
void ssp_interupt ()
{
   byte temp;
   temp=i2c_isr_state();
   if (temp==0)
   {
        temp=i2c_read(); //read the address
        return; //and exit
   }
   if (temp==1)
   {
        temp = i2c_read(); //now read the command
        output_toggle(pin_A2); //signal we have seen this.
   }
}


main()
{
      set_analog_pins(PIN_C3,PIN_C4,pin_A2);
      enable_interrupts(GLOBAL);
      enable_interrupts(INT_SSP);
      while (true)
   {

   }
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19195

View user's profile Send private message

PostPosted: Fri Jul 02, 2021 9:41 am     Reply with quote

You are setting the I2C pins and the output LED as analog.
The instruction needs to be used as I posted it, setting _none_ of the
pins as analog. On both chips.
Also have you added a delay in the transmit main?. Their needs to be a
minimum of 5uSec between a stop and a start at the slow I2C rate,
you cannot just loop flat out.
L.T.



Joined: 24 Jul 2020
Posts: 62

View user's profile Send private message

PostPosted: Sun Jul 04, 2021 11:40 pm     Reply with quote

Hi Ttelmah,

Ttelmah wrote:
You are setting the I2C pins and the output LED as analog.
The instruction needs to be used as I posted it, setting _none_ of the
pins as analog. On both chips.


Ttelmah wrote:
Then this chip is an ANSEL supporting chip. This means it defaults to having all pins setup as analog. Add:
set_analog_pins();
This sets all the chip pins to digital operation.


Did you not say to me set the communication pins as analog? I think, I didnt understand what you mean. I set the pins as analog. You can see as below.

Code:
main()
{
   setup_oscillator(OSC_HFINTRC_24MHZ,OSC_CLK_DIV_BY_16);
   set_analog_pins(PIN_C3,PIN_C4);
   int8 i2c_command = 66;


Where should I add the delay? After the start and stop functions?
Ttelmah



Joined: 11 Mar 2010
Posts: 19195

View user's profile Send private message

PostPosted: Mon Jul 05, 2021 1:00 am     Reply with quote

The point is your chip has an ANSEL register. This is a register controlling
whether pins are analog or digital.
Your pins need to be set to _digital_. Now the ANSEL register on wake up
defaults to having all the pins set as analog!. So you need to set the pins
on your chip to be digital. Which means setting _none of the pins_ to analog.
So
set_analog_pins(); //sets all the pins to be digital

Which is what you need (since at the moment you are not doing anything
analog).

On the delay, you need some form of pause in the main loop after
sending the stop. Now honestly, much better for this to be quite long, like
100mSec, since then when the code works, you have a chance to actually
see the result.
L.T.



Joined: 24 Jul 2020
Posts: 62

View user's profile Send private message

PostPosted: Mon Jul 05, 2021 4:33 am     Reply with quote

Ttelmah wrote:
On the delay, you need some form of pause in the main loop after
sending the stop. Now honestly, much better for this to be quite long, like
100mSec, since then when the code works, you have a chance to actually
see the result.


Thank you so much, it works!!

Now, I need to send data from slave to master. Any tips you want to give like this? I haven't tried it yet, I can try and consult you again if I fail.

Thank you!
L.T.



Joined: 24 Jul 2020
Posts: 62

View user's profile Send private message

PostPosted: Mon Jul 05, 2021 6:16 am     Reply with quote

L.T. wrote:
Now, I need to send data from slave to master. Any tips you want to give like this? I haven't tried it yet, I can try and consult you again if I fail.


Actually, I have a question. In my code, slave address is 0xa0 (1010 0000). The first 7 bits here are the slave address (1010 000), the last bit is the R/W bit (0). But wouldn't the last bit have to be 1 for the master to write? When I write 0xa1 to the first write command on the master, the data is not transmitted.Why?
Ttelmah



Joined: 11 Mar 2010
Posts: 19195

View user's profile Send private message

PostPosted: Mon Jul 05, 2021 8:42 am     Reply with quote

For writes, the slave code gets a lot more complex.
Are you only ever going to read/write one byte, or is more going to happen?.
You need to look at the slave I2c CCS example.
The standard sequence is:

Master sends start
Master sends write address.
Master writes the register address it wants to talk to.
Master sends a restart (start without stop)
Master sends read address.
Master now reads bytes starting from the specified register
For the last read master reads with a NACK
Master sends stop

Now the slave code has:
Slave receives an address with the write bit set. Read this.
slave stores next byte as the register address to use (static value).
slave stores any subsequent bytes into this and subsequent addresses.
Slave receives an address with the read bit set. Slave must read this
without releasing clock. Then write the byte from the register address
to the I2C bus. Release the clock. Increment the register address.
For each subsequent master read, load the next byte.

The slave code shows how to do this.

A series of 'vital' things apply.
First not releasing the clock. The slave must hold the clock until the
data reply has been loaded. It must both read the arriving address and
load the reply data,
Then the master sending the inverted ACK on the last read. This resets
the slave peripheral, and if not done can result in things getting out of
sync.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Jul 05, 2021 2:03 pm     Reply with quote

L.T. wrote:

When I write 0xa1 to the first write command on the master, the data is not transmitted. Why?

Do you have pull-up resistors on SDA and SCL ? You need them.
For a 5v system, you can use 4.7K pullups. If it still doesn't work,
post your test program that fails.
L.T.



Joined: 24 Jul 2020
Posts: 62

View user's profile Send private message

PostPosted: Tue Jul 06, 2021 4:27 am     Reply with quote

PCM programmer wrote:
L.T. wrote:

When I write 0xa1 to the first write command on the master, the data is not transmitted. Why?

Do you have pull-up resistors on SDA and SCL ? You need them.
For a 5v system, you can use 4.7K pullups. If it still doesn't work,
post your test program that fails.


Hello there,
I have a 3.3V supply voltage and the value of the pull-up resistors is 2KOhm. When I set the address of slave microcontroller as 0x12 and send 0x12(00010010) "slave address (0001001)+read command(0)" from master the communication is ok. Master is sending data, slave is reading. But if I change it to 0x13(00010011) "slave address (0001001)+write command(1)" the communication fails. However, the opposite is true. In order to send data from the master, the master must send a write(1) command. Am I wrong?

The code is:
Code:
#include <16F18346.H>
#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT

#define Slave_Read   0x12
#define Slave_Write   0x13

/* Delay for 4 mhz crystal */
#use delay(clock = 24MHz)

/* Setup I2C */
#pin_select SCL1OUT = PIN_C3
#pin_select SCL1IN  = PIN_C3

#pin_select SDA1OUT = PIN_C6
#pin_select SDA1IN  = PIN_C6

#use I2C(MASTER, I2C1, SLOW)

main()
{
   setup_oscillator(OSC_HFINTRC_24MHZ,OSC_CLK_DIV_BY_16);
   set_analog_pins();
   int8 i2c_command = 66;
   
   while (true)
   {
      /* Master */
      i2c_start();      // Start condition
      i2c_write(0x13);   // Device address
      i2c_write(i2c_command);   // Write Command
      i2c_stop();      // Stop condition
      delay_ms(100);

   }
}


Code:
#include <16F18346.H>
#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT


/* Setup I2C */
#pin_select SCL1OUT = PIN_C3
#pin_select SCL1IN  = PIN_C3

#pin_select SDA1OUT = PIN_C6
#pin_select SDA1IN  = PIN_C6

#use i2c(SLAVE, I2C1, address=0x12, FORCE_HW)

#INT_SSP
void ssp_interupt ()
{
   byte temp;
   temp=i2c_isr_state();
   if (temp==0)
   {
        temp=i2c_read(); //read the address
        return; //and exit
   }
   if (temp==1)
   {
        temp = i2c_read(); //now read the command
        output_toggle(pin_A2); //signal we have seen this.
   }
}


main()
{
      set_analog_pins();
      enable_interrupts(GLOBAL);
      enable_interrupts(INT_SSP);
      while (true)
   {

   }
}
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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