 |
 |
| View previous topic :: View next topic |
| Author |
Message |
devau
Joined: 30 Jan 2007 Posts: 9 Location: Switzerland
|
| I2C on PIC18F27Q43 |
Posted: Wed Sep 16, 2026 2:03 am |
|
|
Hello
I could not manage it to get I2C working with hardware-based configuration on a PIC18F27Q43. The chip freezes at the call of i2c_transfer_out. I tried then with the help of AI, and this is what came out:
"The outdated code generation of the CCS C compiler for this specific processor generation bears the primary responsibility.
The hardware hurdle (the chip): With the PIC18F-Q series, Microchip has completely scrapped the decades-old MSSP module. The new, dedicated I2C module features its own highly complex state machine with automatic bus conflict detection. If this module does not see the exact correct sequence of registers upon activation, it immediately goes into a lockout state (bus collision or bus-free error) and blocks all communication.
The software hurdle (the CCS compiler): The CCS `#use i2c(force_hw, ...)` directive was written for older PICs. With the Q-series, the compiler attempts to access legacy control registers (such as SSP1CON1, etc.) that the PIC18F27Q43 no longer possesses. At the same time, the compiler fails to initialize the entirely new, mandatory registers of the Q-series (such as I2C1CON0, I2C1CLK, or the bus timeout register I2C1BTO).
The result: The background-generated function `i2c_transfer_out` waits indefinitely in a `while` loop for a hardware flag that is never set due to a lack of correct initialization. The processor freezes."
Now without "force_hw" the I2C communication works. I’d be surprised if anyone managed to get I2C working on this PIC series using "force_hw". |
|
 |
Ttelmah
Joined: 11 Mar 2010 Posts: 20136
|
|
Posted: Wed Sep 16, 2026 2:45 am |
|
|
The AI's answer is wrong.
Classic example of an AI not having any idea of what it is 'talking' about.
What it posted applied for a few months when these chips launched.
Provided you are using a modern compiler, CCS now supports these
modules properly, but the modules themselves have significant problems
if you have I2C issues.
First thing is you must specify the speed properly. The modules support
rates that require active termination.
Second thing is you need to be very careful about voltages. What voltage
are you running the PIC, and what voltage is the device?. The PIC I2C
modules in general _require_ proper I2C levels. A lot of the modules
in other chips are more flexible about this, and people think they can
use combinations that won't work.
Then there is PPS. You must assign the pins you want to use with this
before your #USE statement.
Then syntax. On these chips, you cannot use the old I2C syntax. These
require:
#USE_I2C
i2c_transfer
i2c_transfer_in
i2C_transfer_out
Not the older syntax used to control the MSSP.
Look at the example ex_i2c_master_hw_k42.h
Don't post AI C**p, before asking. They are wrong more often than they
are right, especially when things become a bit technical. The way we are
being propelled towards 'believing' them is the really worrying thing. |
|
 |
devau
Joined: 30 Jan 2007 Posts: 9 Location: Switzerland
|
|
Posted: Wed Sep 16, 2026 3:23 am |
|
|
Hello
No problem with voltages. All involved hardware run on 5 Volts.
SDA and SCL pins with 4k7 pull-up resistors attached.
And this is what I used:
#pin_select SDA1=PIN_B2
#pin_select SCL1=PIN_B1
#pin_select SDA1IN=PIN_B2
#pin_select SDA1OUT=PIN_B2
#pin_select SCL1IN=PIN_B1
#pin_select SCL1OUT=PIN_B1
#use i2c(Master, I2C1,fast,sda=PIN_B2,scl=PIN_B1,force_hw,STREAM=LCD)
and this in the code: i2c_transfer_out(LCD, LCD_ADDRESS, buffer, 1); |
|
 |
Ttelmah
Joined: 11 Mar 2010 Posts: 20136
|
|
Posted: Wed Sep 16, 2026 4:43 am |
|
|
4K7 is an 'OK' pull up for a slow I2C.
The I2C on the Q chips, supports data rates that this is not low enough
for. You need dynamic pull ups for the maximum rates this supports.
At 400K, you need to be using pull-ups like 1K2.
At 1MHz, proper active pull-ups.
The keyword 'fast' says to select fast rates.
So your answer immediately says you will have problems.
fast=100K might work.
fast=400K if the lines are very short may be OK, but really need lower
pull-ups than 4K7.
fast=1MHz, you need dynamic pull-ups. |
|
 |
Ttelmah
Joined: 11 Mar 2010 Posts: 20136
|
|
Posted: Wed Sep 16, 2026 5:50 am |
|
|
Also, obvious question, what is the address. Have you translated between TI
I2C addresses and PIC I2C addresses?. If not won't work. |
|
 |
