0
\$\begingroup\$

UPDATE: Code snippet already done below. Not sure if correct.

I implemented the routine which is found in Microchip's datasheet in order to reset the EEPROM memory (24LC512)in case it hangs up. But not sure it is correct.

Many people in the internet commented on doing this, but no code "in the wild" yet. Maybe it's about time...

enter image description here

http://ww1.microchip.com/downloads/en/AppNotes/01028a.pdf

I made a draft. I am asking for comments as I can't test this.

Wire1.end();
    const int SDA=70;
    const int SCL=71;

        pinMode(SDA, OUTPUT); //70 -> SDA1
       pinMode(71, OUTPUT); //71 -> SCL2.   

         /* Send START condition */
        //A HIGH to LOW transition on the SDA line while SCL is HIGH defines a START condition. 
          digitalWrite(71, HIGH);
          delayMicroseconds(5);
          digitalWrite(SDA, HIGH);
          delayMicroseconds(5);
          digitalWrite(SDA, LOW);
          delayMicroseconds(5);
          digitalWrite(71, LOW);


             digitalWrite(SDA, HIGH); //WRONG?? " while allowing the SDA line to float,"  https://www.microchip.com/forums/m898899.aspx
       //send 9 clock pulses to reset slaves
       for(int i = 0; i < 9; i++){
           digitalWrite(71, HIGH);
           delayMicroseconds(5);
           digitalWrite(71, LOW);
       }

         /* Send START condition */
         //A HIGH to LOW transition on the SDA line while SCL is HIGH defines a START condition.
         digitalWrite(71, HIGH);
         delayMicroseconds(5);
         digitalWrite(SDA, HIGH);
         delayMicroseconds(5);
         digitalWrite(SDA, LOW);
         delayMicroseconds(5);
         digitalWrite(71, LOW);

           /* Send STOP condition */
           //A LOW to HIGH transition on the SDA line while SCL is HIGH defines a STOP condition.
           digitalWrite(71, HIGH);
           delayMicroseconds(5);
           digitalWrite(SDA, LOW);
           delayMicroseconds(5);
           digitalWrite(SDA, HIGH);
           delayMicroseconds(5);
           digitalWrite(71, LOW);

Wire1.begin();
```
\$\endgroup\$
15
  • 2
    \$\begingroup\$ You could just bit bang it then go back into i2c mode. \$\endgroup\$
    – Ron Beyer
    Mar 15, 2020 at 18:43
  • \$\begingroup\$ 9 bits of '1' is just sending a 0xFF byte (or addressing device 0x7F to write) and not getting an ACK response. The trick is how to send the repeated start condition followed immediately by a stop. \$\endgroup\$
    – The Photon
    Mar 15, 2020 at 19:50
  • \$\begingroup\$ What microcontroller are you using? (full part number would be most helpful) \$\endgroup\$
    – The Photon
    Mar 15, 2020 at 19:55
  • \$\begingroup\$ @ThePhoton That is actually addressing device 0x7F to read, but if there was already a transfer going on the bus and SDA is low, the EEPROM may not see the start bit transmission. If the transmission was from EEPROM to MCU, one of the 1 bits is NAK to the EEPROM so it knows to release the bus. If the transmission was from MCU to EEPROM, one of the bits is logic 0 ACK from EEPROM, but as all other bits leave the bus high, the MCU can stop at a point where both SDA and SCL are high, and then generate a start condition to cancel EEPROM write. \$\endgroup\$
    – Justme
    Mar 15, 2020 at 20:19
  • 2
    \$\begingroup\$ @Justme, It doesn't matter if the EEPROM see's the start. If it's in a state where it is locking the bus due to being in the middle of a data transfer, the 9 clock edges and stop condition will get it out of that state. The point of this sequence isn't that the stop and start conditions you send actually happen, it's that by trying to send them you get the EEPROM into a known state, regardless of where it is when you start. \$\endgroup\$
    – The Photon
    Mar 15, 2020 at 20:21

2 Answers 2

2
\$\begingroup\$

As the bus may be in any state, it may not even be possible to use the TWI peripheral to send anything, not even start bit.

So you must switch the I2C peripheral off so you can just send the wanted sequence by bit-banging the GPIO pins with software. Just remember that you must never output logic high, only logic low or input.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ The point of this special sequence is that it will return the EEPROM to a known state, no matter what state it started in. If you don't know the state of your micro's TWI peripheral, presumably there is a RESET bit somewhere in its registers that would allow you to get it into a known state without having to power cycle. \$\endgroup\$
    – The Photon
    Mar 15, 2020 at 19:53
  • \$\begingroup\$ Yes, but if you have a reset button and uset it to reset your MCU while I2C operation was ongoing, you know in what state the TWI peripheral is, but you don't know the state of the bus or the EEPROM, so you may not be able to use the TWI peripheral for anything. If the EEPROM was sending low data out or ACK bit, the SDA is be low, and the MCU can't even send out start condition. So the TWI peripheral can only be enabled after the bus, and the EEPROM are returned to known state. The sequence is also such that it cancels a write operation that can occur if only a STOP condition is sent. \$\endgroup\$
    – Justme
    Mar 15, 2020 at 20:08
  • 1
    \$\begingroup\$ You don't know the state of the EEPROM, but, like I said before, "The point of this special sequence is that it will return the EEPROM to a known state, no matter what state it started in." Even if it was stuck in the middle of sending a low data bit so you can't create a legitimate start condition, when you start sending clock edges you will get it out of that state. \$\endgroup\$
    – The Photon
    Mar 15, 2020 at 20:17
  • \$\begingroup\$ @Justme I added code to the question. What meakes me wonther is, to send a Start Condition i need to move SDA from HIGH to LOW. If I don't do anything more, the 9 bits will be sent with a LOW SDA. This is not what we wanted.... what did you mean? how would u do this? thank you!! \$\endgroup\$
    – Pep
    Mar 17, 2020 at 9:22
1
\$\begingroup\$

Is the spec really calling for you to send 9 bits over I2C when the interface is generally byte oriented? (Could be so as this is a reset operation, although it is unusual. I would first check the datasheet.)

If it is so, the best way is probably to take over the port pins and write a routine to bit bash this, then release the port. It's a routine that would only be used exceptionally, so no harm with it, and bit bashing is not too hard with I2C. In this case you don't care if it is a bit slower than normal operations.

\$\endgroup\$
3
  • \$\begingroup\$ Yes the reset sequence is special - if you reset the AVR while transmission to EEPROM is ongoing, you have no idea in which state the bus is so the sequence must be such that it clocks out safely from any state. \$\endgroup\$
    – Justme
    Mar 15, 2020 at 19:22
  • \$\begingroup\$ right. I would code this as an I2C_init(0 routine, do it on power up and again if there seem to be problems. \$\endgroup\$
    – danmcb
    Mar 15, 2020 at 19:42
  • \$\begingroup\$ If you consider the ACK bit, every byte transfer over I2C (or TWI) is a 9 bit transaction. \$\endgroup\$
    – The Photon
    Mar 15, 2020 at 19:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.