SOC系统经典IP介绍以及使用方法说明之dw_i2c

系列文章目录

第三章 DW_i2c功能及使用流程介绍


文章目录

前言

一、功能介绍

[1.1 i2c写操作:](#1.1 i2c写操作:)

[1.1.1 详细flow介绍](#1.1.1 详细flow介绍)

[1.2 i2c读操作:](#1.2 i2c读操作:)

[1.2.1 详细flow介绍](#1.2.1 详细flow介绍)

二、软件流程介绍

[2.1 定义WDT中断服务子程序](#2.1 定义WDT中断服务子程序)

[2.2 定义main函数](#2.2 定义main函数)

三、总结



前言

按照i2c的协议,i2c的时钟由master方提供,master可以向slave发送数据,也可以向slave请求数据。对应的slave既可以接收来自master发送的数据,也可以响应master请求数据。关于i2c协议,后续我们会单独讲解里面的细节和注意事项,这里我们主要接收使用过程中的一些基本配置flow。


一、功能介绍

这里简单介绍一下i2c读写过程涉及到flow:

1.1 i2c写操作:

1.1.1 详细flow介绍

step1:首先master发起i2c start,即在sclk高电平拉低sda;

step2:发送slave设备地址,与之通信,这个设备地址按照协议可以是7bit,也可以是10bit,这里介绍最简单的7bit模式。

step3:紧接着发送一个bit的写控制位,表示当前传输为一笔写操作。

step4:然后后续跟着两个byte的数据,这两个byte数据一般用于软件解析命令用,通常情况下收发双方可以利用这两个byte自定义一些私有协议,比如最简单的就是两个纯粹的mem地址0x1000,表示master即将向0x1000地址写数据,因此后续master发送过来的Data,需要软件将其搬运到系统mem 0x1000地址去。当然也可以将这两个byte拆分成多个不同的命令,方便系统灵活运用。

step5:然后是发送过来的真正的payload数据

step6:当master完成数据写传输后,发送stop,即在scl的高电平拉高sda,结束当前传输。

1.2 i2c读操作:

1.2.1 详细flow介绍

step1:首先master发起i2c start,即在sclk高电平拉低sda;

step2:发送slave设备地址,与之通信,这个设备地址按照协议可以是7bit,也可以是10bit,这里介绍最简单的7bit模式。

step3:紧接着发送一个bit的写控制位,表示当前传输为一笔写操作。

step4:然后后续跟着两个byte的数据,这两个byte数据一般用于软件解析命令用,通常情况下收发双方可以利用这两个byte自定义一些私有协议,比如最简单的就是两个纯粹的mem地址0x1000,表示master即将向0x1000地址写数据,因此后续master发送过来的Data,需要软件将其搬运到系统mem 0x1000地址去。当然也可以将这两个byte拆分成多个不同的命令,方便系统灵活运用。

step5:这里master发送了一个re_start操作,即在scl的高电平拉低了sda,而并非发送payload数据,这里其实是一个读的转身,当slave接收到re_start时,会认为master其实想读数据,访问的数据地址体现在2byte信息里。因此,此时软件需要从内存地址里取数据并加载到i2c tx fifo中;

step6:按照协议重新发送设备地址以及R控制bit,这里配合step5供软件解析读过程。

step7:slave会根据软件填写的tx fifo值,把数据发送出去。

step8:当master接收完数据后,发送stop,即在scl的高电平拉高sda,结束当前传输。

二、软件流程介绍

2.1 定义WDT中断服务子程序

中断handler定义:

cs 复制代码
int dw_i2c_int_handler()
{
   int rdata;
   rdata = REG32(I2C_INTR_STAT);  //read intr status
   //judge which intr bit trigger
   if((rdata & 0x1) == 0x1) //rx_under
     {
       rdata = REG32(I2C_CLR_RX_UNDER); //read clear
     }
   else if((rdata & 0x2) == 0x2) //rx_over
     {
       rdata = REG32(I2C_CLR_RX_OVER); //read clear
     }
   else if((rdata & 0x4) == 0x4) //rx_full
     {
       rdata = REG32(I2C_DATA_CMD); //read recv data
     }
   else if((rdata & 0x8) == 0x8) //tx_over
     {
       rdata = REG32(I2C_CLR_TX_OVER); //read clear
     }
   else if((rdata & 0x10) == 0x10) //tx_empty
     {
       REG32(I2C_DATA_CMD) = 0x12; //cpu initial data into tx fifo
     }
   else if((rdata & 0x20) == 0x20) //rd_req
     {
       REG32(I2C_CLR_RD_REQ); //clr stop
       REG32(I2C_DATA_CMD) = 0x12; //cpu initial data into tx fifo
     }
   else if((rdata & 0x40) == 0x40) //tx_abrt
     {
       rdata = REG32(I2C_CLR_TX_ABRT); //read clear
     }
   else if((rdata & 0x80) == 0x80) //rx_done
     {
       rdata = REG32(I2C_CLR_RX_DONE); //read clear
     }
   else if((rdata & 0x100) == 0x100) //activity
     {
       rdata = REG32(I2C_CLR_ACTIVITY); //read clear
     }
   else if((rdata & 0x200) == 0x200) //stop_det
     {
       REG32(I2C_CLR_STOP_DET); //clr stop
     }
}

这里是一个通用的中断handler,大家可以根据注释以及datasheet上的描述对此进行扩展,比如有些软件需要在tm_empty中断发生的时候CPU填写数据,以及fifo full中断的时候CPU需求将数据取走等等。具体还要根据实际应用情况来做扩展。

当然,对于EDA验证来说,这里相对来说更灵活,可以根据验证环境情况来自定义中断handler。

2.2 定义main函数

main函数

cs 复制代码
int main()
{
   CLK_DW_I2C_EN;   //打开i2c模块的时钟使能,根据设计需求
   
   //may be i2c share gpio with module, this cfg can be used 
   GPIO_FUNC_SEL_I2C;  //配置gpio功能为DW_I2C

   set_irq_vector(NVIC_NUM_DW_I2C, (int)dw_i2c_int_handler); //配置中断服务向量
   __nds32_enable_int(NVIC_NUM_DW_I2C); //使能CPU中断

   //dw i2c initial
   REG32(I2C_ENABLE)      = 0x0;  //在配置i2c之前一定要先disable i2c_en
   REG32(I2C_SDA_HOLD)    = 0x5;  //可选,具体参考datasheet描述
   REG32(I2C_FS_SPKEN)    = 0x2;  //滤除毛刺的深度,建议根据需求配置
   REG32(I2C_TX_TL)       = 0x4;  //tx fifo水线
   REG32(I2C_RX_TL)       = 0x4;  /rx fifo水线
   REG32(I2C_CON)         = (REG32(I2C_CON) & 0xFFFFFF80) | 0x65); //master mode and 400k
   REG32(I2C_FS_SCL_HCNT) = 0x6;  //scl高电平宽度配置,根据需求修改
   REG32(I2C_FS_SCL_LCNT) = 0x6;  //scl低电平宽度配置,根据需求修改

   
   REG32(I2C_ENABLE) = 0x1; //使能i2c
   
   //填写tx fifo数据,硬件会自动将数据发送出去,这里填数据也可以放到int_handler中
   REG32(I2C_DATA_CMD) = 0x12;
   REG32(I2C_DATA_CMD) = 0x34;
   REG32(I2C_DATA_CMD) = 0x56;
   ......

   while(发送中断完成);

}

上述main函数中,本文详细介绍了DW_i2c的初始化流程,里面的步骤基本上是必不可少的,当然,有一些配置可以根据实际情况进行调整,同时,如果使用i2c的更多功能,还需要大家自行添加相关寄存器配置。


三、总结

这里只是介绍了master发送的相关case配置,实际上DW_I2C可以配置为master/slave模式,且两个模式可以分别支持收发,即理论上来收还有其他三种case,master收数据,slave发数据以及slave收数据。在实际设计case时,关于数据的收发可以灵活调整,借助每个中断来进行同步收发是一个比较好的编码风格。这里为了让大家更容易理解,因此设计的case简单化了。

在实际验证过程中,不仅仅要根据需求设计严谨的case,还要同时控制收发双方的驱动程序,以及添加数据的自动化checker,这样后期在大量回归测试时,可以更快的完成回归测试。

相关推荐
学编程就要猛2 小时前
RAG(Retrieval Augmented Generation)
人工智能·spring ai
冬奇Lab2 小时前
一天一个开源项目(第259篇):Modern Web Guidance —— Chrome 团队给 AI 编码 Agent 的「现代 Web 最佳实践」外挂
人工智能·开源
菥蓂寻生3 小时前
STM32移植到GD32中以105为例
stm32·单片机·嵌入式硬件
§ꦿCFོ༉3 小时前
嵌入式八股文—C语言入门学习(四)
c语言·开发语言·学习
飞哥数智坊4 小时前
打造自己的 Personal Agent,从抄大肥鱼作业开始
人工智能·deepseek
投图匠4 小时前
十种不同风格的 CTP接口 框架
开发语言·python
对你无可奈何4 小时前
Magpie 实战:把 WorkBuddy、Qoder 的订阅模型接进一个本地池子
人工智能
Csvn4 小时前
每请求到底多少钱?把 Token 成本算成可观测指标(C01)
人工智能·aigc·agent
吴名氏.4 小时前
Java转AI Agent教程(第十三周)混合检索与重排
java·数据库·人工智能·ai·ai agent