Question on using MPC8306 as i2c slave

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 

Question on using MPC8306 as i2c slave

989 次查看
jiaguo
Contributor II

Hi buddies,

I'm developing an i2c slave driver using linux 2.6.34 on MPC8306.

In my test, I use a RS232-to-I2C adapter connected to PC as the i2c master.

When doing master receive and slave transmit, when the last byte has been xfered,

the slave always pull the I2C_SDA low and doesn't release the i2c bus,

STOP can't be received. The datasheet seems doesn't make it clear that how to

release I2C_SDA. Is there anybody facing the same issue?

Please help, thanks in advance.:smileysilly:

As the i2c protocol says, no ACK on the last byte transmit before STOP, and I found

I2CnSR register RXAK bit set, which mean no ACK is received. So, I think the slave

hang the bus and waiting for ACK from master.

Below is my i2c slave driver interrupt routine.

static irqreturn_t fsl_i2cli_irq_handler(int irq, void *device_id)

{

    struct fsl_i2cli_priv *i2cli = device_id;

    if (i2cli != fsl_i2cli)

        return IRQ_HANDLED;

    if ((readb(i2cli->base + MPC_I2C2SR) & I2C2SR_MIF) == 0)

        return IRQ_HANDLED;

    /* If we are addressed as slave, check I2CnSR[SRW] and

       set I2CnCR[MTX] accordingly */

    if (readb(i2cli->base + MPC_I2C2SR) & I2C2SR_MAAS) {

        int tmp;

        u8 cr, x;

        PDEBUG("#### Addressed as an i2c slave ####\n");

          

        tmp = readb(i2cli->base + MPC_I2C2SR) & I2C2SR_SRW;

        i2cli->mode = tmp > 0 ? 1 : 0;

        PDEBUG("xfer mode: %s\n", (i2cli->mode == 0 ?

                "Slave receive" : "Slave transmit"));

        cr = readb(i2cli->base + MPC_I2C2CR);

        if (i2cli->mode == 0)

            writeb((cr & ~I2C2CR_MTX), i2cli->base + MPC_I2C2CR);

        else if (i2cli->mode == 1)

            writeb((cr | I2C2CR_MTX), i2cli->base + MPC_I2C2CR);

        writeb(0, i2cli->base + MPC_I2C2SR);

        /* dummy read on first byte */

        x = readb(i2cli->base + MPC_I2C2DR);

        PDEBUG("Dummy read x: 0x%02x\n", x);

    }

    /* Set by the falling edge of the 9th clock of a byte transfer */

    if (readb(i2cli->base + MPC_I2C2SR) & I2C2SR_MCF) {

        PDEBUG("Data xfered\n");

      

        writeb(0, i2cli->base + MPC_I2C2SR);

        /* If it's ACK on Master START command, do a dummy read */

        if (!i2cli->f_ack_on_start) {

            readb(i2cli->base + MPC_I2C2DR);

            i2cli->f_ack_on_start = 1;

            goto verify_mbb;

        }

  

        /* Data xfer buffer is full */  

        if ((i2cli->mode == 0) &&

                (i2cli->buf_ptr - i2cli->buf >= I2CLI_XFER_BUF_SIZE)) {

            i2cli->xfer_done = 1;

            wake_up_interruptible(&i2cli->wait_qh);

            goto end;

        }

        /* No more data to xfer in slave transmit mode */

        if ((i2cli->mode == 1) && (i2cli->buf_ptr - i2cli->buf >= i2cli->size)) {

            i2cli->xfer_done = 1;

            wake_up_interruptible(&i2cli->wait_qh);

            goto end;

        }

        if (i2cli->mode == 0) {

            /* Slave receive */

            u8 data = readb(i2cli->base + MPC_I2C2DR);

            PDEBUG("Read data: 0x%02x\n", data);

            PDEBUG("buf: %p, buf_ptr: %p\n", i2cli->buf, i2cli->buf_ptr);

            i2cli->size++;

            *i2cli->buf_ptr++ = data;

        } else {

            /* Slave transmit */

            writeb(*i2cli->buf_ptr, i2cli->base + MPC_I2C2DR);

            PDEBUG("Write data: 0x%02x\n", *i2cli->buf_ptr);

            PDEBUG("buf: %p, buf_ptr: %p\n", i2cli->buf, i2cli->buf_ptr);

            i2cli->buf_ptr++;

        }

    }

verify_mbb:

  

    /* If a STOP condition is detected, I2CnSR[MBB] is cleared,

     * Seems only make effect in case of slave receive */

    if ((readb(i2cli->base + MPC_I2C2SR) & I2C2SR_MBB) == 0) {

        PDEBUG("Stoped\n");

        i2cli->xfer_done = 1;

        wake_up_interruptible(&i2cli->wait_qh);

    }

end:

    return IRQ_HANDLED;

}

Message was edited by: Jia Guo

标记 (2)
0 项奖励
回复
0 回复数