瑞萨单片机-硬件I2C从设备

开发环境


1、e2 studio
2、R5F1115AxFL

概述


1、网上关于I2C从机的资料很少,在这里分享下我在瑞萨单片机上实现I2C从机,根据主机发来的数据,从机返回或者保存数据
2、R5F1115AxFL最多支持3个从设备地址(即可以作为三个从设备)
3、从接收模式:直接将数据保存到RAM中,接收完再处理
4、从发送模式:按照I2C读取传感器数据经验,主机读取从设备时,从设备需要立刻返回数据的,但是程序要如何实现一收到指令就返回特定的数据?(时钟拉伸)这里先跳过,我们先实现返回固定的数据。

配置


配置

选择I2C从模式,生成代码后,我们把生成的中断处理函数给屏蔽掉,自己另外实现这些中断函数

从接收模式


1、工作流程
在这里插入图片描述

(1)从模式下,I2C会处于待机模式,直到地址检测到匹配
(2)当地址匹配时会在第九个时钟周期的上升沿将ICSR1.HOA, GCA和AASy
(y = 0 to 2)置1。AASy就是对应那个从设备地址匹配,根据这个位我就就可以做多从设备的识别了

在这里插入图片描述

(3)后面就不说了,自己看手册

从发送模式

在这里插入图片描述

在这里插入图片描述

重写I2C相关的中断函数

1、错误中断处理函数。处理起始条件中断、停止条件中断等

static void r_Config_RIIC0_error_interrupt(void)
{
	volatile uint8_t dummy;
	if ((1U == RIIC0.ICIER.BIT.ALIE) && (1U == RIIC0.ICSR2.BIT.AL))
	{

	}
	else if ((1U == RIIC0.ICIER.BIT.TMOIE) && (1U == RIIC0.ICSR2.BIT.TMOF))
	{
		//超时中断处理

	}
	else if ((1U == RIIC0.ICIER.BIT.NAKIE) && (1U == RIIC0.ICSR2.BIT.NACKF))
	{
		//NACK中断处理
		 dummy = RIIC0.ICDRR;
		while (1U != RIIC0.ICSR2.BIT.STOP)
		{
			nop();
		}
		RIIC0.ICSR2.BIT.NACKF = 0U;
		RIIC0.ICSR2.BIT.STOP = 0U;
		i2c_drv[i2c_dev.id].tx_cnt = 0;
	}
	else if (1U == RIIC0.ICSR2.BIT.STOP)	/* detect stop condition       */
    {
        /*After the ICSR2.STOP flag is confirmed to be 0 and the ICSR2.RDRF flag to be 1, dummy read the ICDRR register*/
        if (1 == RIIC0.ICSR2.BIT.RDRF)
            dummy = RIIC0.ICDRR;

        /*After checking that the ICSR2.STOP flag is 1, set the ICSR2.STOP flag to 0 for the next transfer operation*/
        RIIC0.ICSR2.BIT.NACKF = 0U;
        RIIC0.ICSR2.BIT.STOP = 0U;
		
		/*接收完成*/
        //i2c_drv[i2c_dev.id].rx_len = i2c_drv[i2c_dev.id].rx_cnt;
        //i2c_drv[i2c_dev.id].rx_cnt = 0;
        //i2c_dev.dummy = 0;
    }
    else
    {
    	if (1U == RIIC0.ICSR2.BIT.START)	 /* detect start condition     */
    	{
    		RIIC0.ICSR2.BIT.START = 0;
			//i2c_dev.dummy = 0;
    		while( 0 == RIIC0.ICSR2.BIT.RDRF)//等待第九个时钟中期到
    		{
    			nop();
    		}
			/*判断是哪个从设备和主机通信
			根据标志决定将接收的数据保存到哪个缓冲区,或者将哪个缓存的数据发送出去
			*/
    		if(1 == RIIC0.ICSR1.BIT.GCA || 1 == RIIC0.ICSR1.BIT.AAS0)
    		{
    			//从设备匹配0
    		}
    		else if(1 == RIIC0.ICSR1.BIT.AAS1)
    		{
    			//从设备匹配1
    		}
    		else if(1 == RIIC0.ICSR1.BIT.AAS2)
    		{
    			//从设备匹配2
    		}
    		i2c_dev.model = RIIC0.ICCR2.BIT.TRS;// 从设备处于发送还是接收模式
    	}

    }
}

2、发送中断

static void r_Config_RIIC0_transmit_interrupt(void)
{
	if(I2C_MODEL_TX == RIIC0.ICCR2.BIT.TRS)//发送模式
	{
		if(1 ==RIIC0.ICSR2.BIT.TDRE)//发送中断标志
		{
			//根据匹配地址决定将哪个缓冲区数据发送出去
			//RIIC0.ICDRT = i2c_drv[i2c_dev.id].pTbuf[i2c_drv[i2c_dev.id].tx_cnt];
			//i2c_drv[i2c_dev.id].tx_cnt++;
		}

	}
}

static void r_Config_RIIC0_transmitend_interrupt(void)
{
    volatile uint8_t dummy;

    //if(I2C_MODEL_TX == i2c_dev.model)
    {

        /* Dummy read to release SCL */
        dummy = RIIC0.ICDRR;

    }
}

3、接收中断

static void r_Config_RIIC0_receive_interrupt(void)
{
	uint8_t dummy;
	if(I2C_MODEL_RX == RIIC0.ICCR2.BIT.TRS)
	{
		if (0 == i2c_dev.dummy)
		{
			dummy = RIIC0.ICDRR;//i2c设备地址
			i2c_dev.dummy = 1;
			return;
		}
		RIIC0.ICMR3.BIT.ACKWP = 1U;
		RIIC0.ICMR3.BIT.ACKBT = 0U;
		//保存数据
		//i2c_drv[i2c_dev.id].pRbuf[i2c_drv[i2c_dev.id].rx_cnt] = RIIC0.ICDRR;
		//i2c_drv[i2c_dev.id].rx_cnt++;
	}
	else
	{
		dummy = RIIC0.ICDRR;
	}
}

clock strech时钟拉伸

参考网址https://blog.csdn.net/happygaohualei/article/details/52864694
在发送数据模式下,从设备可能还来不及准备数据,这时候就需要时钟拉伸,等数据准备好后再释放,让主机能继续接收数据(主机支持时钟拉伸功能)

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值