在线时间104 小时
UID3338547
注册时间2017-1-28
NXP金币14
TA的每日心情 | 无聊 2021-12-29 19:06 |
---|
签到天数: 47 天 连续签到: 1 天 [LV.5]常住居民I
金牌会员
 
- 积分
- 1392
- 最后登录
- 2025-3-4
|
本帖最后由 day_day 于 2019-9-21 15:28 编辑
(一)I2C寄存器
iic寄存器主要有五个:
(I2C_A1) Address Register 1 ,高七位为数据位,保存I2C所用到的从地址
(I2C_F) Frequency Divider register ,SCL SDA 电平维持时间
(I2C_C1) Control Register 1 ,控制寄存器,包含I2C使能、中断使能、发送状态控制
(I2C_S) Status registerk ,状态寄存器,完成标志、中断标志、忙状态等
(I2C_D) Data I/O register , 数据寄存器,发送的数据写进来,接收的数据从这里读取
(二)I2C初始化配置 之 周期电平配置
1、首先我们看时钟源的情况
iic的时钟源没有在IIC章节中提及,但可以在时钟源章节的SCG_C2中找到:其第一位是控制IIC寄存器到busclk的时钟。
根据在uart帖子里面的分析,我们的时钟源应该是16m的。
2、周期与电平时间计算
周期与电平时间计算要根据I2C_F寄存器
该寄存器有两个配置:
【MULT】决定一个基础单元多少个时钟,如果这么说不好理解,先理解为“mul”这个变量
然后【ICR】的参数决定了SCL、SDA对应多少个基础单元,这个需要查表,每一个参数对应了一个数据。如果这么说不理解,那就把ICR理解为“SCL divider”这个变量。
表里面对【ICR】=1D,“SCL divider”=160.即占160个基础单元。如果MULT=2的话,一个基础单元占据4个“I2C module clock period”,这个应该是指BUSCLK时钟源的周期。
也就是这个配置下,16M时钟源下,SDA维持时间会保持在40ms,即25kHz。
数据手册提到,该IIC最高可以配置为100kHz,那么我们可以把【MULT】=0,即占据一个时钟单元。
(三)I2C初始化配置 之 控制寄存器配置
最基本的配置都在第一个控制寄存器I2C_C1。
第七位 IICEN 控制I2C使能
第六位 IICIE 控制I2C中断使能
第五位 MST 设置主从模式
第四位 TX 设置发送接收模式
第三位 TXAK
第二位 RSTA 重复启动
第一位 WUEN 唤醒使能
第0位 保留
初始化只需要使能I2C、设置为主模式、发送模式
- I2C_C1 = I2C_C1_IICEN_MASK // enable IIC
- | I2C_C1_MST_MASK // master
- | I2C_C1_TX_MASK;
复制代码
(四)I2C主模式
众所周知,I2C在空闲的时候SDA、SCL都是高电平。当SCL为高,SDA由高拉低,准备传输数据,就代表I2C传输开始了,此后SCL每一个脉冲传输一位。
对于NXP的芯片,通常都有专门的硬件单元,负责启动、传输、结束,此外还有个重复启动,这样有个好处就是,可以灵活配置各个阶段,一次启动能传输任意个字节。
1、起始标志(启动)
启动标志很容易激发,只需要往C1寄存器里面的MST位写1。以下为数据手册对MST位描述:
Master Mode Select
When MST is changed from 0 to 1, a START signal is generated on the bus and master mode is selected.
When this bit changes from 1 to 0, a STOP signal is generated and the mode of operation changes from
master to slave.
0 Slave mode
1 Master mode
由于官方库配置形式丰富,因此可以通过以下方式置位:
- I2C_C1_MST = 1;
- //OR
- I2C_C1 |= I2C_C1_MST_MASK;
复制代码
完成标志在标志位BUSY,该位的描述:
Indicates the status of the bus regardless of slave or master mode. This bit is set when a START signal is detected and cleared when a STOP signal is detected.
当开始信号出现后,BUSY置位,直到STOP信号完成,表明I2C总线在忙。
因此此时需要判断是否正式起始。
2、从地址(从模式专属)
从地址保存在I2C_A1寄存器里,有7位,最低位为读写位,可用于判断读写
Immediately after the START signal, the first byte of a data transfer is the slave address transmitted by the master. This address is a 7-bit calling address followed by an R/W bit. The R/W bit tells the slave the desired direction of data transfer.
• 1 = Read transfer: The slave transmits data to the master
• 0 = Write transfer: The master transmits data to the slave
3、发送数据
数据手册对发送数据的操作描写如下:
When successful slave addressing is achieved, data transfer can proceed on a byte-bybyte basis in the direction specified by the R/W bit sent by the calling master.
当向寄存器I2C_D写入数据时,发送开始。
我们需要等待其完成。无论是发送还是接受数据,都涉及两个状态标志位:
TCF 发送完成标志位,1为发送完成
IICIF 中断标志位,1为中断挂起
4、结束
清除MST、TX控制位
(五)DAC5571
板载IIC器件为TI的DAC5571,器件地址为100110x,最低位由A0口电平决定。板子电路中A0接地,因此地址为0x4C纯寄存器操作方式如下:
- void I2C_write_test(unsigned char addr, unsigned char byte_addr, unsigned char date)
- {
- char str_try[50] = "string is:";
- unsigned char temp;
-
- I2C_F = 0xBF;
- I2C_C1_IICEN = 1; //enable iic
- I2C_C1_TXAK = 0; //ack
-
- //start
- I2C_C1_TX = 1;
- I2C_C1_MST = 1;
- while(!I2C_S_BUSY);
-
- //write addr
- I2C_D = addr;
-
- //wait
- while((I2C_S & I2C_S_IICIF_MASK)==0);
- I2C_S_IICIF = 1;
-
- //write byte_addr
- I2C_D = byte_addr;
-
- //wait
- while((I2C_S & I2C_S_IICIF_MASK)==0);
- I2C_S_IICIF = 1;
- //write date
- I2C_D = date;
-
- //wait
- while((I2C_S & I2C_S_IICIF_MASK)==0);
- I2C_S_IICIF = 1;
-
- //stop
- I2C_C1_MST = 0;
- I2C_C1_TX = 0;
- while(I2C_S_BUSY)
-
- printf("finish");
- }
复制代码 调用该函数:
- I2C_write_test(0x98,0x04,0x50);
复制代码
可以看到波形:
已经有应答,测量J15的3脚和GND的电压,大概为0.89V。
256/76*3.3V=0.97V
中间存在一定参考电压的偏差。
(六)无法挂外部器件
事实上程序与帖子在两周前就已经完成了,但遇到了一个奇怪的现象迟迟未能解决——外部挂载的IIC器件无法工作!
我换过好几个IIC器件,包括ADXL345、MPU9250、以及一些IIC总线的数码管模块、从罗姆社区混来的几个IIC器件,无一例外无法驱动,所有杜邦线测试过、更换过,电压都测过,一切正常,但在同一程序下,只能驱动板载的DAC5571。
从上图可以看到,这是测试ADXL345的IIC总线,我把ADXL345可能的两个地址0xA6、0x3A都试了一遍,都没有ACK,但统一程序复用驱动DAC5571却有驱动!
猜测可能是DAC5571这个器件的IIC阻抗有点问题,导致其他IIC总线都无法被驱动。
查看了下数据手册,除了A2 A3以外,还有一条IIC总线B6 B7,但在这块板子上没有被引出,至此,可以判断这块板子的IIC总线基本成了摆设,除非用风枪把DAC5571吹下来,失去了IIC总线,我的机械臂计划就泡汤,因为IIC是闭环反馈至关重要的一环……
(七)猜测IIC的读函数
我还编写了IIC的读函数,但因为没有经过测试,所以无法判断该函数是否可行,这里也给出来供大家参考:
- void I2C_read_test(unsigned char addr, unsigned char byte_addr)
- {
- char str_try[50] = "string is:";
- unsigned char temp;
-
- // I2C_Init();
- I2C_F = 0xBF;
- I2C_C1_IICEN = 1; //enable iic
- I2C_C1_TXAK = 0; //ack
-
- //start
- // I2C_C1_MST = 0; //master mode off
- I2C_C1_TX = 1; //write
- I2C_C1_MST = 1; //master mode on, start signal
- while(!I2C_S_BUSY);
-
- //write addr
- I2C_D = addr;
-
- //wait
- while((I2C_S & I2C_S_IICIF_MASK)==0);
- I2C_S_IICIF = 1;
-
- //write byte_addr
- I2C_D = byte_addr;
-
- //wait
- while((I2C_S & I2C_S_IICIF_MASK)==0);
- I2C_S_IICIF = 1;
-
- DelayUS(1000);
-
- //restart
- I2C_C1_TXAK = 1;
- I2C_C1_RSTA = 1;
- //DelayUS(1000);
-
- //write addr
- I2C_D = addr+1;
-
- //wait
- while((I2C_S & I2C_S_IICIF_MASK)==0);
- I2C_S_IICIF = 1;
- //rec mode
- I2C_C1_TX = 0;
- // I2C_C1_TXAK = 1;
-
- //wait
- // while((I2C_S & I2C_S_IICIF_MASK)==0);
- // I2C_S_IICIF = 1;
-
- //?? rec
- temp = I2C_D;
- while((I2C_S & I2C_S_IICIF_MASK)==0);
- I2C_S_IICIF = 1;
- temp = I2C_D;
-
- while((I2C_S & I2C_S_IICIF_MASK)==0);
- I2C_S_IICIF = 1;
- temp = I2C_D;
-
- while((I2C_S & I2C_S_IICIF_MASK)==0);
- I2C_S_IICIF = 1;
- temp = I2C_D;
-
- //stop
- // i2c_Wait();
-
- I2C_Stop();
-
- sprintf(str_try,"\r\nrec:0x%x",temp);
- printf(str_try);
- }
复制代码
.
|
|