i2c框架


title: iic框架
tags: ARM
date: 2018-11-05 13:44:58

i2c框架

寄存器

mark

mark

mark

/* 配置引脚用于I2C*/
GPECON &= ~((3<<28) | (3<<30));
GPECON |= ((2<<28) | (2<<30));

/* 设置时钟 */
/* [7] : IIC-bus acknowledge enable bit, 1-enable in rx mode
	 * [6] : 时钟源, 0: IICCLK = fPCLK /16; 1: IICCLK = fPCLK /512
	 * [5] : 1-enable interrupt
	 * [4] : 读出为1时表示中断发生了, 写入0来清除并恢复I2C操作
	 * [3:0] : Tx clock = IICCLK/(IICCON[3:0]+1).
	 * Tx Clock = 100khz = 50Mhz/16/(IICCON[3:0]+1)
	 */
IICCON = (1<<7) | (0<<6) | (1<<5) | (30<<0);

中断配置: IIC没有次中断源.直接配置INTMSK即可INTMSK &= ~(1<<27);

主机发送

mark

int do_master_tx(p_i2c_msg msg)
{
	p_cur_msg = msg;
	
	msg->cnt_transferred = -1;
	msg->err = 0;
	
	/* 设置寄存器启动传输 */
	/* 1. 配置为 master tx mode */
	IICCON |= (1<<7); /* TX mode, 在ACK周期释放SDA */
	IICSTAT = (1<<4);
		
	/* 2. 把从设备地址写入IICDS */
	IICDS = msg->addr<<1;
	
	/* 3. IICSTAT = 0xf0 , 数据即被发送出去, 将导致中断产生 */
	IICSTAT = 0xf0;
	

	/* 后续的传输由中断驱动 */

	/* 循环等待中断处理完毕 */
	while (!msg->err && msg->cnt_transferred != msg->len);

	if (msg->err)
		return -1;
	else
		return 0;
}

主机接收

mark

int do_master_rx(p_i2c_msg msg)
{
	p_cur_msg = msg;

	msg->cnt_transferred = -1;
	msg->err = 0;
	
	/* 设置寄存器启动传输 */
	/* 1. 配置为 Master Rx mode */
	IICCON |= (1<<7); /* RX mode, 在ACK周期回应ACK */
	IICSTAT = (1<<4);
		
	/* 2. 把从设备地址写入IICDS */
	IICDS = (msg->addr<<1)|(1<<0);
	
	/* 3. IICSTAT = 0xb0 , 从设备地址即被发送出去, 将导致中断产生 */
	IICSTAT = 0xb0;
	

	/* 后续的传输由中断驱动 */

	/* 循环等待中断处理完毕 */
	while (!msg->err && msg->cnt_transferred != msg->len);

	if (msg->err)
		return -1;
	else
		return 0;
}

中断处理

注意

  1. 连续读的最后一个字节不响应ack,以用来终止读.
  2. 在读写第一个字节的时候,判断是否有ack来判断是否设备存在

mark

if (p_cur_msg->flags == 0)	/* write */
{
    /* 对于第1个中断, 它是发送出设备地址后产生的
		 * 需要判断是否有ACK
		 * 有ACK : 设备存在
		 * 无ACK : 无设备, 出错, 直接结束传输
		 */
    if (p_cur_msg->cnt_transferred == 0)  /* 第1次中断 */
    {
        if (iicstat & (1<<0))
        { /* no ack */
            /* 停止传输 */
            IICSTAT = 0xd0;
            IICCON &= ~(1<<4);//挂起标志
            p_cur_msg->err = -1;
            printf("tx err, no ack

");
            delay(1000);
            return;
        }
    }

    if (p_cur_msg->cnt_transferred < p_cur_msg->len)
    {
        /* 对于其他中断, 要继续发送下一个数据
			 */
        IICDS = p_cur_msg->buf[p_cur_msg->cnt_transferred];
        IICCON &= ~(1<<4);//挂起标志
    }
    else
    {
        /* 停止传输 */
        IICSTAT = 0xd0;
        IICCON &= ~(1<<4);//挂起标志
        delay(1000);
    }
}

/* 对于第1个中断, 它是发送出设备地址后产生的
 * 需要判断是否有ACK
 * 有ACK : 设备存在, 恢复I2C传输, 这样在下一个中断才可以得到第1个数据
 * 无ACK : 无设备, 出错, 直接结束传输
 */
if (p_cur_msg->cnt_transferred == 0)  /* 第1次中断 */
{
	if (iicstat & (1<<0))
	{ /* no ack */
		/* 停止传输 */
		IICSTAT = 0x90;
		IICCON &= ~(1<<4);
		p_cur_msg->err = -1;
		printf("rx err, no ack

");
		delay(1000);
		return;
	}
	else  /* ack */
	{
		/* 如果是最后一个数据, 启动传输时要设置为不回应ACK */
		/* 恢复I2C传输 */
		if (isLastData())
		{
			resume_iic_without_ack();
		}
		else
		{
			resume_iic_with_ack();
		}
		return;
	}
}

/* 非第1个中断, 表示得到了一个新数据
 * 从IICDS读出、保存
 */
if (p_cur_msg->cnt_transferred < p_cur_msg->len)
{
	index = p_cur_msg->cnt_transferred - 1;
	p_cur_msg->buf[index] = IICDS;

	/* 如果是最后一个数据, 启动传输时要设置为不回应ACK */
	/* 恢复I2C传输 */
	if (isLastData())
	{
		resume_iic_without_ack();
	}
	else
	{
		resume_iic_with_ack();
	}
}
else
{
	/* 发出停止信号 */
	IICSTAT = 0x90;
	IICCON &= ~(1<<4);//清标志
	delay(1000);
}


程序框架

mark

img

原文地址:https://www.cnblogs.com/zongzi10010/p/10023645.html