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

Setting port for I2C
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
rovtech



Joined: 24 Sep 2006
Posts: 262

View user's profile Send private message AIM Address

Setting port for I2C
PostPosted: Sun Jul 12, 2020 8:09 am     Reply with quote

How should the SCL and SDA pins be set in set_tris_c() ?
I resurrected a program from 2014 and happened to have a PIC programmed with the code. The PIC worked in the circuit (graphics on an LCD via I2C) but when I programmed a new PIC with the old code it did not work. There were no errors or warnings when compiled.
Stripping the code down from 298 lines to this
Code:
/* Pre-processor directives */
 #include <16F1938.H>
 #fuses INTRC_IO, NOWDT, PUT, NOPROTECT, BROWNOUT, MCLR
 #use delay (clock=8000000)
 #use I2C (master, SCL=PIN_C3, SDA=PIN_C4)
 #byte portc = getenv("SFR:PORTC")
 
// The main function
void main(void)
 {
// setup ports
  set_tris_c (0x00);                 // all outputs
 
// clear display
   I2C_START ();                // start I2C
   I2C_WRITE (0x4e);        // addr of LCD
   I2C_WRITE ('C');           // C CL to clear display
   I2C_WRITE ('L');           // L
   I2C_STOP ();                // stop I2C

}                        // end of main function

// end

I found it still did not work. I had been suspecting the LCD address as it was 7 bit 0x27 which needs to be shifted to 0x4E. This was not the problem.
When portC was changed to all inputs the program compiled and ran.
Code:
  set_tris_c (0xff);                 // all inputs

Even just commentating out the statement fixed the problem.
I checked several other programs from that time and all had a comment "Working" but all had portC set to output. I can only guess that the version of compiler I used back then corrected this error. Why does my current compiler (PCM ver 5.064) not even give a warning?
What is the correct way to set the pin directions for I2C? They need to be bidiectional and I would think the compiler would take care of that.
newguy



Joined: 24 Jun 2004
Posts: 1903

View user's profile Send private message

PostPosted: Sun Jul 12, 2020 8:44 am     Reply with quote

The I2C lines are supposed to be set to inputs. What you're seeing rather makes me suspicious that the compiler isn't properly handling the tris register.

This is just one more justification that my habit of always specifying #use fast_io, for me at least, is the right choice. I don't want the compiler handling such a simple thing as whether a line is an input or an output; I sleep much better knowing that I set it properly and nothing will second guess me.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Jul 12, 2020 10:05 am     Reply with quote

You're not supposed to set the i2c pins to outputs. That's wrong.
Here's a quote from the 16F1938 data sheet:
Quote:
24.4.3 SDA AND SCL PINS
Selection of any I2C mode with the SSPEN bit set,
forces the SCL and SDA pins to be open-drain. These
pins should be set by the user to inputs by setting the
appropriate TRIS bits

The 2nd problem you have is about understanding the CCS compiler.
The whole idea of CCS is to remove mundane trivial code-writing from
the user. The compiler does it for you in most cases. If you are a
a newbie and you try to out-think the compiler, you will almost always
sabotage yourself.

Look at the .LST file for your program (compiled with vs. 5.094):
Quote:

......... void main(void)
0017: MOVLW 72
0018: MOVLB 01
0019: MOVWF OSCCON

// Here, the compiler sets both i2c pins to inputs, per the data sheet:
001A: BSF TRISC.TRISC3
001B: BSF TRISC.TRISC4

