查看: 2153|回复: 0

NXPS08P试用 IIC

[复制链接]
  • TA的每日心情
    无聊
    2021-12-29 19:06
  • 签到天数: 47 天

    连续签到: 1 天

    [LV.5]常住居民I

    49

    主题

    188

    帖子

    21

    金牌会员

    Rank: 6Rank: 6

    积分
    1392
    最后登录
    2025-3-4
    发表于 2019-9-21 15:28:21 | 显示全部楼层 |阅读模式
    本帖最后由 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寄存器
    KF(%]4F_55{RJHM6@W13%UH.png
    该寄存器有两个配置:
    【MULT】决定一个基础单元多少个时钟,如果这么说不好理解,先理解为“mul这个变量
    H82Y9)72Y@G_CV~51VZQ4`E.jpg
    然后【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,即占据一个时钟单元。
    1. I2C_F  = 0x1D;
    复制代码






    (三)I2C初始化配置 之 控制寄存器配置
    最基本的配置都在第一个控制寄存器I2C_C1。
    第七位 IICEN 控制I2C使能
    第六位 IICIE 控制I2C中断使能
    第五位 MST  设置主从模式
    第四位 TX   设置发送接收模式
    第三位 TXAK
    第二位 RSTA  重复启动
    第一位 WUEN  唤醒使能
    第0位  保留



    初始化只需要使能I2C、设置为主模式、发送模式
    1. I2C_C1 = I2C_C1_IICEN_MASK      // enable IIC
    2.                 | I2C_C1_MST_MASK       // master
    3.                 | 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

    由于官方库配置形式丰富,因此可以通过以下方式置位:
    1. I2C_C1_MST = 1;
    2. //OR
    3. 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总线在忙。
    因此此时需要判断是否正式起始。
    1. while(!I2C_S_BUSY)
    复制代码



    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纯寄存器操作方式如下:
    1. void I2C_write_test(unsigned char addr, unsigned char byte_addr, unsigned char date)
    2. {
    3.         char str_try[50] = "string is:";
    4.         unsigned char temp;
    5.                
    6.         I2C_F  = 0xBF;
    7.         I2C_C1_IICEN = 1;        //enable iic
    8.         I2C_C1_TXAK = 0;        //ack
    9.        
    10.         //start
    11.         I2C_C1_TX = 1;
    12.         I2C_C1_MST = 1;
    13.         while(!I2C_S_BUSY);
    14.        
    15.         //write addr
    16.         I2C_D = addr;
    17.        
    18.         //wait
    19.         while((I2C_S & I2C_S_IICIF_MASK)==0);
    20.         I2C_S_IICIF = 1;
    21.        
    22.         //write byte_addr
    23.         I2C_D = byte_addr;
    24.                
    25.         //wait
    26.         while((I2C_S & I2C_S_IICIF_MASK)==0);
    27.         I2C_S_IICIF = 1;

    28.         //write date
    29.         I2C_D = date;
    30.        
    31.         //wait
    32.         while((I2C_S & I2C_S_IICIF_MASK)==0);
    33.         I2C_S_IICIF = 1;
    34.        
    35.         //stop
    36.         I2C_C1_MST = 0;
    37.         I2C_C1_TX = 0;
    38.         while(I2C_S_BUSY)
    39.        
    40.         printf("finish");
    41. }
    复制代码
    调用该函数:
    1. I2C_write_test(0x98,0x04,0x50);
    复制代码

    可以看到波形:
    1.png


    已经有应答,测量J15的3脚和GND的电压,大概为0.89V。
    256/76*3.3V=0.97V
    中间存在一定参考电压的偏差。


    (六)无法挂外部器件
    事实上程序与帖子在两周前就已经完成了,但遇到了一个奇怪的现象迟迟未能解决——外部挂载的IIC器件无法工作!
    我换过好几个IIC器件,包括ADXL345、MPU9250、以及一些IIC总线的数码管模块、从罗姆社区混来的几个IIC器件,无一例外无法驱动,所有杜邦线测试过、更换过,电压都测过,一切正常,但在同一程序下,只能驱动板载的DAC5571。
    2.png


    从上图可以看到,这是测试ADXL345的IIC总线,我把ADXL345可能的两个地址0xA6、0x3A都试了一遍,都没有ACK,但统一程序复用驱动DAC5571却有驱动!
    猜测可能是DAC5571这个器件的IIC阻抗有点问题,导致其他IIC总线都无法被驱动。
    查看了下数据手册,除了A2 A3以外,还有一条IIC总线B6 B7,但在这块板子上没有被引出,至此,可以判断这块板子的IIC总线基本成了摆设,除非用风枪把DAC5571吹下来,失去了IIC总线,我的机械臂计划就泡汤,因为IIC是闭环反馈至关重要的一环……


    (七)猜测IIC的读函数
    我还编写了IIC的读函数,但因为没有经过测试,所以无法判断该函数是否可行,这里也给出来供大家参考:

    1. void I2C_read_test(unsigned char addr, unsigned char byte_addr)
    2. {
    3.         char str_try[50] = "string is:";
    4.         unsigned char temp;
    5.                
    6. //        I2C_Init();
    7.         I2C_F  = 0xBF;
    8.         I2C_C1_IICEN = 1;        //enable iic
    9.         I2C_C1_TXAK = 0;        //ack
    10.        
    11.         //start
    12. //        I2C_C1_MST = 0;        //master mode off
    13.         I2C_C1_TX = 1;        //write
    14.         I2C_C1_MST = 1;        //master mode on, start signal
    15.         while(!I2C_S_BUSY);
    16.        
    17.         //write addr
    18.         I2C_D = addr;
    19.        
    20.         //wait
    21.         while((I2C_S & I2C_S_IICIF_MASK)==0);
    22.         I2C_S_IICIF = 1;
    23.        
    24.         //write byte_addr
    25.         I2C_D = byte_addr;
    26.                
    27.         //wait
    28.         while((I2C_S & I2C_S_IICIF_MASK)==0);
    29.         I2C_S_IICIF = 1;
    30.        
    31.         DelayUS(1000);
    32.        
    33.         //restart
    34.         I2C_C1_TXAK = 1;
    35.         I2C_C1_RSTA = 1;

    36.         //DelayUS(1000);
    37.        
    38.         //write addr
    39.         I2C_D = addr+1;
    40.        
    41.         //wait
    42.         while((I2C_S & I2C_S_IICIF_MASK)==0);
    43.         I2C_S_IICIF = 1;

    44.         //rec mode
    45.         I2C_C1_TX = 0;
    46. //        I2C_C1_TXAK = 1;
    47.        
    48.         //wait
    49. //        while((I2C_S & I2C_S_IICIF_MASK)==0);
    50. //        I2C_S_IICIF = 1;
    51.        
    52.         //??  rec
    53.         temp = I2C_D;
    54.         while((I2C_S & I2C_S_IICIF_MASK)==0);
    55.         I2C_S_IICIF = 1;
    56.         temp = I2C_D;
    57.        
    58.         while((I2C_S & I2C_S_IICIF_MASK)==0);
    59.         I2C_S_IICIF = 1;
    60.         temp = I2C_D;
    61.        
    62.         while((I2C_S & I2C_S_IICIF_MASK)==0);
    63.         I2C_S_IICIF = 1;
    64.         temp = I2C_D;

    65.        
    66.         //stop
    67. //        i2c_Wait();
    68.        
    69.         I2C_Stop();
    70.        
    71.         sprintf(str_try,"\r\nrec:0x%x",temp);
    72.         printf(str_try);
    73. }
    复制代码


    .
    该会员没有填写今日想说内容.
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2025-8-2 21:40 , Processed in 0.084680 second(s), 20 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表