View previous topic :: View next topic |
Author |
Message |
Andmo
Joined: 04 May 2015 Posts: 14
|
I2C clock manual to ground by a interrupt |
Posted: Thu Mar 03, 2016 8:17 am |
|
|
Hello
Sorry for my english. I have a problem with the I2C connection.
I read a MLX90615 and when a Interrupt comes, the clock SCL go at last Clock not back to Ground (during the Interrupt). Can i put the clock manual to ground?
Danks |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Thu Mar 03, 2016 9:33 am |
|
|
No.
I2C _idles high_. It sounds as if it is doing what it should. GND, is 'active'. |
|
|
Andmo
Joined: 04 May 2015 Posts: 14
|
|
|
40inD
Joined: 30 Jul 2007 Posts: 112 Location: Moscow, Russia
|
|
Posted: Thu Mar 03, 2016 11:59 pm |
|
|
About Clock: You should use a smaller resistor. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Fri Mar 04, 2016 1:59 am |
|
|
It looks as if you are using _software_ I2C.
As such the clock will remain where it is while the interrupt is serviced, and then 'carry on' when it exits.
You must not interfere with the clock yourself. The chip is in the middle of a transaction, and this continues when the interrupt finishes.
Comments:
1) Yes, the rise times look poor. A smaller pull-up would be suggested.
2) Your interrupt handler is taking a long time. Poor design somewhere.
3) Preferably switch to using the I2C hardware.
If you must use software I2C (you are using a chip without the hardware), and you think that breaking the I2C transaction is causing a problem (it shouldn't, though since the device is SMBUS, it may implement a timeout - wouldn't matter if your interrupt handler was reasonably quick), then disable interrupts around each I2C transaction, so the interrupt only gets serviced between bytes. |
|
|
Andmo
Joined: 04 May 2015 Posts: 14
|
|
Posted: Fri Mar 04, 2016 4:13 am |
|
|
I put this on the main.h
Code: | #use I2C(Master, sda=PIN_C4, scl=PIN_C3,FAST=100000) |
If i put a Force_HW on the line, it doesn't work. Why? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Fri Mar 04, 2016 4:36 am |
|
|
You have not told us what PIC. Does the PIC have I2C hardware on these pins?.
However the other thing is that the chip will actually start generating the clock at 100K with the hardware. Your scope trace only shows it as being about 16K with the software. With your poor rise times (pull up resistor too large, or a lot of bus capacitance), 100K is not gong to work. |
|
|
Andmo
Joined: 04 May 2015 Posts: 14
|
|
Posted: Fri Mar 04, 2016 5:26 am |
|
|
Sorry PIC18F97J94
Yes He has 2 hardware I2C
I have a 2.2K Pull-up but the bus-kabel is about 4meter. Its a MLX90615 Sensor. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Fri Mar 04, 2016 5:57 am |
|
|
2K2, would be reasonable for a 5v bus, but at 3v, is rather high for such a long wire. What is the capacitance specification for the wire?. You need to find this out, to see what data rate can be managed. The maximum supported capacitance for I2C, is 400pF, and you may well be getting quite close to this. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Fri Mar 04, 2016 5:57 am |
|
|
hmm..
Quote: | the bus-kabel is about 4meter. |
!!!!
I2C is NOT designed for 4 meters (14 FEET).
I'd have to pull out my Philips manual on that but I2C was designed for SHORT distance, like on a small PCB.
Maybe the spec has changed in the past 2 decades but I don't think that much.....
Jay |
|
|
Andmo
Joined: 04 May 2015 Posts: 14
|
|
Posted: Fri Mar 04, 2016 7:00 am |
|
|
This with the length of the cable is not the problem. The problem is that i dont no how i do the hardware i2c and handle the interrupt. |
|
|
Andmo
Joined: 04 May 2015 Posts: 14
|
|
Posted: Fri Mar 04, 2016 7:05 am |
|
|
If i do this it works fine.
Code: |
i2c_start(); // Start condition
i2c_write(0xB6); // (Slave Address * 2) For R/W bit low for a write
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
//interrupt funktion
for(i=0;i<=3;i++){
auslesen_ADS8519();
AD_summe+=AD_value;
}
AD_summe=AD_summe>>2; //Mittelwert aus 4 Messungen
AD_toflash=AD_summe; //INT32 in INT16 Variable
//AD_toflash=zj;
zj++;
//if(zj==242) zj=0;
AD_bh = (AD_toflash >> 8); //In 2 Byte aufteilen
AD_bl = (AD_toflash);
while(bit_test(flash_status, 0))
{
FLASH_SELECT();
spi_write(0x05);
flash_status = spi_read(0);
FLASH_DESELECT();
}
FLASH_SELECT();
spi_write(0XAD);
//FLASH_DESELECT();
spi_write(AD_bh);
spi_write(AD_bl);
FLASH_DESELECT();
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
i2c_write(0x27); // Device Temp Register address
i2c_start(); // Restart the bus
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
//interrupt funktion
for(i=0;i<=3;i++){
auslesen_ADS8519();
AD_summe+=AD_value;
}
AD_summe=AD_summe>>2; //Mittelwert aus 4 Messungen
AD_toflash=AD_summe; //INT32 in INT16 Variable
//AD_toflash=zj;
zj++;
//if(zj==242) zj=0;
AD_bh = (AD_toflash >> 8); //In 2 Byte aufteilen
AD_bl = (AD_toflash);
while(bit_test(flash_status, 0))
{
FLASH_SELECT();
spi_write(0x05);
flash_status = spi_read(0);
FLASH_DESELECT();
}
FLASH_SELECT();
spi_write(0XAD);
//FLASH_DESELECT();
spi_write(AD_bh);
spi_write(AD_bl);
FLASH_DESELECT();
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
i2c_write(0xB7); // (Slave Address * 2) - R/W bit high for a read
TempLSB = i2c_read(); // Read LSB of device temp from register
TempMSB = i2c_read(); // Read MSB of device temp from register
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
//interrupt funktion
for(i=0;i<=3;i++){
auslesen_ADS8519();
AD_summe+=AD_value;
}
AD_summe=AD_summe>>2; //Mittelwert aus 4 Messungen
AD_toflash=AD_summe; //INT32 in INT16 Variable
//AD_toflash=zj;
zj++;
//if(zj==242) zj=0;
AD_bh = (AD_toflash >> 8); //In 2 Byte aufteilen
AD_bl = (AD_toflash);
while(bit_test(flash_status, 0))
{
FLASH_SELECT();
spi_write(0x05);
flash_status = spi_read(0);
FLASH_DESELECT();
}
FLASH_SELECT();
spi_write(0XAD);
//FLASH_DESELECT();
spi_write(AD_bh);
spi_write(AD_bl);
FLASH_DESELECT();
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
PEC = i2c_read(); // Read PEC
i2c_stop();
TempRAW = make16(TempMSB,TempLSB); // Make 16bit TempRAW from 2 8bit reads
Temperature = ((TempRAW * 0.02) - 273.15); // Calculate Device Temperature
fprintf(debug,":%f:",Temperature);
delay_ms(20); |
If i do this, and the interrupt comes during the while loop every 200us, it doesn't work.
Code: | while(messung_flag==1)
{
output_high(LEDgruen);
flag_mlxread=1;
i2c_start(); // Start condition
i2c_write(0xB6); // (Slave Address * 2) For R/W bit low for a write
i2c_write(0x27); // Device Temp Register address
i2c_start(); // Restart the bus
i2c_write(0xB7); // (Slave Address * 2) - R/W bit high for a read
TempLSB = i2c_read(); // Read LSB of device temp from register
TempMSB = i2c_read(); // Read MSB of device temp from register
PEC = i2c_read(); // Read PEC
i2c_stop();
flag_mlxread=0;
delay_ms(20);
output_low(LEDgruen);
}
|
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Fri Mar 04, 2016 7:26 am |
|
|
You haven't posted your complete program BUT reading the first chunk of code and the term 'interrupt' I have concerns.
You should NOT do any 'fancy math', writing to SPI memory chips,NO delays,prints, etc. in an ISR. ISRs MUST be short ! Set a couple of flags then reurn to main().
I would code and load PCM P's I2C scanner program from the code library and confirm your PIC functions properly. I'm impressed you say it works at 4 m on 3 V BTW!
You also should use the 'hardware' I2C peripheral if possible. Without seeing your 'setup' code I can't tell what's really going on. A SW I2C is NOT as 'forgiving' or 'robust' as the HW I2C.
I'd also cut a simple 'read the sensor-display the data' program and confirm it runs fine for an hour or two THEN when satisfied, add any 'math' or other routines. Be aware that delay_ms(), any delay fucntion effectively 'stops' the PIC from doing anything else until it times out.
Jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Fri Mar 04, 2016 8:48 am |
|
|
temtronic wrote: | hmm..
Quote: | the bus-kabel is about 4meter. |
!!!!
I2C is NOT designed for 4 meters (14 FEET).
I'd have to pull out my Philips manual on that but I2C was designed for SHORT distance, like on a small PCB.
Maybe the spec has changed in the past 2 decades but I don't think that much.....
Jay |
Yes.
You can make I2C go longer distances, but you have to use higher voltages, and transceivers designed to increase the drive currents.
The length of the cable _is_ part of the problem. The high capacitance is not allowing the I2C bus to run at 100KHz. Software I2C is only giving you a much lower rate that is working. It is because you can't use the hardware I2C, and are running so slow, that you are getting the I2C signal being affected by the interrupt.
Start by lowering the pull-up to 1.2KR.
Then reduce the rate you are asking for, to perhaps 80KHz.
I think (looking at the scope traces), this should just about work. You should then be able to use the hardware I2C.
You have a label saying 'interrupt function', but no sign that this is actually in an interrupt. If it is, then follow Temtronic's advice and think again.
The mantra for interrupts is:
An interrupt should _just_ do the minimum required to handle the hardware event it signals. Nothing else.
Even at 100KHz, your full I2C transaction is going to take 400uSec. |
|
|
|