• AVR Freaks

AnsweredHot!I2C with PIC16F18323

Author
DeltaElectronics
Starting Member
  • Total Posts : 46
  • Reward points : 0
  • Joined: 2016/06/24 07:25:46
  • Location: 0
  • Status: offline
2019/06/05 15:55:08 (permalink)
0

I2C with PIC16F18323

Hello to everybody,
I am trying to implement a simple I2C communication library as done in the following tutorials:
https://www.electrosome.c...1_MSSP_Status_Register
https://www.teachmemicro.com/pic16-i2c/#
So I decided to make a simple test circuit like the image file 'Immagine.png'
And I write the following test code:
 
#define _XTAL_FREQ 4000000


void I2C_Master_Init(const unsigned long speed) {
    SSP1CON1 = 0b00101000;
    SSP1CON2 = 0;
    SSP1ADD = (_XTAL_FREQ/(4*speed))-1;
    SSP1STAT = 0;
    TRISC0 = 1; //SCL
    TRISC1 = 1; //SDA
}

void I2C_Master_Wait() {
    while ((SSP1STAT & 0x04) || (SSP1CON2 & 0x1F)); //Transmit is in progress
}

void I2C_Master_Start() {
    I2C_Master_Wait();
    SEN = 1;
    while (SEN);
}

void I2C_Master_Repeated_Start() {
    I2C_Master_Start();
}

void I2C_Master_Stop() {
    I2C_Master_Wait();
    PEN = 1;
    while(PEN);
}

_Bool I2C_Master_Write(unsigned d) {
    I2C_Master_Wait();
    SSP1BUF = d; //Write data to SSPBUF
    SSP1IF = 0;
 // while (!SSP1IF);
    return ACKSTAT;
}

unsigned short I2C_Master_Read(unsigned short a) {
  unsigned short temp;
  I2C_Master_Wait();
  RCEN = 1;
  I2C_Master_Wait();
  temp = SSPBUF; //Read data from SSPBUF
  I2C_Master_Wait();
  ACKDT = (a)?0:1; //Acknowledge bit
  ACKEN = 1; //Acknowledge sequence
  return temp;
}

void main(void) {
    OSCCON1 = 0x60;;
    OSCFRQbits.HFFRQ = 0b011;
    TRISC4 =0;
    TRISC3 =0;
    I2C_Master_Init(100000);
    __delay_ms(3000);
    while(1) {
        LATCbits.LATC4 = 1;
        LATCbits.LATC3 = 0;
        I2C_Master_Start();
        I2C_Master_Write(0x3C);
        I2C_Master_Stop();
        __delay_ms(1000);
        LATCbits.LATC4 = 0;
        LATCbits.LATC3 = 1;
        I2C_Master_Start();
        I2C_Master_Write(0x3E);
        I2C_Master_Stop();
        __delay_ms(1000);
    }
}

 
But, while the two LEDS blinks regularly as a square wave at 0,5Hz & duty 50%, at SDA and SCK pins I never see anything when I attach them on my oscilloscope probes.
Because it's been for many days now I am stuck on this problem, I will be very grateful to everybody will help me to solve this problems.
 
 
Enclosed:
file 'Immagine.png' the test circuit drawing
file 'HelloI2C.zip' my test program and library
DeltaElectronics

Attached Image(s)

#1
ric
Super Member
  • Total Posts : 22768
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: online
Re: I2C with PIC16F18323 2019/06/05 16:54:07 (permalink) ☄ Helpfulby DeltaElectronics 2019/06/19 03:08:17
+1 (1)
You neglected to switch RC0 and RC1 from analog to digital mode.
This is always required when using analog capable pins on a PIC.
 
Change
_Bool I2C_Master_Write(unsigned d) {
    I2C_Master_Wait();
    SSP1BUF = d; //Write data to SSPBUF
    SSP1IF = 0;
 // while (!SSP1IF);
    return ACKSTAT;
}

to
_Bool I2C_Master_Write(unsigned char d) {
    I2C_Master_Wait();
    SSP1IF = 0;
 
    SSP1BUF = d; //Write data to SSPBUF
    while (!SSP1IF);    // wait until the transfer has completed
    return ACKSTAT;
}

as your version was reading ACKSTAT too early.
Then, get your main code to check the return value. If it is 1, the slave did not respond to the transfer => you got a NAK.
 I also don't see the need to use "_Bool". Why not just use "unsigned char" or "bit" as the return value type.
 