001C: MOVLB 04
001D: BCF SSPCON3.DHEN
001E: BCF SSPCON3.AHEN
001F: BCF SSPCON3.SDAHT
0020: MOVLW 13
0021: MOVWF SSPADD
0022: MOVLW 28
0023: MOVWF SSPCON1
0024: BSF SSPSTAT.SMP
0025: BCF SSPSTAT.CKE
0026: MOVLB 0F
0027: CLRF LCDCON
0028: CLRF LCDPS
0029: CLRF LCDSE0
002A: CLRF LCDSE1
002B: CLRF 79A
002C: MOVLB 03
002D: CLRF ANSELA
002E: CLRF ANSELB
002F: MOVLB 02
0030: CLRF CM1CON1
0031: CLRF CM1CON0
0032: CLRF CM2CON1
0033: CLRF CM2CON0
.................... {
.................... // setup ports

// Here, you change them to outputs, and it doesn't work:
.................... set_tris_c (0x00); // all outputs
0034: MOVLW 00
0035: MOVLB 01
0036: MOVWF TRISC
....................

There is one thing you can do that will help. Set all unused pins to
low-level outputs. The compiler won't do that for you. You can do this
as shown below (for example):
Code:

output_low(PIN_A0);
output_low(PIN_A1);
output_low(PIN_A5);
Ttelmah



Joined: 11 Mar 2010
Posts: 19236

View user's profile Send private message

PostPosted: Sun Jul 12, 2020 10:32 am     Reply with quote

The key thing is the compiler correctly sets up the pins for the I2C
to work.
You then override it's setting with the line:

set_tris_c (0x00); // all outputs

If you want to set all the other pins to output, then use:

set_tris_c (0x18); //.all except I2C as outputs.
rovtech



Joined: 24 Sep 2006
Posts: 262

View user's profile Send private message AIM Address

PostPosted: Sun Jul 12, 2020 10:39 am     Reply with quote

Thanks everyone. This was a mistake from 5 years ago. I have 3 programs using the same hardware and all have the same mistake. I don't know why they worked back then. I always make a comment "working" after a program is developed and working. I guess I was lucky.
I have always wondered about setting pins, especially if they become bi-directional so I usually set them as inputs and assume the compiler will fix it.
What about newguy's suggestion of using fast_io?
temtronic



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

View user's profile Send private message

PostPosted: Sun Jul 12, 2020 11:55 am     Reply with quote

Using fast_io() is a two edged sword...
If, IF, you properly use it, it will speed up port/IO accesses and smaller code
but, BUT, if you make a bit an input instead of an output (or vice versa), say 3 months later, during a PCB layout revision... you can spend days trying to understand WHY doesn't it work now ???
Frankly, with the fast PICs of today, using fast_io() really isn't needed unless you've got custom hardware that requires very, very 'tight' timing. I've only needed it twice in 20+ years....
I just use 'standard mode'...though I could 'tweak' better performance using fast_io(), it's just not necessary 99.44% of the time.
newguy



Joined: 24 Jun 2004
Posts: 1903

View user's profile Send private message

PostPosted: Sun Jul 12, 2020 1:42 pm     Reply with quote

fast_io() is an absolute must if your aim is the lowest possible power.

In the end, it comes down to an issue of trust. Do you trust yourself, or do you trust that the author(s) of the compiler did things properly?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Jul 12, 2020 5:41 pm     Reply with quote

newguy wrote:

fast_io() is an absolute must if your aim is the lowest possible power.

Can you explain this.
rovtech



Joined: 24 Sep 2006
Posts: 262

View user's profile Send private message AIM Address

PostPosted: Sun Jul 12, 2020 5:55 pm     Reply with quote

How would I handle a situation where I must, because of limited pins, use mixed I/O.
Code:
set_tris_c(0b01011000);

Now I need to read from some pins and write a pattern to C5, C2, C1, C0, as well as use I2C on C3 and C4.
I normally try to avoid this situation. I could set up a structure for the four outputs and send the pattern but I'm not even sure how I only send four bits.
I suspect that sending 1100 then 1111 to C5, C2, C1, C0 as below
Code:
output_c(0b00100100);
output_c(0b10100111);

would mess up the I2c and other inputs and it sounds dangerous. I remember reading in a data sheet that if I write to an input the data is not placed on the pin but does get written to some internal register. Does this overwrite the last input on the read pin? Or am I confused.
Code:
output_bit(PIN_C5);

Is safe but clumsy.
temtronic



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

View user's profile Send private message

PostPosted: Sun Jul 12, 2020 6:05 pm     Reply with quote

re:
Quote:
fast_io() is an absolute must if your aim is the lowest possible power.

It could be that less executable code = lower power consumption, but I'd have to see the 'numbers'. Obviously it'd only apply to battery powered PIC projects.
newguy



Joined: 24 Jun 2004
Posts: 1903

View user's profile Send private message

PostPosted: Sun Jul 12, 2020 7:06 pm     Reply with quote

temtronic wrote:
re: fast_io() is an absolute must if your aim is the lowest possible power.

It could be that less executable code = lower power consumption, but I'd have to see the 'numbers'. Obviously it'd only apply to battery powered PIC projects.


That's it exactly. Wake, execute the lowest number of instructions possible, go back to sleep. Save a handful of instructions, then multiply that by the hundreds of thousands of wake-sleep cycles and you've added months to the life of your product on a set of batteries.
Ttelmah



Joined: 11 Mar 2010
Posts: 19236

View user's profile Send private message

PostPosted: Sun Jul 12, 2020 11:13 pm     Reply with quote

Well, the key to remember is you don't have to use fast_io, to have the same effect....

So:
Code:

#byte PortBout=getenv("SFR:LATB")
#byte PortBin=getenv("SFR:PORTB")
//For PIC18, and modern PIC16's.

//Then your code uses 'standard IO' as normal, until the point in the
//'low power' section, where you want to read or write the port.

    PortBout=xxxxx;

//Loads the output data latch, leaving the TRIS as standard IO has set it
//Result only bits set as 'output' change.

   //To read the inputs:

   val=PortBin;

In both cases the 'I/O' is directly to the port registers. No extra instructions.
You get the advantage of 'standard IO' controlling the TRIS, but also
the instruction efficiency of fast IO..... Very Happy

As posted would need changing for 'old' PIC16's that don't have a separate
LAT register. However the PIC involved here is one that does.
rovtech



Joined: 24 Sep 2006
Posts: 262

View user's profile Send private message AIM Address

PostPosted: Mon Jul 13, 2020 1:59 pm     Reply with quote

Back to my last question:
"How would I handle a situation where I must, because of limited pins, use mixed I/O."
I actually have the circuit connected and as I suspected it does not work.
When I get to the one added line:
Code:
    output_c (0x24);


the program and I2C freezes. This is trying to output 00 to the I2C pins (C4, C3) which are set as inputs.
What exactly is happening and how do I resolve such a situation.
If I add
Code:
#use fast_io

I get the error " Option invalid Not a valid port:"
gaugeguy



Joined: 05 Apr 2011
Posts: 290

View user's profile Send private message

PostPosted: Mon Jul 13, 2020 2:03 pm     Reply with quote

fast_io is set per port and not globally. The correct usage would be:
Code:
#use fast_io(C)
temtronic



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

View user's profile Send private message

PostPosted: Mon Jul 13, 2020 2:11 pm     Reply with quote

I'm curious......

Why not use output_bit(pin,value) instead of writing the whole port ?

It's fast and will not interfere with the I2C pins.
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