imx28 i2c PIO Queue Mode

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

imx28 i2c PIO Queue Mode

693 Views
liuxing
Contributor II

does imx286 i2c controller support PIO Queue mode.I want to disable interrupt in PIO Queue mode.however,i can't meter the sda and scl signal when i write/read i2c bus.

who can help me check the following code?

void I2COpen(UINT devId)

{

    HW_I2C_CTRL0_CLR(devId, BM_I2C_CTRL0_SFTRST);

    HW_I2C_CTRL0_CLR(devId, BM_I2C_CTRL0_CLKGATE);

  

    // asserting soft-reset

    HW_I2C_CTRL0_SET(devId, BM_I2C_CTRL0_SFTRST);

  

    // waiting for confirmation of soft-reset

    while (!HW_I2C_CTRL0(devId).B.CLKGATE);

    // Done.

  

    HW_I2C_CTRL0_CLR(devId, BM_I2C_CTRL0_SFTRST | BM_I2C_CTRL0_CLKGATE);

    // disable interrupts at the beginning

    HW_I2C_CTRL1_CLR(devId, BM_I2C_CTRL1_BCAST_SLAVE_EN |

                                   BM_I2C_CTRL1_BUS_FREE_IRQ_EN |

                                   BM_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ_EN |

                                   BM_I2C_CTRL1_SLAVE_STOP_IRQ_EN |

                                   BM_I2C_CTRL1_SLAVE_IRQ_EN |

                                   BM_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ_EN |

                                   BM_I2C_CTRL1_NO_SLAVE_ACK_IRQ_EN |

                                   BM_I2C_CTRL1_EARLY_TERM_IRQ_EN |

                                   BM_I2C_CTRL1_MASTER_LOSS_IRQ_EN

                                   );

    // Clear the CTRL0 register

    HW_I2C_CTRL0_CLR(devId, BM_I2C_CTRL0_RUN |

                                    BM_I2C_CTRL0_MULTI_MASTER |

                                    BM_I2C_CTRL0_CLOCK_HELD |

                                    BM_I2C_CTRL0_RETAIN_CLOCK |

                                    BM_I2C_CTRL0_PRE_SEND_START |

                                    BM_I2C_CTRL0_POST_SEND_STOP

                                    );

    // enable the clock

    HW_I2C_CTRL0_CLR(devId, BM_I2C_CTRL0_CLKGATE);

  //100k

    HW_I2C_TIMING0_WR(devId, 0x00780030); // high time = 120 clocks, read bit at 48 for 95KHz at 24mhz

    HW_I2C_TIMING1_WR(devId, 0x00800030); // low time at 128, write bit at 48 for 95 kHz at 24 MHz

    HW_I2C_TIMING2_WR(devId, 0x0015000D); // bus free count of 21 lead in count of 13

  

  HW_I2C_CTRL1_SET(devId, BM_I2C_CTRL1_ACK_MODE);

  HW_I2C_CTRL1_CLR(devId, 0x0000FF00);

  HW_I2C_QUEUECTRL_SET(devId,BM_I2C_QUEUECTRL_PIO_QUEUE_MODE);

  HW_I2C_CTRL0_SET(devId,BM_I2C_CTRL0_RUN);

  HW_I2C_QUEUECTRL_CLR(devId,BM_I2C_QUEUECTRL_QUEUE_RUN);

}

UINT I2CRead(BYTE SlaveAddr,BYTE subaddr,VOID *pBuffer,UINT32 size)

