|
|
View previous topic :: View next topic |
Author |
Message |
Backfire
Joined: 12 Oct 2020 Posts: 46
|
PIC Migration Woes (I2C & PPS) |
Posted: Fri Sep 24, 2021 8:04 am |
|
|
*sigh* I love and hate these little microchips sometimes.
I have read the sticky in the forum, and tried all and any combinations of #use i2c and the #pin_select directives, but my previously functional code now seems to hang on the simplest of i2c bus scans. I'm in a situation where I have to migrate some code from a 18F25K20, to a 18F27Q84. This therefore requires use of the dreaded PPS module.
Most recent config and scanning function below;
Code: |
#pin_select SCL1OUT = PIN_C3
#pin_select SCL1IN = PIN_C3
#pin_select SDA1OUT = PIN_C4
#pin_select SDA1IN = PIN_C4
// Have also tried;
#pin_select SCL1 = PIN_C3
#pin_select SDA1 = PIN_C4
#use i2c(master, slow, i2c1)
// Have also tried;
#use i2c(master, slow, scl=PIN_C3, sda=PIN_C4)
// Have also tried #defining the pins, then using the define'd term for both #pin_select and the #use statements, also seen somewhere on this forum...
int8 I2CCheckDevicePresent(int8 Address)
{
int8 Status;
// Have also tried calling this with paramater #3 as 1...
Status = i2c_transfer(Address, NULL, 0);
if(Status == 0)
return(TRUE);
else
return(FALSE);
}
|
I'd be grateful for any pointers to what my configuration problems are... It is *so* frustrating, as this code has worked flawlessly on the other processor, but the migration has to happen, so I suppose a solution must be found..! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Fri Sep 24, 2021 9:35 am |
|
|
Your last setup:
#use i2c(master, slow, scl=PIN_C3, sda=PIN_C4)
Should have just used software I2C.
With this you could use I2C_write and I2C_read, rather than I2C_transfer.
Your problem is not PPS, but trying to use I2C_transfer.
Now, I2C_transfer is involved, because your new chip has the I2C
module, rather than MSSP. For this I2C_transfer has to be used, but it is a
horribly complex module to use.
So first thing, try using your last setup, add FORCE_SW to make sure
software is used, and use the normal I2C_start and I2C_write commands.
See then what happens.
Problem is that the hardware I2C module will hang if the timeout is
not setup, and the bus is not idling high when a transfer is started.
I suspect this is what is happening to you.
Using the software commands gives the chance to diagnose what is
actually happening. |
|
|
Backfire
Joined: 12 Oct 2020 Posts: 46
|
|
Posted: Mon Sep 27, 2021 3:42 am |
|
|
I'm no further on this sadly, tried all logical combinations, but just cannot get reliable operation. Part of the trouble is the new PIC I'm having to use; the 18F27Q84.
The I2C module is *so* complex inside this device, I know I'm likely just mis-configuring some combination of settings, as I have had the bus work intermittently.
As previously found elsewhere on the forum, I have even been adding the following to my header file;
Code: |
#byte ODCCON=getenv("SFR:ODCONC")
#byte RC4I2C=getenv("SFR:RC4I2C")
#byte RC3I2C=getenv("SFR:RC3I2C")
#define I2C400K 0x61
|
And then running;
Code: |
RC4I2C=I2C400K;
RC3I2C=I2C400K;
bit_set(ODCCON,3);
bit_set(ODCCON,4); //these two explicitly set the pins as OD drive
|
before using the port... And all to no avail. I have also tried setting the I2C pull-ups to be the gpio weak pull-ups, and then disabling them, as I have external bus pull-ups, actually implemented with potentiometers, so they can be any value between 10K and 0...
I'll follow this post with a full code listing so hopefully someone can find my issue... So annoying that this worked flawlessly using the PIC with the MSSP module inside...! |
|
|
Backfire
Joined: 12 Oct 2020 Posts: 46
|
|
Posted: Mon Sep 27, 2021 3:44 am |
|
|
main.h
Code: |
#include <18F27Q84.h>
#device ADC=12
#FUSES NOWDT //No Watch Dog Timer
#FUSES RSTOSC_EXT //On Power-up clock running from External Oscillator
#FUSES PRLOCK1WAY //PRLOCKED bit can be cleared and set only once
#FUSES CKS //Clock Switching Enabled
#FUSES NOJTAG //JTAG DISabled
#FUSES FCMEN //Fail-safe clock monitor enabled
#FUSES PFCMEN //Primary XTAL Fail-safe clock monitor enabled
#FUSES SFCMEN //Secondary XTAL Fail-safe clock monitor enabled
#FUSES MCLR //Master Clear pin enabled
#FUSES NOPUT //No Power Up Timer
#FUSES MVECEN //Vector tables used for interrupts
#FUSES IVT1WAY //IVTLOCKED bit can be cleared and set only once
#FUSES NOBROWNOUT //No brownout reset
#FUSES BORV19 //Brownout reset at 1.9V
#FUSES ZCDDIS //Zero-cross detect circuit is disabled at POR
#FUSES STVREN //Stack full/underflow will cause reset
#FUSES NOLVP //No low Voltage Programming
#FUSES BBSIZ512 //Boot block size 512 bytes
#FUSES CRCBOOTPINC5 //CRC-on-boot output pin is C5
#FUSES CRCBOOTPIN_DRIVEN //CRC-on-bo0t output pin drives high-going and low-going signals (source and sink current)
#FUSES CRCBBSCANERR_STOP //Device will halt execution if CRC error ob boot block
#use delay(internal=16MHz)
//#pin_select SCL1OUT = PIN_C3
//#pin_select SCL1IN = PIN_C3
//#pin_select SDA1OUT = PIN_C4
//#pin_select SDA1IN = PIN_C4
#byte ODCCON=getenv("SFR:ODCONC")
#byte RC4I2C=getenv("SFR:RC4I2C")
#byte RC3I2C=getenv("SFR:RC3I2C")
#define I2C400K 0x61
#pin_select SCL1 = PIN_C3
#pin_select SDA1 = PIN_C4
#use i2c(Master, Slow=100000, force_sw, scl=PIN_C3, sda=PIN_C4, restart_wdt)
#pin_select U1TX = PIN_C6
#pin_select U1RX = PIN_C7
#use rs232(stream=SERIAL, baud=9600, bits=8, parity=N, stop=1, uart1, errors, disable_ints)
// Pin re-defines and useful mappings
#define LINK_LED PIN_A6
#define STAT_LED PIN_A7
#define OPEN 0
#define CLOSED 1
#define I2C_START_SCAN_ADDR 0x10
#define I2C_STOP_SCAN_ADDR 0xF0
#define SETTINGS_S1 PIN_B3
#define SETTINGS_S2 PIN_B2
#define SETTINGS_S3 PIN_B1
#define SETTINGS_S4 PIN_B0
|
main.c
Code: |
#include <main.h>
#include <stdlib.h>
int8 I2CCheckDevicePresent(int8 Address);
void main()
{
int8 Status = 0;
setup_adc_ports(NO_ANALOGS);
RC4I2C=I2C400K;
RC3I2C=I2C400K;
bit_set(ODCCON,3);
bit_set(ODCCON,4); //these two explicitly set the pins as OD drive
set_open_drain_c(0b00001100);
while(TRUE)
{
fprintf(SERIAL, "In Main\r");
output_high(LINK_LED);
delay_ms(500);
output_low(LINK_LED);
delay_ms(500);
Status = I2CCheckDevicePresent(0x20);
fprintf(SERIAL, "Status: %u\r", Status);
}
}
// If we find a I2C slave device at the supplied address, it should respond to
//this function with an "ACK"...
int8 I2CCheckDevicePresent(int8 Address)
{
int8 Status;
//i2c_start(I2CBus);
//Status = i2c_write(Address);
//i2c_stop(I2CBus);
Status = i2c_transfer(Address, NULL, 0);
if(Status == 0)
return(TRUE);
else
return(FALSE);
}
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Mon Sep 27, 2021 8:11 am |
|
|
Start by testing with software. Currently you are connecting the hardware
I2C, and trying to use software. Also are you using a bootloader?. If not
you don't want to be enabling/using the boot block instructions.
You are also not using an external crystal, so don't want FCMEN:
main.h
Code: |
#include <18F27Q84.h>
#device ADC=12
#FUSES NOWDT //No Watch Dog Timer
#FUSES RSTOSC_EXT //On Power-up clock running from External Oscillator
#FUSES PRLOCK1WAY //PRLOCKED bit can be cleared and set only once
#FUSES CKS //Clock Switching Enabled
#FUSES NOJTAG //JTAG DISabled
#FUSES NOFCMEN //Fail-safe clock monitor disabled
#FUSES SFCMEN //Secondary XTAL Fail-safe clock monitor enabled
#FUSES MCLR //Master Clear pin enabled
#FUSES PUT //Power Up Timer
#FUSES MVECEN //Vector tables used for interrupts
#FUSES IVT1WAY //IVTLOCKED bit can be cleared and set only once
#FUSES NOBROWNOUT //No brownout reset
#FUSES BORV19 //Brownout reset at 1.9V
#FUSES ZCDDIS //Zero-cross detect circuit is disabled at POR
#FUSES STVREN //Stack full/underflow will cause reset
#FUSES NOLVP //No low Voltage Programming
#FUSES NOBOOTBLOCK
#use delay(internal=16MHz)
#use i2c(Master, Slow=100000, force_sw, scl=PIN_C3, sda=PIN_C4)
#pin_select U1TX = PIN_C6
#pin_select U1RX = PIN_C7
#use rs232(stream=SERIAL, baud=9600, bits=8, parity=N, stop=1, uart1, errors, disable_ints)
// Pin re-defines and useful mappings
#define LINK_LED PIN_A6
#define STAT_LED PIN_A7
#define OPEN 0
#define CLOSED 1
#define I2C_START_SCAN_ADDR 0x10
#define I2C_STOP_SCAN_ADDR 0xF0
#define SETTINGS_S1 PIN_B3
#define SETTINGS_S2 PIN_B2
#define SETTINGS_S3 PIN_B1
#define SETTINGS_S4 PIN_B0
|
main.c
Code: |
#include <main.h>
#include <stdlib.h>
int8 I2CCheckDevicePresent(int8 Address);
void main()
{
int8 Status = 0;
setup_adc_ports(NO_ANALOGS);
//open drain settings and pull up control are not needed/wanted
//for software I2C.
while(TRUE)
{
fprintf(SERIAL, "In Main\r");
output_high(LINK_LED);
delay_ms(500);
output_low(LINK_LED);
delay_ms(500);
Status = I2CCheckDevicePresent(0x20);
fprintf(SERIAL, "Status: %u\r", Status);
}
}
// If we find a I2C slave device at the supplied address, it should respond to
//this function with an "ACK"...
int8 I2CCheckDevicePresent(int8 Address)
{
int8 Status;
i2c_start();
status = i2c_write(address); // Status = 0 if got an ACK
i2c_stop();
if(status == 0)
return(TRUE);
else
return(FALSE);
}
|
As I said before, test with basic software I2C first. If this hangs, test
'where'. Send a character to the serial before sending the start, then
another before the address, and another before the stop, then you can
see which _part_ of the I2C transaction is failing.
You have kept the PPS setup, and parts of the peripheral configuration.
Don't. Run absolutely 'basic' software I2C.
Having the peripheral connected to the pins will almost certainly cause
problems with the software, so start with it all disabled. |
|
|
|
|
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
|