Reply by Mike Perkins November 26, 20202020-11-26
On 26/11/2020 07:54:57, pozz wrote:
> Il 25/11/2020 18:43, Mike Perkins ha scritto: > > On 20/11/2020 08:43:32, pozz wrote: > >> I hate I2C for several reasons. It's only two-wires bus, but for this > >> reason it is insidious. > >> > >> I usually use hw peripherals when they are available, because it's > >> much more efficient and smart and because it's the only possibility in > >> many cases. > >> Actually we have MCUs with abundant UARTs, timers and so on, so > >> there's no real story: choose a suitable MCU and use that damn > >> peripheral. > >> So I usually start using I2C peripherals available in MCUs, but I > >> found many issues. > >> > >> I have experience with AVR8 and SAMC21 by Atmel/Microchip. In both > >> cases the I2C peripheral is much more complex than UART or similar > >> serial lines. I2C Single Master, that is the most frequent situation, > >> is very simple, > > > > I don't have much experience in these micros, mainly ST ARM devices. But > > single master applications can be very reliable, as long as you check > > all the status bits. Some examples only look for patterns that could > > leave a hanging peripheral. > > > >> but I2C Multi Master introduces many critical situations. > >> I2C peripherals usually promise to be compatible with multi-master, so > >> their internal state machine is somewhat complex... and often there's > >> some bug or situations that aren't expected that leave the code stucks > >> at some point. > > > > This is where I diverge. I would not choose to use I2C in a multi-master > > system. > Me too. It was only to just say the peripheral inside new MCUs are > compatible with I2C Multi-Master, so they are complex state-machine (see > arbitration lost). > > > > I2C was always intended to be used on a single PCB, without long wires > > attracting EM noise. > > > >> I want to write reliable code that not only works most of the time, > >> but that works ALL the time, in any situations (ok, 99%). So my first > >> test with I2C is making a temporary short between SCL and SDA. In this > >> case, I2C in SAMC21 (they named it SERCOM in I2C Master mode) hangs > >> forever. The manual says to write ADDR register to start putting the > >> address on the bus and wait for an interrupt flag when it ends. This > >> interrupt is never fired up. I see the lines goes down (because START > >> bit is putting low SDA before SCL), but the INTFLAG bits stay cleared > >> forever. Even error bits in STATUS register (bus error, arbitration > >> lost, any sort of timeout...) stay cleared and the BUSSTATE is IDLE. > >> As soon as the short is removed, the state-machine goes on. > >> > >> Maybe I'm wrong, so I studied Atmel Software Framework[1] and Arduino > >> Wire libraries[2]. In both cases, a timeout is implemented at the > >> driver level. > >> > >> Even the datasheet says: > >> > >>    "Note:  Violating the protocol may cause the I2C to hang. If this > >>    happens it is possible to recover from this state by a > >>    software reset (CTRLA.SWRST='1')." > > > > Not all manufacturers say this. The trick is to detect an error > > condition, clear the error and if necessary reset the peripheral. > In my case, the peripheral doesn't trigger any error and you can exit > from this situation only with a timeout.
Are you certain that the main event interrupt isn't being called repeatedly? Because not all the conditions that cause the interrupt have been serviced? I'm more familiar with the ST ARM range and generally haven't seen a hang condition that can't be assessed by looking at the status registers. I obviously accept that other MCUs may behave differently. I'm currently using FreeRTOS, and with a transmission complete semaphore, so implementing a short timeout becomes an easy matter. Also useful for repeating the I2C transmission in a failed NAK case. -- Mike Perkins Video Solutions Ltd www.videosolutions.ltd.uk
Reply by pozz November 26, 20202020-11-26
Il 25/11/2020 18:43, Mike Perkins ha scritto:
 > On 20/11/2020 08:43:32, pozz wrote:
 >> I hate I2C for several reasons. It's only two-wires bus, but for this
 >> reason it is insidious.
 >>
 >> I usually use hw peripherals when they are available, because it's
 >> much more efficient and smart and because it's the only possibility in
 >> many cases.
 >> Actually we have MCUs with abundant UARTs, timers and so on, so
 >> there's no real story: choose a suitable MCU and use that damn
 >> peripheral.
 >> So I usually start using I2C peripherals available in MCUs, but I
 >> found many issues.
 >>
 >> I have experience with AVR8 and SAMC21 by Atmel/Microchip. In both
 >> cases the I2C peripheral is much more complex than UART or similar
 >> serial lines. I2C Single Master, that is the most frequent situation,
 >> is very simple,
 >
 > I don't have much experience in these micros, mainly ST ARM devices. But
 > single master applications can be very reliable, as long as you check
 > all the status bits. Some examples only look for patterns that could
 > leave a hanging peripheral.
 >
 >> but I2C Multi Master introduces many critical situations.
 >> I2C peripherals usually promise to be compatible with multi-master, so
 >> their internal state machine is somewhat complex... and often there's
 >> some bug or situations that aren't expected that leave the code stucks
 >> at some point.
 >
 > This is where I diverge. I would not choose to use I2C in a multi-master
 > system.
