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 CCS Technical Support

18F16Q41 HW I2C trouble

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
bdeb



Joined: 05 Nov 2010
Posts: 42
Location: Sweden

View user's profile Send private message Visit poster's website

18F16Q41 HW I2C trouble
PostPosted: Wed Mar 16, 2022 10:39 am     Reply with quote

uP=PIC18F16Q41 (DeviceID=7560 rev=A005)
CCS=5.107
IDE=MPLAB X 5.50

Dear code gods, once again I need your help.

Just switched from a 16F18346 to the 18F16Q41 (64k ROM, 4k RAM, 3xUART, but same pin-out)

Timers are timing, LED's are blinking, and UART's are uarting happily.

Only thing not working is hardware I2C master:
#use i2c(MASTER, I2C1, FAST, CLOCK_SOURCE=FOSC, STREAM=I2CM)

#pin_select is done OK + even tried setting I2C pins open drain (+ set as inputs of course)
Tried other pins, but now using "default" B4/B6
Tried explicitly turning (otherwise unused) SPI2 off
Nothing in errata except "Start/StopFlags may be set when I2C enabled"
Tried different speeds, different clock sources, but nothing helps - uP stalls at first i2c_transfer_out() and I2C pins stay high

If commenting out pin_select and using bit-banged I2C on same pins, everything works...

I'm completely new to this uP (and non-MSSP I2C module), so before checking the assembler against registers, I hope to get some hints to what I've missed.. Wink


All the best:

/Björn
Ttelmah



Joined: 11 Mar 2010
Posts: 19503

View user's profile Send private message

PostPosted: Wed Mar 16, 2022 10:58 am     Reply with quote

You need to use i2c_transfer, rather than i2c_start, read/write, stop.
The default is for the compiler to set up this I2C peripheral to support
this rather than allowing the older syntax.
A search here will find some examples of using this.
bdeb



Joined: 05 Nov 2010
Posts: 42
Location: Sweden

View user's profile Send private message Visit poster's website

PostPosted: Wed Mar 16, 2022 11:06 am     Reply with quote

Thank you Ttelmah,

Done that, that's why I stated using "i2c_transfer_out()"


All the best:

/Björn
bdeb



Joined: 05 Nov 2010
Posts: 42
Location: Sweden

View user's profile Send private message Visit poster's website

PostPosted: Wed Mar 16, 2022 11:14 am     Reply with quote

By the way, as a comment older discussions,

I use the exact number of bytes as "wCount" - adding 1 for address byte is not working.

Maybe different in this CCS version, or it comes from reading EEPROM where you actually have to send an internal address.

/Björn
Ttelmah



Joined: 11 Mar 2010
Posts: 19503

View user's profile Send private message

PostPosted: Thu Mar 17, 2022 2:50 am     Reply with quote

No, 'adding 1' was only right at the start with this function.
Basically when initially released, the count number was the number put
into the actual chip's register. If you read the data sheet this is the total
bytes for the transaction. Quite quickly CCS changed this and made it the
number of bytes to send.

Post what you are actually using, and what chip you are trying to talk to.

Classic things would be using a 7bit address, not an 8bit address, but you
say that bit banged works, which suggests this is not the problem.
Are you sure your pull-ups are small enough to support 400KHz?.
Try with a slower rate. If it then works, this is the problem.

I2c_transfer_out, will only hang if you are not getting a NACK from the
device being talked to. Suggests something is wrong with the syntax
you are using.
bdeb



Joined: 05 Nov 2010
Posts: 42
Location: Sweden

View user's profile Send private message Visit poster's website

PostPosted: Thu Mar 17, 2022 3:25 am     Reply with quote

Thank you Ttelmah,

Pull-ups are excellent, since SCL/SDA never goes low if HW I2C.. Smile
Talking to SSD1306 which;
A-Worked with 16F18346 on same PCB
B-Works with software I2C

Code below hangs after setting LED on

Code:
 