post edited by ric - 2019/06/05 16:59:08

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#2
DeltaElectronics
Starting Member
  • Total Posts : 46
  • Reward points : 0
  • Joined: 2016/06/24 07:25:46
  • Location: 0
  • Status: offline
Re: I2C with PIC16F18323 2019/06/05 23:14:38 (permalink)
0
Hello ric, thanks for replying me...
 
In the first version, I left this line

WHILE (!SSP1F);

uncommented, but then I noticed that programs always blocks indefinitely on this line;
i.e. SSP1F flag never turns to 1 but it still continues to stay at 0 value

you wrote
 
You neglected to switch RC0 and RC1 from analog to digital mode.
This is always required when using analog capable pins on a PIC.

 
How to do it ?
In the tutorials I read it is not indicated to do it, why ?
#3
ric
Super Member
  • Total Posts : 22768
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: online
Re: I2C with PIC16F18323 2019/06/05 23:22:42 (permalink) ☄ Helpfulby DeltaElectronics 2019/06/19 03:08:31
+1 (1)
Have you read the datasheet for your PIC device?
Analog/digital on PORTC is controlled by the ANSELC register.
 
Did you notice that I moved your line that clears SSPIF?
You must clear it BEFORE you write to SSPBUF.
 

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#4
DeltaElectronics
Starting Member
  • Total Posts : 46
  • Reward points : 0
  • Joined: 2016/06/24 07:25:46
  • Location: 0
  • Status: offline
Re: I2C with PIC16F18323 2019/06/05 23:40:20 (permalink)
0
Another silly question... but, by default, it seems me that PORTC is digital, not analog.
On RC4 and RC3 pins I attached two led which regularly blinks, without problems.
So I should add the following lines

ANSELC0 = 0;
ANSELC1 = 0;

before to start I2C communications ?
#5
ric
Super Member
  • Total Posts : 22768
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: online
Re: I2C with PIC16F18323 2019/06/05 23:47:11 (permalink)
0
DeltaElectronics
Another silly question... but, by default, it seems me that PORTC is digital, not analog.

What leads you to that conclusion?
 
Examine the "Power On" status of the ANSELC register.
 
If you are talking about being able to control the LEDs, that's an OUTPUT function, and has nothing to do with the INPUT mode (so long as you correctly write to LATC, and not PORTC, which you are doing.)
post edited by ric - 2019/06/05 23:59:09

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#6
DeltaElectronics
Starting Member
  • Total Posts : 46
  • Reward points : 0
  • Joined: 2016/06/24 07:25:46
  • Location: 0
  • Status: offline
Re: I2C with PIC16F18323 2019/06/05 23:59:26 (permalink)
0
Hello Ric, thanks you very much once again for your attention in helping me....
Surey I'll immediately try to do as you have suggested me when I will return back home (now I am at work); aniway I am very surprised because every tutorial I read (for esample the official Microchip AN735 http://ww1.microchip.com/downloads/en/appnotes/00735a.pdf) does not mention to change ANSELC register.
Thank again for your help.
 
#7
ric
Super Member
  • Total Posts : 22768
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: online
Re: I2C with PIC16F18323 2019/06/06 00:05:22 (permalink)
+1 (1)
What device are those tutorials targeting?
Many older PICs don't have analog capability on PORTC, so it wouldn't matter.
 
Edit: I just checked. That App Note was written in 2000, i.e. nineteen years ago.
Most new PIC16F devices now have analog capability on almost every pin.
post edited by ric - 2019/06/06 00:11:34

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#8
mbrowning
Just a Member
  • Total Posts : 1432
  • Reward points : 0
  • Joined: 2005/03/16 14:32:56
  • Location: Melbourne, FL
  • Status: online
Re: I2C with PIC16F18323 2019/06/06 00:10:48 (permalink)
+2 (2)
You are presenting a 20 year old document as evidence but apparently are unwilling to study the datasheet which has nearly all the information you need for your very modern device. Amazing, but unfortunately common.

Follow ric’s advice and read the datasheet (and any errata) before messing with random “tutorials” from the last century.

Oh well - there's always next year
#9
DeltaElectronics
Starting Member
  • Total Posts : 46
  • Reward points : 0
  • Joined: 2016/06/24 07:25:46
  • Location: 0
  • Status: offline
