|
|
View previous topic :: View next topic |
Author |
Message |
OldPhart
Joined: 04 Dec 2017 Posts: 8 Location: Canada
|
|
Posted: Tue Dec 05, 2017 10:26 am |
|
|
Ttelmah,
I indeed do not get that one (does not seem very clear in the documentation), but I will go with it. Also thanks for fixing my code for the lacking NACK on my last read, very simple, THANKS!
Now if I can just get the first write to work.....
Thanks again,
OldPhart |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19545
|
|
Posted: Tue Dec 05, 2017 11:38 am |
|
|
Yes, it's a fundamental thing of understanding I2C.
99.9% of it is always controlled only by the master. It generates the clocks etc., so the slave only 'sends' bits when the master actually asks for them.
The '0.1%', is that the slave can hold the clock line low at the end of a byte, to delay the master being able to advance.
Have fun. |
|
|
OldPhart
Joined: 04 Dec 2017 Posts: 8 Location: Canada
|
|
Posted: Tue Dec 05, 2017 6:56 pm |
|
|
I figured it out!
I am suffering from a locked up I2C bus. At some point in time a data transfer was interrupted, or an incorrect sequence run that left the bus in an unknown state.
When not active, both SCL and SDA must be high, but my logic probe showed that SDA was held low by the slave. Normally a power reset would reset this condition, but since the DS3231 has a battery backup, this did not happen. Esentially, the slave is waiting for an ACK signal from the master to send the next byte of data, but the master thinks the bus is idle. Analog Devices app note AN-686 has a real good description of the problem.
How to fix this?
A reset of the PIC does not do it, because of the backup battery. Besides, a reset of the DS3231 would destroy all the settings in it.
The master must produce a 1-0-1 sequence on the SCL line, and check the bus status (both lines should be high). This can take as many as 9 cycles, but also as few as 1 or 2. That all depends on where it got stuck. So.....
I was thinking of running the following at the start of MAIN.c:
Code: |
output_float(PIN_C3)
output_float(PIN_C4)
while ((input_state(PIN_C4) && input_state(PIN_C3)) != 1)
{
output_low (PIN_C3); //SCL
delay_cycles(1);
output_float (PIN_C3); //SCL
}
|
I have not tried it yet, something for tomorrow!
Cheers,
OldPhart |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Dec 05, 2017 7:05 pm |
|
|
This recent post has code to implement the i2c reset method described
in Analog Devices AN-686:
http://www.ccsinfo.com/forum/viewtopic.php?t=56821&start=15
Instead of the I2CEN bit, you should use the SSPEN bit, since your PIC
is the 16F877A. Also use getenv() instead of hard-coding the register
address. |
|
|
OldPhart
Joined: 04 Dec 2017 Posts: 8 Location: Canada
|
|
Posted: Wed Dec 06, 2017 3:31 pm |
|
|
PCM programmer,
WONDERFUL! You got me on the right track; I now have a perfectly working timer! My code ended up like this:
Code: |
#bit I2CEN = 0x14.5 // SSPEN bit to enable/disable hardware I2C module
#define i2c_SCL PIN_C3
#define i2c_SDA PIN_C4
if(!input(i2c_SDA)){ // if SDA stuck low - Fault Condition
I2CEN=0; // disable I2C2 Hardware Module
output_drive(i2c_SCL); // set SCL as output
while(!input(i2c_SDA)){ // Toggle clock line till fault clears
output_toggle(i2c_SCL);
delay_us(1);
}
output_float(i2c_SCL); // set SCL as input
I2CEN=1; // enable I2C2 Hardware Module
} |
I did hardcode the SSPEN address for now, I have to look up how to use the getenv(). OldPhart,...... Learn slowwwwww.
On to the next part of the project....
Thanks again,
OldPhart |
|
|
|
|
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
|