void ssd1306Command(uint8_t cmd)
{
   uint8_t data[2];
   data[0] = 0x00;   //Co=0, D/C=0
   data[1] = cmd;

    output_bit(P_LEDRED,1);
    I2C_Transfer_Out(I2CM, _i2caddr, data, 2);
    output_bit(P_LEDRED,0);
}


For good measure also made "empty" project, but scope still shows "flat-lining" pins.

Code:

#include <18F16Q41.h>               //Must come before other includes

#device ADC=10, *=16, WRITE_EEPROM=ASYNC, PASS_STRINGS=IN_RAM

//General
//#fuses DEBUG      //ICD debugger

//Oscillator
#fuses PUT_64MS       //Power Up Timer (PWRT)
#fuses noCLKOUT

//Resets
#fuses noMCLR       //Master Clear pin enabled
#fuses WDT        //Watch Dog Timer set in Setup()
#fuses noBROWNOUT    //Brownout reset
#fuses noLVP
#fuses STVREN       //Reset on stack over/under

//Protection
#fuses noPROTECT     //CP Code read protect
#fuses noPPS1WAY

//Programming
#fuses NOLVP                      //No low Voltage Programming

//New 18xxQ
//#fuses noJTAG       //JTAG DISabled
#fuses noBOOTBLOCK 
#fuses ZCDDIS       //Zero-cross detect circuit is disabled at POR
#fuses noMVECEN     //Vector tables used for interrupts
//#FUSES IVT1WAY                  //IVTLOCKED bit can be cleared and set only once


#use delay(internal = 16MHZ)

//Syntax: #pin_select function=pin
//BIDIRECTIONAL - IN+OUT TO SAME PIN! (I2C can be moved - but will only have ST/TTL-levels on other pins)

#pin_select SCL1IN=PIN_B6
#pin_select SCL1OUT=PIN_B6
#pin_select SDA1IN=PIN_B4
#pin_select SDA1OUT=PIN_B4

#use i2c(MASTER, I2C1, FAST, CLOCK_SOURCE=FOSC, CLOCK_DIVISOR=4, STREAM=I2CM)


void main()
{
    //I2C-pins must be set as inputs!
      set_tris_b(0b11111111);         //4=SDA1, 5=SDA2, 6=SCL1, 7=SCL2   
    //set_open_drain_b(0b01010000);
   
    while(1)
    {
    int8 data[10] = {1,2,3,4,5,6,7,8,9};
    I2C_Transfer_Out(I2CM, 0x78, data, 9);
    delay_ms(1000);
    }
}



Also tried different, speeds, clock sources, ad nauseam.

All the best:

/Björn
Ttelmah



Joined: 11 Mar 2010
Posts: 19503

View user's profile Send private message

PostPosted: Thu Mar 17, 2022 5:35 am     Reply with quote

Key thing is that the software operation will be significantly slower.

Now two things may cause problems when you go faster. The first is the
pull-ups. A pull up that is entirely adequate at 100KHz, will not be low enough
for 400KHz. You are specifying 'FAST', which tells the hardware to select
400KHz. For a 3.3v system, I'd recommend 1.2KR for the pull ups.
The way to test the hardware at slow speed, is not to fiddle with the
clock sources, but select 'SLOW'.

Second is the chip's slew rate limiting. By default this in enabled. This will
limit the speeds that the outputs actually support.
Add the line

set_slow_slew_b(FALSE);

Then I'm not actually sure that this is a legitimate command sequence
for the SSD1306. You seem to be setting the page offsets, before the
chip has actually been started. Now software I2C, and hardware I2C
are very different in what will happen if the slave doesn't send a good
ACK on a byte.
Try sending something legitimate like 0xAF, which is the power on
command.
bdeb



Joined: 05 Nov 2010
Posts: 42
Location: Sweden

View user's profile Send private message Visit poster's website

PostPosted: Thu Mar 17, 2022 9:44 am     Reply with quote

Valid tips!

Tried with "SLOW" and no clock source/divider
Tried without "STREAM"
Tried set_slow_slew_b(FALSE)
Have 1.5k as pull-ups
Tried a correct SSD1306-command
Tried with complete setup that works on SW-I2C
Tried without display (only scope on SCL)