Re: I2C with PIC16F18323 2019/06/15 08:43:01 (permalink)
0
Hello to everybody,
As previuosly suggested by @Ric and other, I modified my code as following

 
void I2C_Master_Init(const unsigned long speed) {
SSP1CON1 = 0b00101000;
SSP1CON2 = 0;
SSP1CON3 = 0b01100000;
SSP1DATPPS = 0x13;
SSP1CLKPPS = 0x12;
INTCONbits.GIE = 1;
SSP1ADD = (_XTAL_FREQ/(4*speed))-1;
SSP1STAT = 0;
ANSC0 = 0;
ANSC1 = 0;
TRISC0 = 1; //SCL
TRISC1 = 1; //SDA
}
 
 
 
_Bool I2C_Master_Write(unsigned d) {
I2C_Master_Wait();
SSP1BUF = d; //Write data to SSPBUF
SSP1IF = 0;
while (!SSP1IF);
return ACKSTAT;
}
 

But I noticed that code stops at this instruction

 
while (!SSP1IF);
 

i.e. SSP1IF flag never sets... and at oscilloscope I continue to watch any I2C signal, only 5V.
What's the problem ?
post edited by DeltaElectronics - 2019/06/15 09:15:20
#10
1and0
Access is Denied
  • Total Posts : 9316
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: I2C with PIC16F18323 2019/06/15 10:36:12 (permalink)
+1 (1)
Read Ric's Post #2 again carefully.  Compare the code there with yours lines by lines.
 
#11
DeltaElectronics
Starting Member
  • Total Posts : 46
  • Reward points : 0
  • Joined: 2016/06/24 07:25:46
  • Location: 0
  • Status: offline
Re: I2C with PIC16F18323 2019/06/15 10:55:37 (permalink)
0
Hello @1and0My current code is here:

//file i2c.h
#include <xc.h>
#include "config.h"

void I2C_Master_Init(const unsigned long speed) {
SSP1CON1 = 0x28;
SSP1CON1bits.SSPEN=1;
SSP1CON2 = 0;
SSP1CON3 = 0b01100000;
INTCONbits.GIE = 1;
PIR1bits.SSP1IF = 1;
SSP1CON3bits.SCIE = 1;
SSP1CON3bits.PCIE = 1;

SSP1ADD = (_XTAL_FREQ/(4*speed))-1;
SSP1STAT = 0;
ANSELC = 0x00;
TRISC0 = 1; //SCL
TRISC1 = 1; //SDA
}
void I2C_Master_Wait() {
while ((SSP1STAT & 0x04) || (SSP1CON2 & 0x1F)); //Transmit is in progress
}

void I2C_Master_Start() {
I2C_Master_Wait();
SEN = 1;
while (SEN);
}
void I2C_Master_Repeated_Start() {
I2C_Master_Start();
}
void I2C_Master_Stop() {
I2C_Master_Wait();
PEN = 1;
while(PEN);
}
_Bool I2C_Master_Write(unsigned d) {
I2C_Master_Wait();
SSP1IF=0;
SSP1BUF = d; //Write data to SSPBUF
while (!SSP1IF);
return ACKSTAT;
}
unsigned short I2C_Master_Read(unsigned short a) {
unsigned short temp;
I2C_Master_Wait();
RCEN = 1;
I2C_Master_Wait();
temp = SSPBUF; //Read data from SSPBUF
I2C_Master_Wait();
ACKDT = (a)?0:1; //Acknowledge bit
ACKEN = 1; //Acknowledge sequence
return temp;
}
/code]and 

/file main.c
#include <xc.h>
#include "config.h"
#include "i2c.h"
void main(void) {
OSCCON1 = 0x60;;
OSCFRQbits.HFFRQ = 0b011;
TRISC4 =0;
TRISC3 =0;

I2C_Master_Init(100000);
_Bool green = 1;
while(1) {
__delay_ms(500);
if (green) {
LATCbits.LATC4 = 1;
LATCbits.LATC3 = 0;
green = 0;
} else {
LATCbits.LATC4 = 0;
LATCbits.LATC3 = 1;
green = 1;
}
I2C_Master_Start();
I2C_Master_Write(0x3C);
I2C_Master_Stop();
}
}
but it continue stops at the following instruction


while (!SSP1IF);
and olnly a LED is on.
If instaeas I commemt the infinete loop, two led regularly blinks, at oscilloscope display I see only two plain line.
post edited by DeltaElectronics - 2019/06/15 11:30:25
#12
davekw7x
Entropy++
  • Total Posts : 1769
  • Reward points : 0
  • Joined: 2012/01/16 12:01:07
  • Location: Left Coast, USA
  • Status: offline
