1.1 I2C位传输
1.3 I2C应答信号
写寄存器的标准流程为:
1.
2.
3.
4.
5.
6.
7.
8.
9.
写一个寄存器
读寄存器的标准流程为:
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
读一个寄存器
Mpc8560的CCSR中控制I2C的寄存器共有6个。
2.1 I2CADR 地址寄存器
CPU也可以是I2C的Slave,CPU的I2C地址有 I2CADR指定用来设置I2C总线频率
2.3 I2CCR 控制寄存器
MEN: Module Enable.
MIEN:Module Interrupt Enable. 置1时,I2C中断使能。
MSTA:Master/slave mode. 1 Master mode,0 Slave mode.
MTX:Transmit/receive mode select.0 Receive mode,1 Transmit mode
TXAK:Transfer acknowledge. 置1时,CPU在9th clock发送ACK拉低SDA
RSTA:Repeat START. 置1时,CPU发送REPEAT START
BCST:置1,CPU接收广播信息(信息的slave addr为7个0)
2.4 I2CSR 状态寄存器
MAAS:当CPU作为Slave时,若I2CDR与会话中Slaveaddr匹配,此bit被置1
MBB:0 I2C bus idle
MAL:若置1,表示仲裁失败
BCSTM:若置1,表示接收到广播信息
SRW:When MAAS is set, SRW indicates the value of the R/W command bit of the calling address, which is sent from the master.
MIF:Module interrupt. The MIF bit is set when an interrupt is pending, causing a processor interrupt request(provided I2CCR[MIEN] is set)
RXAK:若置1,表示收到了ACK
2.5 I2CDR 数据寄存器
这个寄存器储存CPU将要传输的数据。
3. PPC-Linux中I2C的实现
- static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
- {
struct i2c_msg *pmsg; int i; int ret = 0; unsigned long orig_jiffies = jiffies; struct mpc_i2c *i2c = i2c_get_adapdata(adap); mpc_i2c_start(i2c); // 设置I2CCR[MEN], 使能I2C module //一直读I2CSR[MBB],等待I2C总线空闲下来 while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) { if (signal_pending(current)) { pr_debug("I2C: Interruptedn"); writeccr(i2c, 0); return -EINTR; } if (time_after(jiffies, orig_jiffies + HZ)) { pr_debug("I2C: timeoutn"); if (readb(i2c->base + MPC_I2C_SR) == (CSR_MCF | CSR_MBB | CSR_RXAK)) mpc_i2c_fixup(i2c); return -EIO; } schedule(); } for (i = 0; ret >= 0 && i < num; i++) { pmsg = &msgs[i]; pr_debug("Doing %s %d bytes to 0xx - %d of %d messagesn", pmsg->flags & I2C_M_RD ? "read" : "write", pmsg->len, pmsg->addr, i + 1, num); //根据消息里的flag进行读操作或写操作 if (pmsg->flags & I2C_M_RD) ret = mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i); else ret = mpc_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i); } mpc_i2c_stop(i2c); //保证为I2CCSR[MSTA]为0,保证能触发STOP return (ret < 0) ? ret : num; - }
- static int mpc_write(struct mpc_i2c *i2c, int target,
const u8 * data, int length, int restart) - {
int i; unsigned timeout = i2c->adap.timeout; u32 flags = restart ? CCR_RSTA : 0; //以防万一,保证I2C模块使能起来 if (!restart) writeccr(i2c, CCR_MEN); //写了I2CCR[CCR_MSTA],触发CPU发起START信号 writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags); //CPU发送一个字节,slave I2C addr和0 (写操作bit) writeb((target << 1), i2c->base + MPC_I2C_DR); if (i2c_wait(i2c, timeout, 1) < 0) //等待slave 发ACK return -1; for (i = 0; i < length; i++) { writeb(data[i], i2c->base + MPC_I2C_DR); //CPU接着发数据,包括reg addr和data if (i2c_wait(i2c, timeout, 1) < 0) //等待slave 发ACK return -1; } return 0; - }
- static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
- {
unsigned long orig_jiffies = jiffies; u32 x; int result = 0; if (i2c->irq == 0) { //循环读I2CSR,直到I2CSR[MIF]置1 while (!(readb(i2c->base + MPC_I2C_SR) & CSR_MIF)) { schedule(); if (time_after(jiffies, orig_jiffies + timeout)) { pr_debug("I2C: timeoutn"); writeccr(i2c, 0); result = -EIO; break; } } x = readb(i2c->base + MPC_I2C_SR); writeb(0, i2c->base + MPC_I2C_SR); } else { result = wait_event_interruptible_timeout(i2c->queue, (i2c->interrupt & CSR_MIF), timeout * HZ); if (unlikely(result < 0)) { pr_debug("I2C: wait interruptedn"); writeccr(i2c, 0); } else if (unlikely(!(i2c->interrupt & CSR_MIF))) { pr_debug("I2C: wait timeoutn"); writeccr(i2c, 0); result = -ETIMEDOUT; } x = i2c->interrupt; i2c->interrupt = 0; } if (result < 0) return result; if (!(x & CSR_MCF)) { pr_debug("I2C: unfinishedn"); return -EIO; } if (x & CSR_MAL) { //仲裁失败 pr_debug("I2C: MALn"); return -EIO; } if (writing && (x & CSR_RXAK)) {//写后没收到ACK pr_debug("I2C: No RXAKn"); writeccr(i2c, CCR_MEN); return -EIO; } return 0; - }
- static int mpc_read(struct mpc_i2c *i2c, int target,
u8 * data, int length, int restart) - {
unsigned timeout = i2c->adap.timeout; int i; u32 flags = restart ? CCR_RSTA : 0; //以防万一,保证I2C模块使能 if (!restart) writeccr(i2c, CCR_MEN); //注意这里,再次把CCR_MSTA置1,再触发 START writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags); //CPU发送slave I2C addr和读操作1 writeb((target << 1) | 1, i2c->base + MPC_I2C_DR);
if (i2c_wait(i2c, timeout, 1) < 0) return -1; if (length) { if (length == 1) writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK); else //为什么不置 TXAK writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA); readb(i2c->base + MPC_I2C_DR); } for (i = 0; i < length; i++) { if (i2c_wait(i2c, timeout, 0) < 0) return -1; //注意这里TXAK置1,表示CPU每收到1byte数据后,会发送ACK if (i == length - 2) writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK); //注意这里CCR_MSTA [1->0] CPU会触发STOP if (i == length - 1) writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_TXAK); data[i] = readb(i2c->base + MPC_I2C_DR); } return length; - }
上一篇:白话现场总线
下一篇:PROFIBUS-DP总线连接器终端电阻的作用
推荐阅读最新更新时间:2024-05-02 23:52