Me too. It was only to just say the peripheral inside new MCUs are 
compatible with I2C Multi-Master, so they are complex state-machine (see 
arbitration lost).


 > I2C was always intended to be used on a single PCB, without long wires
 > attracting EM noise.
 >
 >> I want to write reliable code that not only works most of the time,
 >> but that works ALL the time, in any situations (ok, 99%). So my first
 >> test with I2C is making a temporary short between SCL and SDA. In this
 >> case, I2C in SAMC21 (they named it SERCOM in I2C Master mode) hangs
 >> forever. The manual says to write ADDR register to start putting the
 >> address on the bus and wait for an interrupt flag when it ends. This
 >> interrupt is never fired up. I see the lines goes down (because START
 >> bit is putting low SDA before SCL), but the INTFLAG bits stay cleared
 >> forever. Even error bits in STATUS register (bus error, arbitration
 >> lost, any sort of timeout...) stay cleared and the BUSSTATE is IDLE.
 >> As soon as the short is removed, the state-machine goes on.
 >>
 >> Maybe I'm wrong, so I studied Atmel Software Framework[1] and Arduino
 >> Wire libraries[2]. In both cases, a timeout is implemented at the
 >> driver level.
 >>
 >> Even the datasheet says:
 >>
 >>    "Note:  Violating the protocol may cause the I2C to hang. If this
 >>    happens it is possible to recover from this state by a
 >>    software reset (CTRLA.SWRST='1')."
 >
 > Not all manufacturers say this. The trick is to detect an error
 > condition, clear the error and if necessary reset the peripheral.
In my case, the peripheral doesn't trigger any error and you can exit 
from this situation only with a timeout.


 >> I think the driver code should trust the hw, between them there's a
 >> contract, otherwise it's impossibile. For a UART driver, you write
 >> DATA register and wait an interrupt flag when a new data can be
 >> written in the register. If the interrupt nevers fire, the driver
 >> hangs forever.
 >> But I have never seen a UART driver that uses a timeout to recover
 >> from a hardware that could hang. And I used UARTs for many years now.
 >>
 >>
 >> Considering all these big issues when you want to write reliable code,
 >> I'm considering to wipe again the old and good bit banging technique.
 >> For I2C Single Master scenario, it IS very simple: put data low/high
 >> (three-state), put clock low/high. The only problem is to calibrate
 >> the clock frequency, but if you a free timer it will be simple too.
 >
 > Nothing wrong with bit-banging.
 >
 >> What is the drawback of bit banging? Maybe you write a few additional
 >> lines of code (you have to spit off 9 clock pulses by code), but I
 >> don't think much more than using a peripheral and protect it with a
 >> timeout.
 >> But you earn a code that is fully under your control and you know when
 >> the I2C transaction starts and you can be sure it will end, even when
 >> there are some hw issues on the board.
 >
 > There is no drawback, apart from difficult to debug and a high MCU
 > utilisation. At least I2C is meant to be static, unlike SMB.
 >