Re: I2C with PIC16F18323 2019/06/15 14:11:54 (permalink)
+1 (1)
You must make both Output and Input PPS assignments for the I2C Signals:

For example to use pin RC0 as I2C SCL and RC1 as I2C SDA:

Assign Output Pins:
Look at the Register 13-2 description in the Data sheet to see values for pins RC0 and RC1 on the right hand side.
I use binary notation right off of the data sheet instead of hex; use whatever suits your fancy, but make sure to get it right!

    RC0PPS     = 0b?????;   // SCL1 output sent to RC0
    RC1PPS     = 0b?????;   // SDA1 output sent to RC1


You must assign the same pins to I2C input signals.
Look in Table 13-1 to see values for SCL1 and SDA1

    SSP1CLKPPS = 0b?????;   // RC0 sent to SCL1 input
    SSP1DATPPS = 0b?????;   // RC1 sent to SDA1 input




Regards,

Dave
post edited by davekw7x - 2019/06/15 18:23:28

Attached Image(s)


Sometimes I just can't help myself...
#13
DeltaElectronics
Starting Member
  • Total Posts : 46
  • Reward points : 0
  • Joined: 2016/06/24 07:25:46
  • Location: 0
  • Status: offline
Re: I2C with PIC16F18323 2019/06/17 09:48:33 (permalink)
0
@davekw7x
Like this

 
void I2C_Master_Init(const unsigned long speed) {
SSP1CON1 = 0x28;
SSP1CON1bits.SSPEN=1;
SSP1CON2 = 0;
SSP1CON3 = 0b01100000;
SSP1DATPPS = 0x13;
SSP1CLKPPS = 0x12;
INTCONbits.GIE = 1;
PIR1bits.SSP1IF = 1;
SSP1CON3bits.SCIE = 1;
SSP1CON3bits.PCIE = 1;

RC0PPSbits.RC0PPS = 0x19; //RC0->SDA1
RC1PPSbits.RC1PPS = 0x18; //RC1->SCL1*/
SSP1DATPPS = 0x11;
SSP1CLKPPS = 0x10;
SSP1ADD = (_XTAL_FREQ/(4*speed))-1;
 
SSP1STAT = 0;
ANSELC = 0x00;
TRISC0 = 1; //SCL
TRISC1 = 1; //SDA
}
 

I just tried, but nothing happens.
post edited by DeltaElectronics - 2019/06/17 09:50:58
#14
davekw7x
Entropy++
  • Total Posts : 1769
  • Reward points : 0
  • Joined: 2012/01/16 12:01:07
  • Location: Left Coast, USA
  • Status: offline
Re: I2C with PIC16F18323 2019/06/17 10:44:52 (permalink) ☼ Best Answerby DeltaElectronics 2019/06/19 03:07:50
+1 (1)
DeltaElectronics
...nothing...

Here are your assignments with my comments on the right

 RC0PPSbits.RC0PPS = 0x19; //RC0->SDA1   <--- 0b11001: SDA output to RC0
 RC1PPSbits.RC1PPS = 0x18; //RC1->SCL1*/ <--- 0b11000: SCL output to RC1
 SSP1DATPPS = 0x11;        //            <--- 0b10001: RC1 to SDA input
 SSP1CLKPPS = 0x10;        //            <--- 0b10000: RC0 to SCK input

 
Bottom line: Which is SCL and which is SDA?  Assignments must be consistent.
 
Note that, for this particular chip,you don't have to make assignments to default input PPS functions, but I always put them there for documentation purposes.
 
Not all devices have the default input assignments, and sometimes I use other than default pins. Putting the instructions as a Placeholder makes it easier for me to see the setup in case I want to change anything.  But you gotta get it right!  You always have to make output PPS pin assignments.
 
[/Begin Edit]
Please clean up your code.  Superfluous instructions make debugging a bigger nightmare than you (or I)
deserve.
 
For starters, remove these

 SSP1CON3 = 0b01100000; // <--- Why the heck are you messing with these "slave-only" bits?
 SSP1DATPPS = 0x13;     // <--- Incorrect and Superfluous; overwritten by later instruction
 SSP1CLKPPS = 0x12;     // <--- Incorrect and Superfluous; overwritten by later instruction

[/End Edit]
 