{

       UINT32 QueCmd = 0,RxSize = 0,RxCnt = 0;

       DWORD dwTickCnt = 0;

       DWORD *ptrRx = NULL;

       QueCmd = CMD_I2C_WRITE|BF_I2C_CTRL0_XFER_COUNT(3);

       HW_I2C_QUEUECMD_WR(I2C_INDEX,QueCmd);

       memset(TxBuf,0x00,100);

       TxBuf[0] = (SlaveAddr << 1)|I2C_WRITE;

       TxBuf[1] = subaddr;

       TxBuf[2] = SlaveAddr << 1)|I2C_READ;

       ptrRx = (DWORD *)&TxBuf[0];

       HW_I2C_DATA_WR(I2C_INDEX,*ptrRx);

       QueCmd = CMD_I2C_READ|BF_I2C_CTRL0_XFER_COUNT(size);

       QueCmd |= BM_I2C_QUEUECMD_POST_SEND_STOP;

       HW_I2C_QUEUECMD_WR(I2C_INDEX,QueCmd);

       HW_I2C_QUEUECTRL_SET(I2C_INDEX,BM_I2C_QUEUECTRL_QUEUE_RUN);

  ptrRx= (DWORD *)&RxBuf[0];

  RxSize = (size+3)/4;

  dwTickCnt = OALGetTickCountEx();

  while(RxSize)

  {

       if(OALGetTickCountEx()-dwTickCnt>1000)break;

       if(!(HW_I2C_QUEUESTAT_RD(I2C_INDEX)&BM_I2C_QUEUESTAT_RD_QUEUE_EMPTY))

      {

            *ptrRx = HW_I2C_QUEUEDATA_RD(I2C_INDEX);

            ptrRx++;

            RxSize--;

            RxCnt += 4;

       }

  }

   if(RxCnt)

  {

            RxCnt =(RxCnt>size)?size:RxCnt;

  }

       HW_I2C_QUEUECTRL_CLR(I2C_INDEX,BM_I2C_QUEUECTRL_QUEUE_RUN);

       memcpy(pBuffer,&RxBuf[0],RxCnt);

       return RxCnt;

}

//////////////////////

after set HW_I2C_QUEUECTRL.QUEUE_RUN

HW_I2C_QUEUESTAT = 0x00002048

HW_I2C_QUEUECMD = 0x00120001

Labels (1)
0 Kudos
2 Replies

478 Views
Pavel
NXP Employee
NXP Employee

Look at the Section 27.3.1 of the MCIMX28 Reference Manual:

http://cache.freescale.com/files/dsp/doc/ref_manual/MCIMX28RM.pdf?fasp=1&WT_TYPE=Reference%20Manuals...

This Section contains recommended command sequence for the i.MX28 I2C in PIO mode.

Check your command sequence using this Section.


Have a great day,
Pavel

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos

478 Views
liuxing
Contributor II

Hi,I think you misunderstand my question,I want to implement the PIO Queue Mode,not  PIO mode.I think the PIO Queue mode can handle without DMA.

please refer to section 27.3.2 of the MCIMX28RM.

some codes in linux i2c driver:

static void hw_i2c_pioq_setup_read(struct mxs_i2c_dev *dev,
       u8 addr, void *buff, int len, int flags)
{
u32 queuecmd;
u32 queuedata;

WARN_ONCE(len > 24, "choose DMA mode if xfer len > 24 bytes\n");

/* fill queue cmd */
queuecmd = CMD_I2C_SELECT;
__raw_writel(queuecmd, dev->regbase + HW_I2C_QUEUECMD);

/* fill data (slave addr) */
queuedata = (addr << 1) | I2C_READ;
__raw_writel(queuedata, dev->regbase + HW_I2C_DATA);

/* fill queue cmd */
queuecmd = CMD_I2C_READ | flags;
queuecmd |= BF_I2C_CTRL0_XFER_COUNT(len) | flags;
__raw_writel(queuecmd, dev->regbase + HW_I2C_QUEUECMD);

}

static void hw_i2c_pioq_setup_write(struct mxs_i2c_dev *dev,
        u8 addr, void *buff, int len, int flags)
{
int align_len, i;
u8 slaveaddr;
u32 queuecmd;
u8 *buf1;
u32 *buf2;

WARN_ONCE(len > 24, "choose DMA mode if xfer len > 24 bytes\n");

align_len = (len + 1 + 3) & ~3;

buf1 = (u8 *) dev->buf;
buf2 = (u32 *) dev->buf;

/* fill queue cmd */
queuecmd = CMD_I2C_WRITE;
queuecmd |= BF_I2C_CTRL0_XFER_COUNT(len + 1) | flags;
__raw_writel(queuecmd, dev->regbase + HW_I2C_QUEUECMD);

/* fill data (slave addr) */
slaveaddr = (addr << 1) | I2C_WRITE;
memcpy(buf1, &slaveaddr, 1);

memcpy(&buf1[1], buff, len);

/* fill data */
for (i = 0; i < align_len / 4; i++)
  __raw_writel(*buf2++, dev->regbase + HW_I2C_DATA);
}

static void hw_i2c_pioq_run(struct mxs_i2c_dev *dev)

{

__raw_writel(0x20, dev->regbase + HW_I2C_QUEUECTRL_SET);

}

0 Kudos