Electronic – use an ATtiny84 as SPI slave and i2c master in the same application

attinyi2cspi

I'm designing a board using the ATtiny84A which uses a USI (Universal Serial Interface), and as such there is no dedicated I2C and SPI peripheral.

I have gotten I2C to work and tested it by communicating with a 24AA02UID EEPROM.

I have gotten Slave SPI to work and have tested it by returning requested data to a master.

My question is: if the ATtiny has no control over if/when the master decides to start an SPI transaction, is it possible to use these same USI pins to query the EEPROM over i2c?

enter image description here

I'm guessing that allowing the external SPI master to use the i2c pins that are attached to the EEPROM willy-nilly is going to cause strange data to appear on the EEPROM if/when the master happens to send a byte corresponding to the i2c address of the EEPROM chip, followed by other random data.

Or, am I worrying too much? I was hoping that the SPI signals would be disregarded by the EEPROM due to improper i2c protocol formatting.

The problem of the external SPI master taking control of the lines during a i2c communication sequence is troubling, however.

Is the best solution to use a tristate buffer that my ATtiny84a can toggle to cut off the external SPI master from the lines in question whenever it wants to read/write to the EEPROM?

EDIT:

It would seem that the cheapest and easiest and most awesomest solution is to simply use a different ATtiny chip. I think I will go with the ATtiny88 which has a dedicated TWI and SPI port (on separate pins):

enter image description here

Best Answer

You properly identified the biggest problem - SPI host might try driving clock/data line up while I2C master or slave pulling it down.

The second problem is timing, because SPI request can come in the middle of I2C packet. What happens next depends on particular I2C slave. It might either ignore the data, wait for next clock cycle, wait for stop condition or simply do something weird/unexpected.

The easiest solution would be already suggested separation of the channels and bit-banging I2C. However this is only possible if you have 2 pins and processor time available, and slower I2C speed is acceptable.

If the above does not work for you, some additional hardware is necessary. Specifically, you need two 3-state gates to disconnect SCK and MOSI lines coming from SPI master, and one more gate to disconnect SCL input of I2C slave (when SPI gates are open). This is the solution you already described in your question and it will work, to a point. The potential problem here is that SPI master not knowing that you are not listening will accept whatever state you have on MISO line as valid reply.

If CS line from master is available and you want to be more master-friendly you can try to use I2C clock stretching as a way to pause I2C transaction to handle SPI request. The idea is to put latches on I2C bus to "freeze" the signals coming from attiny at the moment CS line is activated. Several things will happen then:

  • the SCL and SDA coming from attiny will stop where they were;
  • the ISR in attiny will reprogram USI to SPI;
  • in the end it will open SCK and MOSI gates and handle incoming request.

When CS line is released the attiny will close SPI gates, generate "stop" condition for I2C slave, and reprogram USI back. This is very complicated scenario and some slave devices might not like it (master clock stretching was deprecated in recent specifications).

In short - if you can use bit-banging, use it. If not - be prepared for some extensive tinkering.