Still pins are stable high without even the shortest spike.
IMHO pins should show 8-9 clocks even if display does not "understand" what is sent?

Before sacrificing live goats to the I2C-gods, I've tried to study the listing.
Many years since last ASM, but found nothing obvious.
Don't know if it's good practice to post it here.
Ttelmah



Joined: 11 Mar 2010
Posts: 19503

View user's profile Send private message

PostPosted: Thu Mar 17, 2022 10:48 am     Reply with quote

OK.
I just tried compiling this dummy project.
Selected 'symbolic' and then looked at the listing.
A huge amount of the generated code is talking to SPI2, rather than the
I2C peripheral!...
It is testing status bits in the wrong peripheral.

Talk to CCS. Ask them for an example using the I2C peripheral, and
point out this oddity.

I suspect there is actually a fault in the implementation on this chip, and
the code is incorrect.
bdeb



Joined: 05 Nov 2010
Posts: 42
Location: Sweden

View user's profile Send private message Visit poster's website

PostPosted: Thu Mar 17, 2022 10:51 am     Reply with quote

Wow!

Felt something missing in disassembled listings after all..
Changed I2C pins to *outputs* and then it suddenly works!

Call me stupid, but I'm sure you normally should set I2C pins as inputs, so the CCS code or MSSP can handle direction?

Thanks for many excellent tips anyway!

/Björn
Ttelmah



Joined: 11 Mar 2010
Posts: 19503

View user's profile Send private message

PostPosted: Thu Mar 17, 2022 11:06 am     Reply with quote

On 90% of PPS chips, you never have to touch TRIS. The peripheral
takes over complete control of the pins.
However this peripheral says:
The SDA and SCL pins must be configured as open-drain outputs.

The CCS code is correctly setting this in the initialisation,
but the TRIS for this is being overwritten by your TRIS line.

000D0: BSF 00A.6
000D2: BSF 00A.4 //These are the open collector settings
000D4: BCF TRISB.TRISB6
000D6: BCF TRISB.TRISB4
At the start of main.

But then your TRIS line sets the TRIS bits.

So you have shot yourself in the foot on this one....
bdeb



Joined: 05 Nov 2010
Posts: 42
Location: Sweden

View user's profile Send private message Visit poster's website

PostPosted: Thu Mar 17, 2022 12:07 pm     Reply with quote

My feet are bullet-ridden..


What is safe and correct way for me to set TRIS for normal I/O pins on same port as any PPS peripheral?
Moving TRIS before any #use statement?

Did you find the info of setting to open drain output in any CCS doc's?


Excellent info - thank's again!
temtronic



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

View user's profile Send private message

PostPosted: Thu Mar 17, 2022 2:01 pm     Reply with quote

generally speaking, you do not need to use 'tris' or 'fast_io' statements.
The compiler's pretty smart and it'll handle the 'details' for you. The default should be 'standard_io().
In over 2 decades of using PICs, I've only needed them for very time sensitive, propriatory equipment and back then 20MHz was a real fast PIC.
dyeatman



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

View user's profile Send private message

PostPosted: Thu Mar 17, 2022 3:18 pm     Reply with quote

I second what temtronic says. I almost always use default Standard_IO.
I have needed TRIS statements only twice. Once in an interrupt driven real
time application communicating with "factory floor" equipment and once
in a Rockwell PLC simulator I wrote for training equipment.

BTW, During development I also rarely specify more than 3-5 fuses (NOLVP,
NOWDT, etc.) since most fuses default to settings you would normally use.

Try to keep things simple and let the compiler do all the work!
_________________
Google and Forum Search are some of your best tools!!!!
bdeb



Joined: 05 Nov 2010
Posts: 42
Location: Sweden

View user's profile Send private message Visit poster's website

PostPosted: Thu Mar 17, 2022 4:04 pm     Reply with quote

Thank you all for good advice - will make use of them.



All the best:

/Björn
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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