1. This forum section is a read-only archive which contains old newsgroup posts. If you wish to post a query, please do so in one of our main forum sections (here). This way you will get a faster, better response from the members on Motherboard Point.

I2C slave code example for an ATtiny26

Discussion in 'Embedded' started by Piotr Piatek, Mar 4, 2004.

  1. Piotr Piatek

    Piotr Piatek Guest

    Hello all,

    I'm trying to implement an I2C slave device using the Universal Serial
    Interface. The program kind of works, but sending any odd data (i.e.
    with the least significant bit set) through the I2C bus causes a start
    condition. Could anyone help with a working code example?

    My program is available here if anyone's interested:

    Thanks in advance

    Piotr Piatek, Mar 4, 2004
    1. Advertisements

  2. Piotr Piatek

    Gary Kato Guest

    The program kind of works, but sending any odd data (i.e.
    When the slave sends odd data or when the master sends odd data?

    I think you are sending ACK wrong. You seem to be doing
    sbi DDRB,SDA
    when you should be doing this
    sbi PORTB,SDA

    I could see this as being part of your problem. The data line during the ACK is
    possibly whatever bit was sent last. So, if a 0 bit was sent last, an ACK
    appears during the ACK clock pulse. If a 1 bit was sent last, a NACK appears
    during the ACK clock pulse.
    Gary Kato, Mar 5, 2004
    1. Advertisements

  3. Piotr Piatek

    Piotr Piatek Guest

    Sorry, I wasn't precise enough. When the master sends odd data the
    program detects a spurious start condition. I haven't tried receiving
    data from the slave.
    The SDA line in an I2C bus is of the open-collector or open-drain
    type, so an instruction SBI PORTB,SDA should never appear in the code.
    When sending data through the I2C bus, the PORTB,SDA signal should be
    fixed at 0, and only the SDA line direction should be controlled:

    sbi DDRB,SDA sends 0 to the SDA line
    cbi DDRB,SDA sends 1 to the SDA line

    This applies only when bit-banging the bus transfer in software.

    However, my sample code uses the USI to send ACK:

    1. write 0 to the USIDR (the 7-th bit of the USIDR will be sent to the
    SDA line)
    2. set the SDA line as output to enable the SDA driver
    3. write 0x0E to the 4-bit counter, so it generates an USI overflow
    interrupt after receiving of 2 SCL edges

    BTW, doing the transfer entirely in software was a much simpler task,
    but it eats microcontroller's resources. Here's my working and tested
    program simulating the PCF8574 expander chip:

    Thank you for your reply

    Piotr Piatek, Mar 5, 2004
  4. Piotr Piatek

    Gary Kato Guest

    When sending data through the I2C bus, the PORTB,SDA signal should be
    This is true if PORTB,SDA is fixed at 0, but it isn't in your slave_4.asm code.
    It will be whatever was the last bit that the master sent. So, if the last bit
    that the master sent was a 1, then you are sending back a NACK.
    Gary Kato, Mar 5, 2004
  5. Piotr Piatek

    Piotr Piatek Guest

    No, it doesn't work this way. Please notice that the transfer is done
    entirely in hardware using a dedicated shift register USIDR. The SDA
    pin isn't configured as a general purpose input/output, thus the
    PORTB,SDA state has no effect on this pin. The ACK bit sent to the
    master is determined by the value written to the USIDR register.

    Nevertheless you have put me on the right track. While testing if the
    slave sends ACK or NACK I noticed that the SCK pulses have wrong
    phase. It turned out that I didn't take into account the first falling
    SCK edge which occurs immediately after detecting of the start

    SDA=1, SCL=1 - initial bus state
    SDA=0, SCL=1 - start condition detected
    SDA=0, SCL=0 - the first SCL edge which incremented the 4-bit USI

    Seems that I got this working. Thank you very much for the

    Piotr Piatek, Mar 6, 2004
  6. Piotr Piatek

    Gary Kato Guest

    The SDA
    Not according to the ATTiny26 datasheet. Under Figure 43, it says:

    "1. The a start condition is generated by the master by forcing the SDA low
    line while
    the SCL line is high (A). SDA can be forced low either by writing a zero to bit
    7 of
    the Shift Register, or by setting the PORTB0 bit to zero. ..."

    Happy that I was of some service. I also learned from this. The only I2C I've
    done has been with a I2C controller that handled more of the low level details
    than the USI.
    Gary Kato, Mar 7, 2004
  7. Piotr Piatek

    Piotr Piatek Guest

    You're right, somehow I've missed this information. Thanks for
    pointing this out. However, it's still confusing to me. Does it mean
    that the state of the SDA output is an AND function of PORTB,SDA and
    the 7-th bit of the shift register? I've observed that the PORTB,SDA
    must be set to 1 directly before reading from the USIDR, otherwise I
    cannot shift out anything but zeroes.
    I'm new to the ATtiny26 as well, and there still remain unresolved

    Here's the latest version of my sample program simulating the PCF8574
    I2C expander (using the USI, of course):

    Best regards

    Piotr Piatek, Mar 7, 2004
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.