Woody
Joined: 11 Sep 2003 Posts: 91 Location: Warmenhuizen - NL
|
|
Posted: Wed Sep 16, 2026 8:25 am |
|
|
| Ttelmah wrote: |
Provided you are using a modern compiler, CCS now supports these
modules properly, but the modules themselves have significant problems
if you have I2C issues. |
Do you happen to know if ex_i2c_master_hw_k42.h changed between 5.121 and the later compilers? I played with this in 5.121 and could not get it to function properly. Doing it by hand I got it working, but you make me wonder if this could (should) have been possible with the CCS functions as well. Anyway, this morning I updated my maintenance so if the problem is in my compiler that should be fixed later today :-)
And indeed there are a number of I2C problems in the errata sheet of the 18F14Q41 I happen to be using. Microchip just seem to be unable to get that right in one or two silicon versions. |
|
 |
Ttelmah
Joined: 11 Mar 2010 Posts: 20136
|
|
Posted: Thu Sep 17, 2026 12:45 am |
|
|
I'll have to do a compile and compare, but I doubt it has changed. However
the speed is a critical problem. The keyword 'fast' tells the compiler to set
the peripheral up with the timings for the fast protocol, but by default the
compiler always programs the peripheral to 'as fast as possible'. The 4K7
pull-ups, are probably OK for a device at 400KHz, if the cables are short, and
is great for stuff at 100K, but are not even remotely adequate once you
get up to 1MHz, or over. The I2C peripheral on these chips supports fast mode
plus timings, and these require very good pull-ups. The compiler will be
selecting these rates with the line you posted. At these speeds technically
active pull-ups are required. Try just specifying the rate with FAST=400K. |
|
 |
Woody
Joined: 11 Sep 2003 Posts: 91 Location: Warmenhuizen - NL
|
|
Posted: Thu Sep 17, 2026 1:35 am |
|
|
I see I made a mistake in file naming, I meant ex_i2c_slave_hw_k42.h but typed master instead. Anyway, I installed the latest compiler (5.125) and no, ex_i2c_slave_hw_k42.h did not change. I'll see if i can get the new compiler to work with my 18F14K41.
The remainder of your answer was probably meant for the TS, which is what happens when you break in in someone else's thread like I did. For which I apologize. |
|
 |
Ttelmah
Joined: 11 Mar 2010 Posts: 20136
|
|
Posted: Thu Sep 17, 2026 6:26 am |
|
|
OK. Lets step through problems I have seen on these peripherals:
First, on some chips the transfer count needs to include the actual address
byte, and on some others it doesn't. On the first chips it always needed this
extra byte, and they seem to get this differently on different chips.....
Second, on most of the chips if the pin is selected for I2C, the internal
slew rate limitation gets turned off and replaced with the I2C slew control.
However I have seen at least one chip where the internal slew rate limit
remained in force, so this needs to be disabled. The setting of the I2C
slew_rate seems also to be missed on some of the chips.
A couple of the really new chips have got current limit controls as well
on the pin (I think I've only seen this on DsPIC's though). Again needs
to be turned to high current for the I2C.
Then the obvious huge caveat already mentioned if copying I2C_transfer
code from other chips of needing to double the I2C address used.
When this first appeared, the drivers weer all problematical, but after
a couple of compiler versions, the internal code changed to match what
is in the MicroChip examples, and then started to work.
On a few chips there are errata for some parts of this peripheral. I think
you mentioned that Woody?.
On some chips you have to be careful, with the I2C behaving differently
on some pins (again the peripheral is meant to override this but doesn't
seem to always do so...). It almost seemed as if the TTL/SCHMITT pin
behaviour was overriding the I2C selection.
Then we have the speed one. The compiler always seems to default to
selecting 'as fast as possible', unless explicitly told the clock to use.
Once you have had a chip try to clock the I2C at over 3MHz, you realise
to make sure you specify the speed!....
Also the peripheral itself seems to be more fussy on the actual signal
rise-time, than the old MSSP. I've had one system where a working chip
with MSSP was replaced with one using the I2C peripheral, and despite
all the settings for speed etc., being the same, it would not work till I
reduced the pull-ups used.
The PIC18 chips with this are the K83, K42, Q41, 42 & 83 families. I've used
about five of them now, with probably twenty I2C devices, and in all cases
eventually managed to get it to work. However I have seen slightly
different 'oddities' in the settings on all of them, depending both on
the chip involved, and the target device. On modern compilers, the
code in the core of the handler is identical to that in MicroChip's own
example for this. |
|
 |
devau
Joined: 30 Jan 2007 Posts: 9 Location: Switzerland
|
|
Posted: Thu Sep 17, 2026 9:09 am |
|
|
"Try just specifying the rate with FAST=400K."
It doesn't work even with "slow."
The connection is only 10 cm (4 inches) long! |
|
 |
