I want to implement the SMBUS protocol in my AVR device (ATMega1284P), which will have the role of slave. I need to support the PEC (Packet Error Code) feature, which means that the master device (which is not mine) will send a "checksum" byte after the last byte of its command, to which I need to respond with ACK or NACK depending on its validity.

I have some experience with I²C/SMBUS/TWI as I used it before, but it seems I can't solve this particular problem. Apparently, with AVR's TWI implementation I need to decide for ACK or NACK in the byte received prior to the PEC value; i.e., in response to a previous TWSR = 0x80 (data has been received). The problem is, I don't know in advance if the PEC I will be receiving next will be valid or not! Apparently setting or clearing the TWEA bit is only effective for the next byte to be received. Example:

1 - ME     = Prepare for TWI slave operation; set address and ACK
2 - MASTER = Writes SLA+W (gets ACK from step #1)
3 - ME     = INT with TWSR 0x60; Sets ACK/NACK for next byte (ACK)
4 - MASTER = Sends Byte (gets ACK/NACK from step #3)
5 - ME     = INT with TWSR 0x80; Sets ACK/NACK for next byte (ACK)
6 - MASTER = Sends Byte (gets ACK/NACK from step #5)
7 - ME     = INT with TWSR 0x80; Sets ACK/NACK for next byte (ACK)
8 - MASTER = Sends PEC Byte (gets ACK/NACK from step #7)
9 - ME     = INT with TWSR 0x80 (PEC); too late to ACK/NACK PEC value!

As you can see, I should decide for ACK/NACK in step #9, but the master's already got an ACK set at step #7!

As much as I digged into the docs, I cannot find a way to respond with NACK "on the fly" because the ATMega sets the interrupt AFTER sending the ACK (or NACK). TWSR will be either 0x80 or 0x88, which means "byte received, ACK sent" and "byte received, NACK sent" respectively.

Aside from implementing a bit-banging SMBUS library, is there some way to solve this?

Thank you.


This is the main problem with trying to do SMBUS slave with PEC in software. And it is in fact mentioned in the standards as well as one of the reasons that PEC is not mandatory, but strongly suggested.

That means a master may not assume, by suggested best practise in the standard, that a slave sending an ACK in the last byte actually indicated the PEC was coded successfully. The only thing mandatory is that if a PEC is sent and it is invalid, the data must be discarded.

The only reliable way to do PEC and NACK as you want is if you have hardware support for either CRC8-CCITT (the PEC polynomial is the CCITT poly) or SMBUS, or preferably both.

Your chosen MCU cannot be made to do hardware I2C and also let you decide on the ACK bit last minute. That's just not something enough people want to put into every microcontroller. In 9 out of 10 cases the fact the slave expects another byte is enough to ACK. Or possibly 99 out of a 100 even.

You could hack it in hardware so that you can "NACK" just in time with an extra IO pin, but that would mean you need to make your CRC very efficient, or you'll be too late.

  • \$\begingroup\$ So, a bit-banging solution! :( \$\endgroup\$ – Guillermo Prandi Mar 2 '17 at 20:07

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