|
|
View previous topic :: View next topic |
Author |
Message |
Torello
Joined: 29 Sep 2006 Posts: 120
|
Setup/enable I2C internal pull-ups |
Posted: Tue Apr 30, 2024 11:25 pm |
|
|
Hi,
How do I enable/setup the internal pull-ups for I2C? Preferably with a CCS build-in function.
I'm using the PIC18F26Q83 that does have them.
I would only like pull-ups on those two pins (C3/C4) _________________ Regards, Edwin. PCWHD v5.114 |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19495
|
|
Posted: Wed May 01, 2024 2:00 am |
|
|
OK.
Several things. The internal pullups are _only_ acceptable for slow speed
I2C, with a very short bus (low capacitance). If you have a bus that is
more than perhaps 150mm long, or uses more than perhaps 2 devices,
or clocks over perhaps 200KHz, you will have to provide external pullups.
Technically you can enable fast mode on the pins with this, and turn the
current up to 20* the default level, but reviews from users are suggesting
this can be unreliable. So keep things slow if you want this to work.
100KHz max.
Now the good thing is you are on the standard I2C pins (you must still
set PPS to these pins). Only the pull ups on these pins support the
current needed for I2C.
Code: |
#include <maini2c18.h>
#pin_select SCL1=PIN_C3
#pin_select SDA1=PIN_C4
#use i2C(I2C1, slow=100000)
#BYTE RC3I2C=getenv("SFR:RC3I2C")
#BYTE RC4I2C=getenv("SFR:RC4I2C")
#define TENTIMES 0x20
#define TWENTYTIMES 0x30
#define MASK 0xC3
void main()
{
port_c_pullups(0b00001100); //enable weak pullups
RC3I2C = (RC3I2C & MASK) | TENTIMES; //set current to ten times on C3
RC4I2C = (RC4I2C & MASK) | TENTIMES; //set current to ten times on C4
//etc..
|
|
|
|
Torello
Joined: 29 Sep 2006 Posts: 120
|
|
Posted: Wed May 01, 2024 3:54 am |
|
|
Thanx Ttelmah,
I've found more a less the same and was also struggling to get to 400Khz. The use_i2C is quite fuzzy and not always working with given parameters as described in the manual
Code: |
---- In Header file:
#bit FME=getenv("BIT:FME") //'0'= (postscale5, only 10x or 2c PU-currents) '1'= (postscale4, 20, 10, 5x PU-currents)
#byte RC4I2C=getenv("SFR:RC4I2C")
#byte RC3I2C=getenv("SFR:RC3I2C")
#byte I2C1BAUD = getenv("SFR:I2C1BAUD")
#define pSCL PIN_C3
#define pSDA PIN_C4
#pin_select SCL1OUT = pSCL
#pin_select SCL1IN = pSCL
#pin_select SDA1OUT = pSDA
#pin_select SDA1IN = pSDA
#use i2c(stream=MCP9808_Stream, Master, SDA=pSDA, SCL=pSCL, I2C1, CLOCK_SOURCE=HFINTOSC)
---- In C-module:
I2C1BAUD=2; // Scale HFINTOSC by 2+1 and that by 4 (FME=1) ->F_SCL= 4Mhz/12= 333Khz
FME=1; // Div=4, selectable PU-currents: 20, 10, 5x; -> R_pull approx.= 1k1, 2k2, 4k4)
RC3I2C=RC4I2C=0b01010001; // fast slew, Rpull=2k2, I2C thresholds |
_________________ Regards, Edwin. PCWHD v5.114 |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19495
|
|
Posted: Wed May 01, 2024 5:12 am |
|
|
Remember you have to do both pins. What you show only sets C3.....
The pins are individual.
You are selecting fast slew for 400K, but not setting a baud rate for the
#use I2C. Use a baud rate here, rather than writing to I2C baud.
However don't try to think of the internal pullups as being equivalent
to a resistor value. They are not, they are programmed current sources.
So draw more when the signal is low and decline as the signal goes up.
this is why people are finding them not reliable at higher baud rates....
Don't put the pins in the #use I2C. Using I2C1 is all you need. The compiler
(at least on current versions), automatically sets bot the 'in' and 'out', if
you just specify the signal as I show.
You do need to enable the weak pull up though. |
|
|
Torello
Joined: 29 Sep 2006 Posts: 120
|
|
Posted: Wed May 01, 2024 8:48 am |
|
|
Thanx for your extensive help!
I think am doing both pins: RC3I2C=RC4I2C=0b01100001;
~~
Maybe a complier bug (i'm stuck at 5.114)
Fast=xxxxxx in the #use_i2C(..) does not work. It compiles ok but the device is not working on the correct freq.
If I comment out the I2CBaud=2 and FME=1
#use i2c(stream=MCP9808_Stream, Master, I2C1, CLOCK_SOURCE=HFINTOSC, FAST) compiles ok but F-SCL=~800Khz...
#use i2c(stream=MCP9808_Stream, Master, I2C1, CLOCK_SOURCE=HFINTOSC, FAST=100000) same as above
In both cases the read back of the I2Cbaud=0 and FME=0. Thus the clock source (4Mhz) only gets div'd by FME=0 (=div 5). Which makes ~800khz
And the fast=xxxxxx hz parameter doesn't do anything. I know the exact frequency can't be made. But then I would expect the closest.
The parameter CLOCK_DIVISOR does work. But that only sets the bit FME.
I2C_Speed() function raises a compiler error.
So looks like using the I2C1Baud register is the only thing that works for now.
~~~
What you describe is a resistor pull-up behaviour, I would say. As the voltage across the resistor declines the current does also.
A good current source would keep the current the same independand of Vpin. The slope of the signals would then be more a straight line.
But they are not. Maybe caused by the slew-rate control?
~~~
Indeed I can leave the SDA SCL pins out. I2C1 is enough.
~~~
The PU bits in the RC3I2C/RC4I2C doesn't need the weak to be enabled, for what I see on the device.
I tested it by setting the bits explicitly low, readback and verify they are/stay low
I also watched the slope of the SCL impove at higher currents and still keeping the weak pull-ups disabled _________________ Regards, Edwin. PCWHD v5.114 |
|
|
Woody
Joined: 11 Sep 2003 Posts: 83 Location: Warmenhuizen - NL
|
|
Posted: Tue Sep 10, 2024 5:07 am |
|
|
Hi,
I don't want to start a new thread as this one exactly describes the problem I run into.
My question: did anyone ever find out why #use I2C() does not work for setting the I2C clock speed?
I keep struggling with it and can only come to the same conclusion: best to do the I2C settings manually as #use I2C() only gets the clock source right.
Setting FAST=nnnnn and CLOCK_DIVISOR=x don't do what I expect them to (at least, in my compiler, 5.115 and with my chip, 18F14Q41)
Doing this 'by hand' works better but even then I find that the chip (18F14Q41) does not follow its datasheet.
When I set hfintosc (system clock is 16MHz internal) as the source in the #use i2c(), set I2C1BAUD=31 and FME to 1 I get a nice 125kHz i2c clock. As advertised in the datasheet, page 647. But if I then select FME=0 I expect a 100kHz clock (DS page 646) but get 83.5kHz.
I do not see any i2c clock related issues in the errata, so why this happens is unclear to me. I really hate it when I don't understand things like this
I'll renew my compiler today to see if that makes any difference to the use i2c() settings; there was a change that might influence this (although for S/W i2c):
-> 5.118 Updated S/W #use i2c() so that slower baud rates can be used from a fast clock speed on PCM/PCH. |
|
|
Woody
Joined: 11 Sep 2003 Posts: 83 Location: Warmenhuizen - NL
|
|
Posted: Wed Sep 11, 2024 5:15 am |
|
|
Man, this is complicated.
I renewed my compiler. This seems to partly solve my problem. I now can use the FAST=nnnnnn parameter in #use i2c() and that gives me the desired baud rate.
But I find I have to take into account how the compiler decides to make the baud rate, with FME=0 or FME=1. Because this FME bit does also influence the SCL timing, which has implications for the peripheral that is used. For instance:
In my case, where I have a 16MHz FOSC, if I use
Code: | #use i2c(Master,I2C1,fast=400000, clock_source=FOSC/4) |
I get an i2c baud rate of 400kHz. The compiler makes this by setting the I2C1BAUD to 1 and FME to 0, and 4Mhz/2/5 = 400kHz. But this completely upsets my peripheral.
If I now use
Code: | #use i2c(Master,I2C1,fast=400000, clock_source=FOSC) |
I also get a 400kHz baud rate. Only this time the compiler makes it by setting I2C1BAUD to 9 and FME to 1 and 16Mhz / 10 / 4 = 400kHz, but now my peripheral works OK.
I expected that the clock_divisor parameter would always set the FME bit, but that is not the case. An example:
Code: | #use i2c(Master,I2C1,fast=100000, clock_divisor=5)
#use i2c(Master,I2C1,fast=100000, clock_divisor=4) |
In both cases I get a 100kHz baud rate. And in both cases the compiler makes that by setting I2C1BAUD to 9 and FME to 1, while I would expect that in the first line where clock_divisor=5 I2C1BAUD would be set to 7 and FME to 0. Although on paper these would also give a 100kHz baudrate it turns out that these values give me an 83.5kHz clock. I do not have a clue as to why but this is the same problem I started out with yesterday.
I still do not understand all ins and outs and start to go round in circles. Parameters in the #use i2c() seem to have unexpected effects on each other which makes me think it is indeed more safe to set all these 'by hand'
But I realize that is no news to people here |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19495
|
|
Posted: Wed Sep 11, 2024 7:01 am |
|
|
I would raise this with CCS.
The problem here is that the #use I2C command was written originally for
the MSSP peripheral. With this there were none of the extra settings such
as FME. Now I'm assuming that you are using the internal I2C pull-ups?.
If so, FME has the extra function, of changing the current this peripheral
produces. Hence why the bus works when the FME bit gets set, but not
when it isn't. The SCL line is also held high for one clock cycle longer
when FME is 0.
I must admit I agree with you that selecting the clock_divisor as 4 ought
really to enable FME, and to 5, disable this. Seems that whoever wrote
this did not quite understand what this should be doing. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9221 Location: Greensville,Ontario
|
|
Posted: Wed Sep 11, 2024 7:29 am |
|
|
OK, I'm a 'dinosaur' and prefer to use REAL resistors as pullups, even when I have to hand solder them onto the PCB cause, well as a 'dinosaur' I tend to um, ah, er, forget things.....
I don't trust 'computers'..... |
|
|
Woody
Joined: 11 Sep 2003 Posts: 83 Location: Warmenhuizen - NL
|
|
Posted: Wed Sep 11, 2024 10:52 am |
|
|
Ttelmah wrote: | Now I'm assuming that you are using the internal I2C pull-ups?. If so, FME has the extra function, of changing the current this peripheral
produces. Hence why the bus works when the FME bit gets set, but not when it isn't. The SCL line is also held high for one clock cycle longer
when FME is 0. |
Yes, you assume correctly (as I stupidly forgot these on the proto)
For now I have:
Code: |
#byte RB6I2C=getenv("SFR:RB6I2C")
#byte RB4I2C=getenv("SFR:RB4I2C")
#byte I2C1BAUD = getenv("SFR:I2C1BAUD")
#byte I2C1CLK = getenv("SFR:I2C1CLK")
#bit FME=getenv("BIT:FME")
#use i2c(Master,I2C1) // Enable i2c
RB6I2C = 0x61; // RxyI2C for SDA, (fast mode (400k) slew rate, 10x current of standard pullup, i2c specific input thresholds)
RB4I2C = 0x61; // RxyI2C for SCL, (fast mode (400k) slew rate, 10x current of standard pullup, i2c specific input thresholds)
I2C1CLK = 0x00; // Fosc / 4, (Fosc is 16MHz)
FME=1; // Fast Mode Enable bit = 1, which divides I2C1CLK / 4
I2C1BAUD = 9; // i2c Baudrate = I2C1CLK / 4 / (I2C1BAUD+1) - 4MHz / 4 / 10 = 100kHz |
This gives me the desired 100kHz i2c, with neat ~120ns risetimes on SDA and SCL. I can change the RxyI2C values, where 0x51 gives me ~600ns risetimes and 0x71 ~120ns risetimes, so not different from 0x61.
I have not managed to get the same results with only parameterizing #use_i2c() and the RxyI2C setting (that I definitely need to make up for the missing resistors.
Tomorrow I will go the way of the 'dinosaur' and solder a couple of pull-ups on the board. See where that leads me |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9221 Location: Greensville,Ontario
|
|
Posted: Wed Sep 11, 2024 4:36 pm |
|
|
GREAT but please....be careful soldering !! Don't need to see 4 pages about 'it was working' fine until .....oopsy...soldered both pins together, grr....WHY did I listen to 'dinosaur'...he's supposed to be extinct !!!! |
|
|
Woody
Joined: 11 Sep 2003 Posts: 83 Location: Warmenhuizen - NL
|
|
Posted: Thu Sep 12, 2024 2:29 am |
|
|
I hope you did not lose too much sleep over it
Being close to extinction myself I like a challenge so I heated up the welding torch and got to it. I'm not too miffed about the result:
https://box.postkamer.eu/cloud/index.php/s/wNzB2BynfSHkbye
(Sorry, no idea if and how this [img][/img] is supposed to work)
I switched off all internal pullups (set RxyI2C to 0x01, I2C-specific input thresholds).
Now risetimes for both SDA and SCL are ~130ns, and fall times are ~15ns. These used to be more 'in line' with each other. This might be a ifference between using the internal current source and external resistors.
Anyway, the resistors are in and functioning. Note to self: do not forget them. Then again, I'll probably mislay that note.... |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9221 Location: Greensville,Ontario
|
|
Posted: Thu Sep 12, 2024 5:04 am |
|
|
re: I'll probably mislay that note....
yes !!! reminds me that I need to make a 'hidden hidden driveway sign ahead'.
sigh, I'm the hidden driveway on a corner and city trees are blocking the big warning sign yellow sign.
Naturally when you said you were adding resistors, I assumed REAL resistors ! You know ,multicouloured cylinders with wires on both ends NOT some silly, itty, bitty, blob with '2431' on it !!
sigh, I feel OLD now......
BTW does 2431 mean red-yellow-orange-brown ?? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19495
|
|
Posted: Thu Sep 12, 2024 5:19 am |
|
|
The really small ones don't even have printing on them. Sizes like 0201
and 0402. Hand soldering these is something that should be used as the
basis for a silly TV program. 'Resistor wars', or something. Only way
really is hot air and solder paste with a mini finger holder and a microscope.
Classic "don't try this at home" exercise... |
|
|
Woody
Joined: 11 Sep 2003 Posts: 83 Location: Warmenhuizen - NL
|
|
Posted: Thu Sep 12, 2024 5:37 am |
|
|
temtronic wrote: |
BTW does 2431 mean red-yellow-orange-brown ?? |
What ARE you on about???
I believe the 5-band color coding for this 1% resistor would be red-yellow-orange-brown-brown. Using 5-band 1% thru-hole resistors is some time ago.
TBH I started with a couple of real, 2k7, TH resistors but they proved to be a bit too big for the SSOP package the PIC lives in. On the other end of the i2c bus lives an MXC6655XA motion sensor: 12 pads on the bottom of a 2x2mm package.
The SMD's I used were left over from another project and made for a nice i2c pullup @ 3v3. |
|
|
|
|
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
|