Ttelmah
Joined: 11 Mar 2010 Posts: 20136
|
|
Posted: Fri Sep 18, 2026 1:52 am |
|
|
Device address????.
What is the device????.
Give an example of the transaction you are using. |
|
 |
Woody
Joined: 11 Sep 2003 Posts: 91 Location: Warmenhuizen - NL
|
|
Posted: Fri Sep 18, 2026 2:23 am |
|
|
Some time ago I used a Sensirion SHT31 temperature/relative humidity sensor on a PIC18F55Q43, which I suspect has the same I2C module as the PIC18F27Q43. With the SHT31 as a client device you start an acquisition by setting some parameters then wait 15 ms after which you read the results. The PIC in this project is clocked by an external oscillator @18432000Hz and the compiler version used back then was 5.105
Below the I2C settings I used. Mind(1): you cannot compile this 1:1, it just is a grab of parts of the code that made it work for me. Mind(2): I am by no means an I2C expert; it baffles me with every new chip and/or project and hence I might have made silly mistakes that Ttelmah might shake his head about
| Code: | //// I2C pin selects
#pin_select SCL1OUT = PIN_C3
#pin_select SDA1OUT = PIN_C4
#pin_select SDA1IN = PIN_C4
// Registers for slew rate, pullups and input threshold selection on PIN_C3/PIN_C4 (SCL/SDA), set in init(). See DS page 330
#byte SDA_CONTROL=getenv("SFR:RC4I2C")
#byte SCL_CONTROL=getenv("SFR:RC3I2C")
// I2C set to master mode, I2C module 1, clock mfintosc = 500Khz.
#use i2c(Master,I2C1,clock_source=mfint)
#define SHT31_I2C_ADDRESS 0x88 // I2C address for the SHT3x-DIS chip is 0x44; CCS uses 8 bit addresses, not 7 bit.... |
Some arrays to hold Sensirion commands and data:
| Code: | //
// Sensirion SHT3x-DIS
//
// The new i2c_transfer requires arrays to write and read data.
int8 sensirion_cmd[2] = { 0x24, 0x00 }; // Single shot data acquisition mode, high repeatability, clock stretching disabled
int8 temp_rh[6]; // 0,1 = temperature, 2=crc, 3,4 = rh, 5=crc |
The code that sets slew rate and pullup
| Code: |
// Initialize the slew rate and pullup and threshold selection on PIN_C3/PIN_C4 (SCL/SDA), see DS page 330
// Slew rate = fast plus mode, no pullups (external resistors are used) and i2c-specific input thresholds
SDA_CONTROL = 0xc1;
SCL_CONTROL = 0xc1; |
The code that tells the sensor to start a measurement:
| Code: | // Issue the Single shot data acquisition command. This transfer of 3 bytes bytes takes 300us (timed with scope)
// The measurement itself can take up to 15 ms. We won't wait for that.
i2c_transfer_out(SHT31_I2C_ADDRESS, sensirion_cmd, sizeof(sensirion_cmd)); |
The Sensirion takes about 15ms to do an acquisition, I did not wait for that but triggered it with an ISR driven timer, but this is the code that gets the data out.
| Code: | // Read trigger is set, start a result transfer. This transfer of 7 bytes takes 660us (timed with scope)
i2c_transfer_in(SHT31_I2C_ADDRESS, temp_rh, sizeof(temp_rh)); |
I hope this is of some help to you. |
|
 |
Ttelmah
Joined: 11 Mar 2010 Posts: 20136
|
|
Posted: Fri Sep 18, 2026 12:46 pm |
|
|
Sensible example.
Your 'key thing' was needing to allow the time between triggering and
reading.
I'm worried because his stream name is 'LCD', and most LCD devices
will use TI style addresses. Most will also have delays needed as your
sensor did. |
|
 |
devau
Joined: 30 Jan 2007 Posts: 9 Location: Switzerland
|
|
Posted: Mon Sep 21, 2026 4:22 am |
|
|
| used LCD_ADDRESS for the PCF8574 is 0x4E. This is the default address used mostly by LCD-modules coming from the Chinese market. |
|
 |
Ttelmah
Joined: 11 Mar 2010 Posts: 20136
|
|
Posted: Mon Sep 21, 2026 5:16 am |
|
|
As I thought.
This is _wrong_ for a PIC. On the PIC's, the address has to be shifted left
one bit. This is because on the PIC, the low bit of the I2C address register
is reserved for the R/W bit. So for a PIC,, your I2C address needs to
be 0x9C.
The 0x4E, is the Texas format address.
Texas address 0xxxx xxxx for the 8 bits
PIC address xxxxx xxxR for the 8 bits
That it has the bottom bit set immediately says this is a TI format address.
This is a classic error when moving code onto the PIC. |
|
 |
|
|
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
|