I2c_Rd or I2c_Wr blocking when interrupted.
I2c_Rd or I2c_Wr blocking when interrupted.
Hi all,
It seems to be, experienced by myself and a number of other people on the forum, that the I2c routines (not the "soft" ones, the "hard" ones) can be blocked (they never "return").
This happens when interrupts are used that are not related at all to I2c (e.g. Timer0 or Usart). In my case it is the I2c_Rd that is blocking after a while with the SCL line on "low". The SCL line is not blocked by the I2c peripheral since removal of the perpheral does not release SCL to high.
Gentlemen of mikroElektronica, can you please give advice? Or is disabling interrupts the only solution for this problem
Thanks in advance.
p.s. I do use mikroPascal, the others are using mikroBasic I think:
http://www.mikroe.com/forum/viewtopic.p ... highlight=
http://www.mikroe.com/forum/viewtopic.p ... highlight=
http://www.mikroe.com/forum/viewtopic.p ... highlight=
It seems to be, experienced by myself and a number of other people on the forum, that the I2c routines (not the "soft" ones, the "hard" ones) can be blocked (they never "return").
This happens when interrupts are used that are not related at all to I2c (e.g. Timer0 or Usart). In my case it is the I2c_Rd that is blocking after a while with the SCL line on "low". The SCL line is not blocked by the I2c peripheral since removal of the perpheral does not release SCL to high.
Gentlemen of mikroElektronica, can you please give advice? Or is disabling interrupts the only solution for this problem
Thanks in advance.
p.s. I do use mikroPascal, the others are using mikroBasic I think:
http://www.mikroe.com/forum/viewtopic.p ... highlight=
http://www.mikroe.com/forum/viewtopic.p ... highlight=
http://www.mikroe.com/forum/viewtopic.p ... highlight=
Kind regards, Dany.
Forget your perfect offering. There is a crack in everything, that's how the light gets in... (L. Cohen)
Remember when we were young? We shone like the sun. (David Gilmour)
Forget your perfect offering. There is a crack in everything, that's how the light gets in... (L. Cohen)
Remember when we were young? We shone like the sun. (David Gilmour)
Hi,
I don't know ....
I have few industrial applications :
1. Ethernet, EEprom 24LC256 (for storing events) + Interrupt with TMR2 at every 1 ms, tested in real world, more than one year, hard conditions (extreme temperatures -20 C to + 60 C) and I don't have any problems !!!
2. Ethernet, EEprom 24LC256, PCF8583, Interrupt with TMR2 at every 1 ms, also tested in real world, no problems.
3. CAN, EEprom 24LC256, PCF8583, one master and 6 slaves, Interrupt with TMR2 at every 1 ms, industrial applications, in functions from March 2007, no problems.
PS. I use MikroPascal 7.0
I don't know ....
I have few industrial applications :
1. Ethernet, EEprom 24LC256 (for storing events) + Interrupt with TMR2 at every 1 ms, tested in real world, more than one year, hard conditions (extreme temperatures -20 C to + 60 C) and I don't have any problems !!!
2. Ethernet, EEprom 24LC256, PCF8583, Interrupt with TMR2 at every 1 ms, also tested in real world, no problems.
3. CAN, EEprom 24LC256, PCF8583, one master and 6 slaves, Interrupt with TMR2 at every 1 ms, industrial applications, in functions from March 2007, no problems.
PS. I use MikroPascal 7.0
Best regards, Florin Andrei Medrea.
http://www.microelemente.ro/
http://www.microelemente.ro/produse-si-servicii/
http://www.microelemente.ro/custom-software/
mail : florin@microelemente.ro
http://www.microelemente.ro/
http://www.microelemente.ro/produse-si-servicii/
http://www.microelemente.ro/custom-software/
mail : florin@microelemente.ro
I'm affraid that Danny is right - appropriately (or rather 'inappropriately' ) timed interrupts may lock some of the I2C library routines. That's caused by an elementary programming error, i.e. clearing a flag after starting a hardware process that ends with setting this flag and then waiting for it. This is better described by:
Errors like the above may be found in both I2C_read and I2C_write routines. I've pointed it out in 2006, but the bug apparently survived (though another one was fixed).
One should also take into account that the library is very basic. Moreover, the PIC18s' I2C state machine is not perfect and in some processors it's not easy to make certain it won't block itself in specific circumstances. Not to mention silicon errors...
You had some luck, Florin, that others are missing . Or your programs' structure is resistant to this bug .
Code: Select all
1. Start process
- here comes an interrupt which takes longer than the process
2. Clear flag
- hardware process did set the flag, but it's been cleared
3. Wait for flag being set
- infinite loop locks here
One should also take into account that the library is very basic. Moreover, the PIC18s' I2C state machine is not perfect and in some processors it's not easy to make certain it won't block itself in specific circumstances. Not to mention silicon errors...
You had some luck, Florin, that others are missing . Or your programs' structure is resistant to this bug .
Maybe this is the case. I am still using the 16F877!yo2lio wrote:or this problem was resolved at PIC18F97J60 family ?!
Kind regards, Dany.
Forget your perfect offering. There is a crack in everything, that's how the light gets in... (L. Cohen)
Remember when we were young? We shone like the sun. (David Gilmour)
Forget your perfect offering. There is a crack in everything, that's how the light gets in... (L. Cohen)
Remember when we were young? We shone like the sun. (David Gilmour)
Thanks very much Janni. Do you think there is a possibility to solve this (by using other -- self made -- I2c_Rd and I2C_Wr routines)? If there are no fundamental problems than I will try to write my own routines. However, if you think this can not be solved due to fundamental problems then I will continue to disable interrupts while reading or writing I2c.janni wrote:Errors like the above may be found in both I2C_read and I2C_write routines. I've pointed it out in 2006, but the bug apparently survived (though another one was fixed).Code: Select all
1. Start process - here comes an interrupt which takes longer than the process 2. Clear flag - hardware process did set the flag, but it's been cleared 3. Wait for flag being set - infinite loop locks here
Kind regards, Dany.
Forget your perfect offering. There is a crack in everything, that's how the light gets in... (L. Cohen)
Remember when we were young? We shone like the sun. (David Gilmour)
Forget your perfect offering. There is a crack in everything, that's how the light gets in... (L. Cohen)
Remember when we were young? We shone like the sun. (David Gilmour)
Hi, looking at the above investigation results of Janni, I did some experiments.janni wrote:Code: Select all
1. Start process - here comes an interrupt which takes longer than the process 2. Clear flag - hardware process did set the flag, but it's been cleared 3. Wait for flag being set - infinite loop locks here
It seems (as far as I can test anyway) that this code does not suffer from the "interrupt" problem:
Code: Select all
function New_I2C_Rd(ack : byte) : byte;
begin
SSPCON2.RCEN := 1; // enable reception
repeat until SSPSTAT.BF = 1; // wait for full buffer
Result := SSPBUF; // read buffer
if ack > 0
then SSPCON2.ACKDT := 0 // ack (inverted!)
else SSPCON2.ACKDT := 1; // nack
SSPCON2.ACKEN := 1; // and send ack/nack
repeat until SSPCON2.ACKEN = 0; // ack/nack has been sent, all done
end;
The routine can simply be used in stead of I2c_Rd (I hope).
Kind regards, Dany.
Forget your perfect offering. There is a crack in everything, that's how the light gets in... (L. Cohen)
Remember when we were young? We shone like the sun. (David Gilmour)
Forget your perfect offering. There is a crack in everything, that's how the light gets in... (L. Cohen)
Remember when we were young? We shone like the sun. (David Gilmour)
I don't think so - library is the same and the processor doesn't differ that much from the rest of the PIC18 family. More probable is that your ISR is short enough (clock fast enough) or your program structure disfavors the collision (for example, interrupts are more or less synchronised with main loop).yo2lio wrote:Maybe it's luck ...
or this problem was resolved at PIC18F97J60 family ?!
Sure. You could use a copy of official lib routines with the bug fixed:Dany wrote:Do you think there is a possibility to solve this (by using other -- self made -- I2c_Rd and I2C_Wr routines)?
Code: Select all
function cI2C_rd(ack:byte): byte;
begin
PIR1.SSPIF:=0;
SSPCON2.RCEN:=1;
while PIR1.SSPIF=0 do begin end;
result:=SSPBUF;
SSPCON2.ACKDT:=0;
if ack<>0 then SSPCON2.ACKDT:=1;
PIR1.SSPIF:=0;
SSPCON2.ACKEN:=1;
while PIR1.SSPIF=0 do begin end;
End;{cI2C_rd}
function cI2C_wr(data:byte): byte;
begin
PIR1.SSPIF:=0;
SSPBUF:=data;
while PIR1.SSPIF=0 do begin end;
if SSPCON2.ACKSTAT=0 then result:=0
else
begin
SSPCON2.PEN:=1;
result:=2;
end;
End;{cI2C_wr}
procedure cI2C_Stop;
begin
SSPCON2.PEN:=1;
End;{cI2C_Stop}
I'm sure you'll find the above working better with interrupts than the official version but take into account that there are still infinite loops there and the routines are far from ideal. Writing your own routines is certainly a good idea.
Thanks Janni.
I studied the datasheet,did some experiments myself and came up with some Rd and Rw routines that seem to work with repect to inturrupts. I did publish them on my small PIC related website:
http://users.edpnet.be/rosseel01/DRO/PI ... #PIC_Units, see "NewI2c.ppas". Perhaps you can have a look and see if troubles can be expected with them?
Thanks for all the support!
I studied the datasheet,did some experiments myself and came up with some Rd and Rw routines that seem to work with repect to inturrupts. I did publish them on my small PIC related website:
http://users.edpnet.be/rosseel01/DRO/PI ... #PIC_Units, see "NewI2c.ppas". Perhaps you can have a look and see if troubles can be expected with them?
Thanks for all the support!
Last edited by Dany on 19 Aug 2008 12:20, edited 6 times in total.
Kind regards, Dany.
Forget your perfect offering. There is a crack in everything, that's how the light gets in... (L. Cohen)
Remember when we were young? We shone like the sun. (David Gilmour)
Forget your perfect offering. There is a crack in everything, that's how the light gets in... (L. Cohen)
Remember when we were young? We shone like the sun. (David Gilmour)
Very interesting subject !
I made few tests , real hardware, PIC18F67J60, EEprom 24LC16 (my HWZA board) and I can't reproduce this problem.
I use 1 ms interrupt with TMR2 and in main loop I write, read and verify , continuously from EEprom.
I use Watchdog and if device hang I can see this ....
This is the program :
I made few tests , real hardware, PIC18F67J60, EEprom 24LC16 (my HWZA board) and I can't reproduce this problem.
I use 1 ms interrupt with TMR2 and in main loop I write, read and verify , continuously from EEprom.
I use Watchdog and if device hang I can see this ....
This is the program :
Code: Select all
program Test_I2C;
uses aditional_string_util,lib1_18F97J60_V3_4,eth_lib_user,lib2_18F97J60_V3_4; // Don't touch this line !!!!!
var user_ip_addr : IpHeader;
count_led : byte;
data_user : string[100];
add_eep : word;
txt : string[6];
eol : string[2];
cycle : word;
procedure interrupt; // with TMR2 timer
begin
if TestBit(PIR1,TMR2IF) = 1 then // 1 ms TMR2 Q=41.6667 MHz
begin
PIR1.TMR2IF:=0;
CounterTask; // must called at 1ms
inc(count_led);
if count_led > 99 then
begin
count_led := 0;
asm
BTG PORTB,0
end;
end;
delay_us(500); // Use here 50 % from processor
end;
end;
procedure SI2C_Write(ee_adr : word; ee_data : byte);
begin
I2C_Start(); // Issue I2C start signal
I2C_Wr($A0 + (Hi(ee_adr) shl 1)); // Send byte via I2C(command to 24c16)
I2C_Wr(Lo(ee_adr)); // Send byte(address for EEPROM)
I2C_Wr(ee_data); // Send data(data that will be written)
I2C_Stop();
while true do
begin
I2C_Start; // Issue I2C start signal
I2C_Wr($A0); // Send byte via I2C
if (I2C_Is_Idle) then break;
end;
end;
function SI2C_Read(ee_adr : word) : byte;
begin
I2C_Start(); // Issue I2C start signal
I2C_Wr($A0 + (Hi(ee_adr) shl 1)); // Send byte via I2C(command to 24c16)
I2C_Wr(Lo(ee_adr)); // Send byte(address for EEPROM)
I2C_Repeated_Start; // Issue I2C signal repeated start
I2C_Wr($A1 + (Hi(ee_adr) shl 1)); // Send byte(request data from EEPROM)
result := I2C_Rd(0); // Read the data
I2C_Stop(); // Issue I2C_stop signal
end;
Procedure Init; // with TMR2 timer interrupt
Begin
OSCTUNE := %01000000;
delayms(100);
ClrWdt;
TRISB := %11111110;
PORTB := 0;
count_led := 0;
WDTCON := 1;
CMCON := $07;
ADCON1 := %00001111; // All digital
ADCON2 := %10000111; // RC Clock
INTCON2 := %01111111; // PORTB Pull Up
I2C_Init(100000);
PIE1 := %00000010;
PR2 := 216;
T2CON := %00010010; // prescaler 16, poscaler 3 ; 16*3*217*4 / 41.666667 = 999.935
TMR2 := 0;
T2CON.TMR2ON := 1; // start TMR2
INTCON := %11000000; // intrerupere TMR2 la 1 ms
eol[0] := $0D;
eol[1] := $0A;
eol[2] := 0;
End;
Procedure Eth_SetParameters; // set your parameters here
Begin
Str2Ip('192.168.1.253',eth_ip_addr);
Str2Ip('192.168.1.1',eth_gateway);
Str2Ip('255.255.255.0',eth_mask);
Str2Mac('0004A3008080',eth_mac);
Str2Ip('192.168.1.2',user_ip_addr);
eth_port := 10001;
dest_port := 10001;
end;
begin
Init;
Eth_SetParameters;
Eth_Init;
Wait_for_LAN;
data_user := 'Device Reseted ...';
Str_Cat(data_user,eol);
Send_UDP(user_ip_addr, dest_port, eth_port, Str_Len(data_user), data_user);
cycle := 0;
while PORTB.6 = 0 do
begin
data_user := 'Cycle no. : ';
Word2Str(cycle,txt);
Str_Cat(data_user,txt);
Str_Cat(data_user,eol);
Send_UDP(user_ip_addr, dest_port, eth_port, Str_Len(data_user), data_user);
add_eep := 0;
while add_eep < 2048 do
begin
Eth_DoPacket; // process incoming packets
SI2C_Write(add_eep,255); // Write 255 first
SI2C_Write(add_eep,Lo(add_eep));
if SI2C_Read(add_eep) <> Lo(add_eep) then
begin
data_user := 'Error at address : ';
Word2Str(add_eep,txt);
Str_Cat(data_user,txt);
Str_Cat(data_user,eol);
Send_UDP(user_ip_addr, dest_port, eth_port, Str_Len(data_user), data_user);
end;
inc(add_eep);
end;
inc(cycle);
end;
reset;
end.
Best regards, Florin Andrei Medrea.
http://www.microelemente.ro/
http://www.microelemente.ro/produse-si-servicii/
http://www.microelemente.ro/custom-software/
mail : florin@microelemente.ro
http://www.microelemente.ro/
http://www.microelemente.ro/produse-si-servicii/
http://www.microelemente.ro/custom-software/
mail : florin@microelemente.ro
Thanks Florin,
Did you also do a test wherein more than 1 byte is read from I2c? In the application where I detected the problem, every read I did (on the mikroElektronika Real Time Clock) was a consecutive read of the first 8 registers of the I2c device.
Perhaps the problem only shows with consecutive I2c_Rd's?
Thanks in advance and keep up the good work!
Did you also do a test wherein more than 1 byte is read from I2c? In the application where I detected the problem, every read I did (on the mikroElektronika Real Time Clock) was a consecutive read of the first 8 registers of the I2c device.
Perhaps the problem only shows with consecutive I2c_Rd's?
Thanks in advance and keep up the good work!
Kind regards, Dany.
Forget your perfect offering. There is a crack in everything, that's how the light gets in... (L. Cohen)
Remember when we were young? We shone like the sun. (David Gilmour)
Forget your perfect offering. There is a crack in everything, that's how the light gets in... (L. Cohen)
Remember when we were young? We shone like the sun. (David Gilmour)
I change SI2C_Read with this :
and no hang ....
Code: Select all
function SI2C_Read_8(ee_adr : word) : byte;
begin
I2C_Start(); // Issue I2C start signal
I2C_Wr($A0 + (Hi(ee_adr) shl 1)); // Send byte via I2C(command to 24c16)
I2C_Wr(Lo(ee_adr)); // Send byte(address for EEPROM)
I2C_Repeated_Start; // Issue I2C signal repeated start
I2C_Wr($A1 + (Hi(ee_adr) shl 1)); // Send byte(request data from EEPROM)
result := I2C_Rd(1); // Read the data
I2C_Rd(1);
I2C_Rd(1);
I2C_Rd(1);
I2C_Rd(1);
I2C_Rd(1);
I2C_Rd(1);
I2C_Rd(0);
I2C_Stop(); // Issue I2C_stop signal
end;
Best regards, Florin Andrei Medrea.
http://www.microelemente.ro/
http://www.microelemente.ro/produse-si-servicii/
http://www.microelemente.ro/custom-software/
mail : florin@microelemente.ro
http://www.microelemente.ro/
http://www.microelemente.ro/produse-si-servicii/
http://www.microelemente.ro/custom-software/
mail : florin@microelemente.ro
Hi Florin, is it possible for you to test with the e.g. 16F877A?
Perhaps those I2c routines are not of the same structure as those of the PIC18F67J60.
As far as I understand it the problem is the order of the first statements in I2c_Rd: first enabling reception and after that clearing the interrupt bit gives the problem. Is that order indeed the same in the PIC18F67J60 I2c library or are they not comparable (I do not know the PIC18F67J60).
Thanks in advance.
Perhaps those I2c routines are not of the same structure as those of the PIC18F67J60.
As far as I understand it the problem is the order of the first statements in I2c_Rd: first enabling reception and after that clearing the interrupt bit gives the problem. Is that order indeed the same in the PIC18F67J60 I2c library or are they not comparable (I do not know the PIC18F67J60).
Thanks in advance.
Kind regards, Dany.
Forget your perfect offering. There is a crack in everything, that's how the light gets in... (L. Cohen)
Remember when we were young? We shone like the sun. (David Gilmour)
Forget your perfect offering. There is a crack in everything, that's how the light gets in... (L. Cohen)
Remember when we were young? We shone like the sun. (David Gilmour)
Sorry Dany, I don't have 16F877A !
For JANNI : I put one post few months ago :
http://www.mikroe.com/forum/viewtopic.php?t=14464
I have a bad experience with I2C_Is_Idle at PIC18F452 ...
For JANNI : I put one post few months ago :
http://www.mikroe.com/forum/viewtopic.php?t=14464
I have a bad experience with I2C_Is_Idle at PIC18F452 ...
Best regards, Florin Andrei Medrea.
http://www.microelemente.ro/
http://www.microelemente.ro/produse-si-servicii/
http://www.microelemente.ro/custom-software/
mail : florin@microelemente.ro
http://www.microelemente.ro/
http://www.microelemente.ro/produse-si-servicii/
http://www.microelemente.ro/custom-software/
mail : florin@microelemente.ro
Well, the interrupt comes every several thousand instructions, your main loop also takes thousands of them, the interrupt is probably synchronised with the main loop (unless Send_UDP introduces random delays) - how frequently, do you think, the interrupt will happen exactly between the two critical instructions in I2C routines?yo2lio wrote:I made few tests , real hardware, PIC18F67J60, EEprom 24LC16 (my HWZA board) and I can't reproduce this problem.
I use 1 ms interrupt with TMR2 and in main loop I write, read and verify , continuously from EEprom.
To prove that there is no problem with the library, one would have to make sure that the interrupt would, once in a while, happen after every assembly instruction. To show that there is a problem, one would have to do almost the same , but it should be a bit easier. I'll try to find some time for it, but Dany's post already indicates that the locking problem vanishes with another way of reading I2C device.
About your other post - there is no need to confirm that Microchip's datasheets are far from ideal .