Regards,
 
Dave
post edited by davekw7x - 2019/06/17 17:10:30

Sometimes I just can't help myself...
#15
DeltaElectronics
Starting Member
  • Total Posts : 46
  • Reward points : 0
  • Joined: 2016/06/24 07:25:46
  • Location: 0
  • Status: offline
Re: I2C with PIC16F18323 2019/06/19 03:07:00 (permalink)
0
@davekw7x
Tombola !!!!
Or better 'Bingo' as you americans calls this italian game :-)
It works fine; thank you very much for your comments very helpful.
Another silly question: As it seems me to understand reading from DS and you comments, it seems me there is the possibility to choose fon whic MCU pins put I2C clk and sda; i.e. for example this chunk of code
 


 RC2PPSbits.RC2PPS = 0x19; //RC2->SDA1   <--- 0b11001: SDA output to RC2
 RC3PPSbits.R31PPS = 0x18; //RC3->SCL1*/ <--- 0b11000: SCL output to RC3
SSP1DATPPS = 0b10010;        //            <--- 0b10001: RC2 to SDA input
SSP1CLKPPS = 0b10011;        //            <--- 0b10000: RC3 to SCK input

[/code]
configures SDA channel on RC2 and CLK one on RC3; right ?
But in reading from table 2 PIN Allocation Table, it seems that only RC0 can be dedicated to SDA channel and RC1 to CLK. It puzzles me a lot !!!Smile: Smile
#16
pcbbc
Super Member
  • Total Posts : 1108
  • Reward points : 0
  • Joined: 2014/03/27 07:04:41
  • Location: 0
  • Status: offline
Re: I2C with PIC16F18323 2019/06/19 04:57:43 (permalink)
0
DeltaElectronicsTombola !!!!
Or better 'Bingo' as you Americans calls this Italian game :-)

No, in Britain we say "Bingo" when we finally get something right also, and it is also used for the name of the Italian "Tombola" game.
 
Tombola is a completely different game for both US and UK.  Seems there has been a mix-up coming over to the British English.  So not just an American misunderstanding.
#17
ric
Super Member
  • Total Posts : 22768
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: online
Re: I2C with PIC16F18323 2019/06/19 06:46:35 (permalink)
0
DeltaElectronics
...
Another silly question: As it seems me to understand reading from DS and you comments, it seems me there is the possibility to choose fon whic MCU pins put I2C clk and sda; i.e. for example this chunk of code
 ...
configures SDA channel on RC2 and CLK one on RC3; right ?

Yes

But in reading from table 2 PIN Allocation Table, it seems that only RC0 can be dedicated to SDA channel and RC1 to CLK. It puzzles me a lot !!!Smile: Smile

No it doesn't.
Read "Note 4" underneath.
You can use any pin, but you are restricted to TTL/ST voltage levels if you use the other pins.
RC0 and RC1 support I2C/SMBUS specific voltage thresholds.
If you're just using 5V I2C, then it really doesn't matter.
 

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#18
davekw7x
Entropy++
  • Total Posts : 1769
  • Reward points : 0
  • Joined: 2012/01/16 12:01:07
  • Location: Left Coast, USA
  • Status: offline
Re: I2C with PIC16F18323 2019/06/19 06:54:48 (permalink)
0
[Edit]Ric beat me to it.  Oh, well...[/Edit]
 
DeltaElectronics
 
But in reading from table 2 PIN Allocation Table, it seems that only RC0 can be dedicated to SDA channel and RC1 to CLK. It puzzles me...


Look at note (4) at the bottom of the table:

4:     These pins are configured for I2C logic levels as described in Section 13.3 “Bidirectional Pins”; clock and data signals may be assigned to any of these pins. Assignments to the other pins (e.g., RA5) will operate, but logic levels will be standard TTL/ST as selected by the INLVL register.

The specially-dedicated SDA and SCL pins have slightly different electrical characteristics specifically tailored to I2C/SMB signals, but in my experience, using PPS to select other pins with standard logic levels is no problem with my usual connections.
 
Regards,
 
Dave
 
Footnote: Never heard of Trombola.  My slightly younger nephew would probably say, "Right on!"  My slightly older brother would probably say, "Huzzah!"  I just say, "Whew!"
 
post edited by davekw7x - 2019/06/19 07:03:03

Sometimes I just can't help myself...
#19
Jump to:
© 2019 APG vNext Commercial Version 4.5