Reply by Mike Perkins November 25, 20202020-11-25
On 20/11/2020 08:43:32, pozz wrote:
> I hate I2C for several reasons. It's only two-wires bus, but for this > reason it is insidious. > > I usually use hw peripherals when they are available, because it's much > more efficient and smart and because it's the only possibility in many > cases. > Actually we have MCUs with abundant UARTs, timers and so on, so there's > no real story: choose a suitable MCU and use that damn peripheral. > So I usually start using I2C peripherals available in MCUs, but I found > many issues. > > I have experience with AVR8 and SAMC21 by Atmel/Microchip. In both cases > the I2C peripheral is much more complex than UART or similar serial > lines. I2C Single Master, that is the most frequent situation, is very > simple,
I don't have much experience in these micros, mainly ST ARM devices. But single master applications can be very reliable, as long as you check all the status bits. Some examples only look for patterns that could leave a hanging peripheral.
> but I2C Multi Master introduces many critical situations. > I2C peripherals usually promise to be compatible with multi-master, so > their internal state machine is somewhat complex... and often there's > some bug or situations that aren't expected that leave the code stucks > at some point.
This is where I diverge. I would not choose to use I2C in a multi-master system. I2C was always intended to be used on a single PCB, without long wires attracting EM noise.
> I want to write reliable code that not only works most of the time, but > that works ALL the time, in any situations (ok, 99%). So my first test > with I2C is making a temporary short between SCL and SDA. In this case, > I2C in SAMC21 (they named it SERCOM in I2C Master mode) hangs forever. > The manual says to write ADDR register to start putting the address on > the bus and wait for an interrupt flag when it ends. This interrupt is > never fired up. I see the lines goes down (because START bit is putting > low SDA before SCL), but the INTFLAG bits stay cleared forever. Even > error bits in STATUS register (bus error, arbitration lost, any sort of > timeout...) stay cleared and the BUSSTATE is IDLE. As soon as the short > is removed, the state-machine goes on. > > Maybe I'm wrong, so I studied Atmel Software Framework[1] and Arduino > Wire libraries[2]. In both cases, a timeout is implemented at the driver > level. > > Even the datasheet says: > >   "Note:  Violating the protocol may cause the I2C to hang. If this >   happens it is possible to recover from this state by a >   software reset (CTRLA.SWRST='1')."
Not all manufacturers say this. The trick is to detect an error condition, clear the error and if necessary reset the peripheral.
> I think the driver code should trust the hw, between them there's a > contract, otherwise it's impossibile. For a UART driver, you write DATA > register and wait an interrupt flag when a new data can be written in > the register. If the interrupt nevers fire, the driver hangs forever. > But I have never seen a UART driver that uses a timeout to recover from > a hardware that could hang. And I used UARTs for many years now. > > > Considering all these big issues when you want to write reliable code, > I'm considering to wipe again the old and good bit banging technique. > For I2C Single Master scenario, it IS very simple: put data low/high > (three-state), put clock low/high. The only problem is to calibrate the > clock frequency, but if you a free timer it will be simple too.
Nothing wrong with bit-banging.
> What is the drawback of bit banging? Maybe you write a few additional > lines of code (you have to spit off 9 clock pulses by code), but I don't > think much more than using a peripheral and protect it with a timeout. > But you earn a code that is fully under your control and you know when > the I2C transaction starts and you can be sure it will end, even when > there are some hw issues on the board.
There is no drawback, apart from difficult to debug and a high MCU utilisation. At least I2C is meant to be static, unlike SMB. -- Mike Perkins Video Solutions Ltd www.videosolutions.ltd.uk
Reply by Reinhardt Behm November 24, 20202020-11-24
On 11/23/20 8:25 PM, Richard Damon wrote:
> One thing to note about the I2C bus protocol, is that a High to Low > transition of the SDA line when SCL is high (a Start Bit) is supposed to > 'Reset' the communication channel of every device on the bus and put it > in the mode to compare the next 8 bits as a Device Address.
Also a sequence of >= 10 clock pulses is supposed to get devices into normal function. Unfortunately not all devices have read this spec. I had one (LM75) which could be driven reproducible into a non-responding mode by a short glitch on data or clock. The only way to recover was a power cycle.
Reply by Richard Damon November 23, 20202020-11-23
On 11/23/20 2:44 AM, pozz wrote:
> Il 22/11/2020 19:44, David Brown ha scritto: >> On 22/11/2020 17:48, pozz wrote: >>> Il 21/11/2020 12:06, David Brown ha scritto: >>>> On 20/11/2020 18:39, Tauno Voipio wrote: >>>> >>>>> I have had thousands of industrial instruments in the field for >>>>> decades, >>>>> each running some internal units with I2C, some bit-banged and others >>>>> on the hardware interfaces on the processors used, and not a single >>>>> failure due to I2C hanging. >>>>> >>>> >>>> The only time I have seen I²C buses hanging is during development, when >>>> you might be re-starting the cpu in the middle of an operation without >>>> there being a power-on reset to the slave devices.  That can easily >>>> leave the bus in an invalid state, or leave a slave state machine >>>> out of >>>> synchronisation with the bus.  But I have not seen this kind of thing >>>> happen in a live system. >>> In the past I had a big problem with a I2C bus on a board. Ubiquitous >>> EEPROM 24LC64 connected to a 16-bits MCU by Fujitsu. In that case, I2C >>> was implemented by a bit-bang code. >>> >>> At startup MCU read the EEPROM content and if it was corrupted, factory >>> default are used and wrote to the EEPROM. This mechanism was introduced >>> to write a blank EEPROM at the very first power up of a fresh board. >>> >>> Unfortunately it sometimes happened that the MCU reset in the middle of >>> a I2C transaction with the EEPROM (the reset was caused by a glitch on >>> the power supply that triggered a MCU voltage supervisor). >>> When the MCU restarted, it tried to communicate with the EEPROM, but it >>> was in a not synchronized I2C state. This is well described in AN868[1] >>> from Analog Devices.. >>> >>> The MCU thoughts it was a blank EEPROM and factory settings was used, >>> overwriting user settings! What the user blamed was that the machine >>> sometimes restarted with factory settings, losing user settings. >>> >>> In that case the solution was adding a I2C reset procedure at startup >>> (some clock pulses and STOP condition as described in the Application >>> Note). >>> I think this I2C bus reset procedure must be always added where there's >>> a I2C bus and most probably it must be implemented by a big-bang code. >>> >>> >>> [1] >>> https://www.analog.com/media/en/technical-documentation/application-notes/54305147357414AN686_0.pdf >>> >>> >> >> Sure, add that kind of a reset at startup - it also helps if you are >> unlucky when restarting the chip during development. >> >> Also make sure you write two copies of the user data to the EEPROM, so >> that you can survive a crash while writing to it. >> >> But if your board is suffering power supply glitches that are enough to >> trigger the MCU brown-out, but not enough to cause a proper re-start of >> the rest of the board, then /that/ is a major problem that you should be >> trying to solve. > > Yes, but it's not simple. As described in AN686, I2C EEPROMs doesn't > have a reset, so it's impossible for the MCU to reset the EEPROM at > startup. The only solution is to introduce dedicated hw to remove and > reapply power supply. > > This is the main reason I now prefer to use SPI EEPROM (when possible), > because slave-select signal of the SPI bus restart automatically the > transaction. > > >>>>> Please remember that the I2C bus is an Inter-IC bus, not to be used >>>>> for >>>>> connections to the outside of the device, preferably only on the same >>>>> circuit board. There should be no external connectors where e.g. the >>>>> shorts between the SCL and SDA could happen. >>>>> >>>>> All the hardWare I2C controls have been able to be restored to a >>>>> sensible state with a software reset after a time-out. This includes >>>>> the Atmel chips. >>>>> >>>> >> >
One thing to note about the I2C bus protocol, is that a High to Low transition of the SDA line when SCL is high (a Start Bit) is supposed to 'Reset' the communication channel of every device on the bus and put it in the mode to compare the next 8 bits as a Device Address. Thus, if at the 'random' reset, no device is driving the SDA line high, then as soon as the master starts a new cycle, everything is back in sync. It is possible, that a device is either doing an ACK or a Read Cycle at the point of reset, holding SDA low. The master just needs to cycle SCL until SDA goes high by completing that ack or read cycle. The Read might need up to 8 clocks. One we have SDA and SCL high, we can generate the Start to get everyone listening. Devices should not be holding SCL low for extended periods, so that shouldn't be a problem (or is a problem of a different nature if you do have an oddball infinite bus extender).
Reply by David Brown November 23, 20202020-11-23
On 23/11/2020 08:44, pozz wrote:
> Il 22/11/2020 19:44, David Brown ha scritto:
>> But if your board is suffering power supply glitches that are enough to >> trigger the MCU brown-out, but not enough to cause a proper re-start of >> the rest of the board, then /that/ is a major problem that you should be >> trying to solve. > > Yes, but it's not simple. As described in AN686, I2C EEPROMs doesn't > have a reset, so it's impossible for the MCU to reset the EEPROM at > startup. The only solution is to introduce dedicated hw to remove and > reapply power supply. > > This is the main reason I now prefer to use SPI EEPROM (when possible), > because slave-select signal of the SPI bus restart automatically the > transaction. >
I hit "send" before I included a final point - the "dedicated hardware to remove the power supply to the eeprom" is usually just a GPIO pin from the microcontroller. Often a GPIO pin can easily supply the current needed for a low power device like an eeprom, so that you don't need anything else.
Reply by David Brown November 23, 20202020-11-23
On 23/11/2020 08:44, pozz wrote:
> Il 22/11/2020 19:44, David Brown ha scritto: >> On 22/11/2020 17:48, pozz wrote: >>> Il 21/11/2020 12:06, David Brown ha scritto: >>>> On 20/11/2020 18:39, Tauno Voipio wrote: >>>> >>>>> I have had thousands of industrial instruments in the field for >>>>> decades, >>>>> each running some internal units with I2C, some bit-banged and others >>>>> on the hardware interfaces on the processors used, and not a single >>>>> failure due to I2C hanging. >>>>> >>>> >>>> The only time I have seen I²C buses hanging is during development, when >>>> you might be re-starting the cpu in the middle of an operation without >>>> there being a power-on reset to the slave devices.  That can easily >>>> leave the bus in an invalid state, or leave a slave state machine >>>> out of >>>> synchronisation with the bus.  But I have not seen this kind of thing >>>> happen in a live system. >>> In the past I had a big problem with a I2C bus on a board. Ubiquitous >>> EEPROM 24LC64 connected to a 16-bits MCU by Fujitsu. In that case, I2C >>> was implemented by a bit-bang code. >>> >>> At startup MCU read the EEPROM content and if it was corrupted, factory >>> default are used and wrote to the EEPROM. This mechanism was introduced >>> to write a blank EEPROM at the very first power up of a fresh board. >>> >>> Unfortunately it sometimes happened that the MCU reset in the middle of >>> a I2C transaction with the EEPROM (the reset was caused by a glitch on >>> the power supply that triggered a MCU voltage supervisor). >>> When the MCU restarted, it tried to communicate with the EEPROM, but it >>> was in a not synchronized I2C state. This is well described in AN868[1] >>> from Analog Devices.. >>> >>> The MCU thoughts it was a blank EEPROM and factory settings was used, >>> overwriting user settings! What the user blamed was that the machine >>> sometimes restarted with factory settings, losing user settings. >>> >>> In that case the solution was adding a I2C reset procedure at startup >>> (some clock pulses and STOP condition as described in the Application >>> Note). >>> I think this I2C bus reset procedure must be always added where there's >>> a I2C bus and most probably it must be implemented by a big-bang code. >>> >>> >>> [1] >>> https://www.analog.com/media/en/technical-documentation/application-notes/54305147357414AN686_0.pdf >>> >>> >> >> Sure, add that kind of a reset at startup - it also helps if you are >> unlucky when restarting the chip during development. >> >> Also make sure you write two copies of the user data to the EEPROM, so >> that you can survive a crash while writing to it. >> >> But if your board is suffering power supply glitches that are enough to >> trigger the MCU brown-out, but not enough to cause a proper re-start of >> the rest of the board, then /that/ is a major problem that you should be >> trying to solve. > > Yes, but it's not simple. As described in AN686, I2C EEPROMs doesn't > have a reset, so it's impossible for the MCU to reset the EEPROM at > startup. The only solution is to introduce dedicated hw to remove and > reapply power supply. > > This is the main reason I now prefer to use SPI EEPROM (when possible), > because slave-select signal of the SPI bus restart automatically the > transaction. > >
I too prefer SPI - it is often simpler and can be much faster. However, if it is possible for your power supply to glitch and reset the MCU, without being turned off properly (and therefore reseting your eeprom), you have a definite hardware problem on the board. (Of course, boards vary in how much effort and money you are willing to spend to get stability, and how unstable a supply you might have.)
Reply by pozz November 23, 20202020-11-23
Il 22/11/2020 19:44, David Brown ha scritto:
> On 22/11/2020 17:48, pozz wrote: >> Il 21/11/2020 12:06, David Brown ha scritto: >>> On 20/11/2020 18:39, Tauno Voipio wrote: >>> >>>> I have had thousands of industrial instruments in the field for decades, >>>> each running some internal units with I2C, some bit-banged and others >>>> on the hardware interfaces on the processors used, and not a single >>>> failure due to I2C hanging. >>>> >>> >>> The only time I have seen I²C buses hanging is during development, when >>> you might be re-starting the cpu in the middle of an operation without >>> there being a power-on reset to the slave devices.  That can easily >>> leave the bus in an invalid state, or leave a slave state machine out of >>> synchronisation with the bus.  But I have not seen this kind of thing >>> happen in a live system. >> In the past I had a big problem with a I2C bus on a board. Ubiquitous >> EEPROM 24LC64 connected to a 16-bits MCU by Fujitsu. In that case, I2C >> was implemented by a bit-bang code. >> >> At startup MCU read the EEPROM content and if it was corrupted, factory >> default are used and wrote to the EEPROM. This mechanism was introduced >> to write a blank EEPROM at the very first power up of a fresh board. >> >> Unfortunately it sometimes happened that the MCU reset in the middle of >> a I2C transaction with the EEPROM (the reset was caused by a glitch on >> the power supply that triggered a MCU voltage supervisor). >> When the MCU restarted, it tried to communicate with the EEPROM, but it >> was in a not synchronized I2C state. This is well described in AN868[1] >> from Analog Devices.. >> >> The MCU thoughts it was a blank EEPROM and factory settings was used, >> overwriting user settings! What the user blamed was that the machine >> sometimes restarted with factory settings, losing user settings. >> >> In that case the solution was adding a I2C reset procedure at startup >> (some clock pulses and STOP condition as described in the Application >> Note). >> I think this I2C bus reset procedure must be always added where there's >> a I2C bus and most probably it must be implemented by a big-bang code. >> >> >> [1] >> https://www.analog.com/media/en/technical-documentation/application-notes/54305147357414AN686_0.pdf >> > > Sure, add that kind of a reset at startup - it also helps if you are > unlucky when restarting the chip during development. > > Also make sure you write two copies of the user data to the EEPROM, so > that you can survive a crash while writing to it. > > But if your board is suffering power supply glitches that are enough to > trigger the MCU brown-out, but not enough to cause a proper re-start of > the rest of the board, then /that/ is a major problem that you should be > trying to solve.
Yes, but it's not simple. As described in AN686, I2C EEPROMs doesn't have a reset, so it's impossible for the MCU to reset the EEPROM at startup. The only solution is to introduce dedicated hw to remove and reapply power supply. This is the main reason I now prefer to use SPI EEPROM (when possible), because slave-select signal of the SPI bus restart automatically the transaction.
>>>> Please remember that the I2C bus is an Inter-IC bus, not to be used for >>>> connections to the outside of the device, preferably only on the same >>>> circuit board. There should be no external connectors where e.g. the >>>> shorts between the SCL and SDA could happen. >>>> >>>> All the hardWare I2C controls have been able to be restored to a >>>> sensible state with a software reset after a time-out. This includes >>>> the Atmel chips. >>>> >>> >
Reply by Michael Kellett November 22, 20202020-11-22
On 22/11/2020 16:35, pozz wrote:
> Il 21/11/2020 10:10, Michael Kellett ha scritto: >> On 20/11/2020 08:43, pozz wrote: >>> I hate I2C for several reasons. It's only two-wires bus, but for this >>> reason it is insidious. >>> >>> I usually use hw peripherals when they are available, because it's >>> much more efficient and smart and because it's the only possibility >>> in many cases. >>> Actually we have MCUs with abundant UARTs, timers and so on, so >>> there's no real story: choose a suitable MCU and use that damn >>> peripheral. >>> So I usually start using I2C peripherals available in MCUs, but I >>> found many issues. >>> >>> I have experience with AVR8 and SAMC21 by Atmel/Microchip. In both >>> cases the I2C peripheral is much more complex than UART or similar >>> serial lines. I2C Single Master, that is the most frequent situation, >>> is very simple, but I2C Multi Master introduces many critical >>> situations. >>> I2C peripherals usually promise to be compatible with multi-master, >>> so their internal state machine is somewhat complex... and often >>> there's some bug or situations that aren't expected that leave the >>> code stucks at some point. >>> >>> I want to write reliable code that not only works most of the time, >>> but that works ALL the time, in any situations (ok, 99%). So my first >>> test with I2C is making a temporary short between SCL and SDA. In >>> this case, I2C in SAMC21 (they named it SERCOM in I2C Master mode) >>> hangs forever. The manual says to write ADDR register to start >>> putting the address on the bus and wait for an interrupt flag when it >>> ends. This interrupt is never fired up. I see the lines goes down >>> (because START bit is putting low SDA before SCL), but the INTFLAG >>> bits stay cleared forever. Even error bits in STATUS register (bus >>> error, arbitration lost, any sort of timeout...) stay cleared and the >>> BUSSTATE is IDLE. As soon as the short is removed, the state-machine >>> goes on. >>> >>> Maybe I'm wrong, so I studied Atmel Software Framework[1] and Arduino >>> Wire libraries[2]. In both cases, a timeout is implemented at the >>> driver level. >>> >>> Even the datasheet says: >>> >>>    "Note:  Violating the protocol may cause the I2C to hang. If this >>>    happens it is possible to recover from this state by a >>>    software reset (CTRLA.SWRST='1')." >>> >>> I think the driver code should trust the hw, between them there's a >>> contract, otherwise it's impossibile. For a UART driver, you write >>> DATA register and wait an interrupt flag when a new data can be >>> written in the register. If the interrupt nevers fire, the driver >>> hangs forever. >>> But I have never seen a UART driver that uses a timeout to recover >>> from a hardware that could hang. And I used UARTs for many years now. >>> >>> >>> Considering all these big issues when you want to write reliable >>> code, I'm considering to wipe again the old and good bit banging >>> technique. >>> For I2C Single Master scenario, it IS very simple: put data low/high >>> (three-state), put clock low/high. The only problem is to calibrate >>> the clock frequency, but if you a free timer it will be simple too. >>> >>> What is the drawback of bit banging? Maybe you write a few additional >>> lines of code (you have to spit off 9 clock pulses by code), but I >>> don't think much more than using a peripheral and protect it with a >>> timeout. >>> But you earn a code that is fully under your control and you know >>> when the I2C transaction starts and you can be sure it will end, even >>> when there are some hw issues on the board. >>> >>> >>> >>> >>> >>> [1] >>> https://github.com/avrxml/asf/blob/68cddb46ae5ebc24ef8287a8d4c61a6efa5e2848/sam0/drivers/sercom/i2c/i2c_sam0/i2c_master.c#L406 >>> >>> >>> [2] >>> https://github.com/acicuc/ArduinoCore-samd/commit/64385453bb549b6d2f868658119259e605aca74d >>> >> If you do a bit banged interface do not forget to support clock >> stretching by the slave. > > If the slave should use clock streching, I think the datasheet would say > this clearly. > >> Do not assume that the slave has no special timing requirements. >> To do it right you need a hardware timer (or a cast iron guarantee >> that the bit bang function won't be interrupted). > > Please, explain. I2C is synchronous to clock transmitted by the Master. > Of course Master should respect a range for the clock frequency (around > 100kHz or 400kHz), but I don't think a jitter on the I2C clock, caused > by an interrupt, could be a serious problem for the slave. > > >> I've found hardware I2C controllers on micros to be 100% reliably a >> problem. The manufacturers drivers are often part of that problem. >> >> I'm currently trying to debug some one else's not working >> implementation of an ST I2C peripheral controller. It uses ST's driver. >> >> MK >
Jitter should not be a problem, but I have known slave devices go to sleep after a few ms of inactivity on the bus. I've seen many bit banged attempts using processor loops for delays. Then something changes (compiler upgrade, faster clock, whatever) and then it all goes wrong. MK
Reply by David Brown November 22, 20202020-11-22
On 22/11/2020 17:48, pozz wrote:
> Il 21/11/2020 12:06, David Brown ha scritto: >> On 20/11/2020 18:39, Tauno Voipio wrote: >> >>> I have had thousands of industrial instruments in the field for decades, >>> each running some internal units with I2C, some bit-banged and others >>> on the hardware interfaces on the processors used, and not a single >>> failure due to I2C hanging. >>> >> >> The only time I have seen I²C buses hanging is during development, when >> you might be re-starting the cpu in the middle of an operation without >> there being a power-on reset to the slave devices.  That can easily >> leave the bus in an invalid state, or leave a slave state machine out of >> synchronisation with the bus.  But I have not seen this kind of thing >> happen in a live system. > In the past I had a big problem with a I2C bus on a board. Ubiquitous > EEPROM 24LC64 connected to a 16-bits MCU by Fujitsu. In that case, I2C > was implemented by a bit-bang code. > > At startup MCU read the EEPROM content and if it was corrupted, factory > default are used and wrote to the EEPROM. This mechanism was introduced > to write a blank EEPROM at the very first power up of a fresh board. > > Unfortunately it sometimes happened that the MCU reset in the middle of > a I2C transaction with the EEPROM (the reset was caused by a glitch on > the power supply that triggered a MCU voltage supervisor). > When the MCU restarted, it tried to communicate with the EEPROM, but it > was in a not synchronized I2C state. This is well described in AN868[1] > from Analog Devices.. > > The MCU thoughts it was a blank EEPROM and factory settings was used, > overwriting user settings! What the user blamed was that the machine > sometimes restarted with factory settings, losing user settings. > > In that case the solution was adding a I2C reset procedure at startup > (some clock pulses and STOP condition as described in the Application > Note). > I think this I2C bus reset procedure must be always added where there's > a I2C bus and most probably it must be implemented by a big-bang code. > > > [1] > https://www.analog.com/media/en/technical-documentation/application-notes/54305147357414AN686_0.pdf >
Sure, add that kind of a reset at startup - it also helps if you are unlucky when restarting the chip during development. Also make sure you write two copies of the user data to the EEPROM, so that you can survive a crash while writing to it. But if your board is suffering power supply glitches that are enough to trigger the MCU brown-out, but not enough to cause a proper re-start of the rest of the board, then /that/ is a major problem that you should be trying to solve.
> >>> Please remember that the I2C bus is an Inter-IC bus, not to be used for >>> connections to the outside of the device, preferably only on the same >>> circuit board. There should be no external connectors where e.g. the >>> shorts between the SCL and SDA could happen. >>> >>> All the hardWare I2C controls have been able to be restored to a >>> sensible state with a software reset after a time-out. This includes >>> the Atmel chips. >>> >>