This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] MSP430FR2433:MSP430FR2433 - I2C (DS1621)

Guru**** 2347060 points
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/758764/msp430fr2433-msp430fr2433---i2c-ds1621

器件型号:MSP430FR2433

大家好、我正在尝试    使用 MSP430FR2433读取 I2C 上的 DS1621温度传感器

批量读取代码行会导致 I2C 总线“挂起”,并且不会生成 ACK 确认位!!!

BIS.w  #UCTXSTT、&UCB0CTLW0  ;I2C start+address
MOV.w #0x00AA、UCB0TXBUF      ;命令 DS1621 (读取温度)
BIS.w  #UCTXSTP,&UCB0CTLW0  ;I2C 停止

如果我在步骤中有一个程序、那么 I2C 总线工作!


I2C 总线在两个阶段有一个“部分”写入周期

BIS.w #UCTXSTT、&UCB0CTLW0;I2C start+address
MOV.w #0x00AA、UCB0TXBUF;命令 DS1621 (读取温度)

BIS.w #UCTXSTP,&UCB0CTLW0;I2C 停止

BIS.w #UCTXSTT、&UCB0CTLW0;I2C start+address

MOV.w #0x00AA、UCB0TXBUF;命令 DS1621 (读取温度)
BIS.w #UCTXSTP,&UCB0CTLW0;I2C 停止

然后、在开始+地址之后、无论波特率如何、ACK + TX_DATA 都以50ms 的间隔出现。

I2C 总线上的几个字节的周期记录不能分两个阶段进行部分分步调试。

BIS.w #UCTXSTT、&UCB0CTLW0;start+address

MOV.w #0x00AA、UCB0TXBUF;ACK+命令 DS1621 (读取温度)
MOV.w #0x00EE、UCB0TXBUF;ACK+命令 DS1621 (启动温度转换)
MOV.w #0x0022、UCB0TXBUF;ACK+命令 DS1621 (暂停温度转换)
MOV.w #0x00AA、UCB0TXBUF;ACK+命令 DS1621 (读取温度)
BIS.w #UCTXSTP,&UCB0CTLW0;ACK+STOP

BIS.w #UCTXSTT、&UCB0CTLW0;I2C start+address
MOV.w #0x00AA、UCB0TXBUF;ACK+命令 DS1621 (读取温度)
MOV.w #0x00EE、UCB0TXBUF;ACK+命令 DS1621 (启动温度转换)
MOV.w #0x0022、UCB0TXBUF;ACK+命令 DS1621 (暂停温度转换)
MOV.w #0x00AA、UCB0TXBUF;ACK+命令 DS1621 (读取温度)

BIS.w #UCTXSTP,&UCB0CTLW0;ACK+STOP

在 NACK + STOP 总线上、仅以相同的50ms 间隔发送 ACK + 1个数据字节+

如果您在寄存器 UCB0TXBUF 中预先设置数据、然后在一个命令中设置开始+停止位

MOV.w #0x00AA、UCB0TXBUF;命令 DS1621 (读取温度)
BIS.w #UCTXSTT+UCTXSTP、&UCB0CTLW0;I2C start+address

START + ADRESS + ACK + STOP 出现在总线 I2C 上。

  1. 为什么主器件在每8位数据传输一次后不会生成 ACK、这是 I2C 协议所规定的、并在传输下一个状态(TX_DATA 和 STOP)之前形成 ACK?
  2. I2C 为什么会自动"挂起"50ms?
  3. 为什么 I2C 自动拒绝在没有分步模式的情况下执行总线周期(UCBBUSY 位的分析没有导致结果)?
  4. 如何在从器件的1个写入周期内传输多个数据字节?

批量代码执行只会导致读取第一个字节

BIS.w #UCTXSTT、&UCB0CTLW0;I2C start+address+RX_data
MOV.w UCB0RXBUF、R7
BIS.w #UCTXSTP、&UCB0CTLW0
MOV.w UCB0RXBUF、R8;ACK + NACK + STOP

分步执行中

BIS.w #UCTXSTT、& UCB0CTLW0

命令、它会调用 START + addres + ACK + RX_DATA (16位)、而 UCB0RXBUF 寄存器(slau445h.pdf 第655页)只接受8个低位!

读取寄存器 UCB0RXBUF 会在总线上产生 ACK + RX_DATA (8位)

MOV.w UCB0RXBUF、R7

当#UCTXSTP 位置位时、读取寄存器命令 UCB0RXBUF 会导致 ACK + NACK + STOP

BIS.w #UCTXSTP 和 UCB0CTLW0
MOV.w UCB0RXBUF、R7              ; ACK + NACK + STOP

运行

BIS.w # UCTXSTT + UCTXSTP、& UCB0CTLW0

导致一个读周期、8个数据位开始+地址+ ACK + RX_DATA + NACK + STOP

如何读取几个字节的数据?


IAR Workbench ASM 代码:

;------------------------------------------------------------------

;CPU:MSP430FR2433IRGER

;------------------------------------------------------------------

; I2C 地址:

;#090h - DS1621    (W)

;#091h - DS1621    (R)

;UCB0I2CSA =#048h

;------------------------------------------------------------------

#include "msp430.h"                    ;#define controlled include 文件

          RSEG  CSTACK                ;定义堆栈段

          RSEG  代码

;------------------------------------------------------------------

重置      mov.w  #SFE (CSTACK),SP            ;初始化 stackpointer

StopWDT    mov.w  #WDTPW+WDTHOLD、&WDTCTL    ;停止看门狗计时器

 

//配置 GPIO

          BIS.b #BIT2+BIT3、P1SEL0          ;I2C 引脚

          BIC.b #BIT2+BIT3、&P1DIR

          BIC.w  #LOCKLPM5、PM5CTL0          ;解锁 I/O 引脚

//将 USCI_B0配置为 I2C 模式

          BIS.w  #UCSWRST、&UCB0CTLW0

          BIS.w  #UCMST、  &UCB0CTLW0      ;I2C 主机模式

          BIS.w  #UCMODE_3、&UCB0CTLW0      ;eUSCI_B 模式= I2C

          MOV.w  #0x0100、  UCB0BRW        ;波特率= SMCLK / 100

          BIC.w  #UCSWRST、&UCB0CTLW0      ;

 

wait1      bit.w #UCBBUSY、和 UCB0STATW        ;等待 I2C 模块完成所有操作

          JC    wait1

          

// WIRITE I2C           

          MOV.w  #0x0048、  UCB0I2CSA              ;I2C 从器件地址= DS1621

          BIS.w  #UCTR、    &UCB0CTLW0              ;I2C=TX

 

          BIS.w  #UCTXSTT、&UCB0CTLW0      ;start+address

          MOV.w  #0x00AA、  UCB0TXBUF      ;ACK+命令 DS1621 (读取温度)

          MOV.w  #0x00EE、  UCB0TXBUF      ;ACK+命令 DS1621 (启动温度转换)

//暂停

      NOP

//--

 MOV.w  #0x0022、  UCB0TXBUF      ;ACK+命令 DS1621 (暂停温度转换)

          MOV.w  #0x00AA、  UCB0TXBUF      ;ACK+命令 DS1621 (读取温度)

          BIS.w  #UCTXSTP,&UCB0CTLW0      ;ACK+STOP

 

//读取 I2C

          BIC.w  #UCTR、    &UCB0CTLW0      ;I2C=RX

 

          BIS.w  #UCTXSTT+UCTXSTP、&UCB0CTLW0      ;start+address+RX_data

          MOV.w  UCB0RXBUF、R7

 

          BIS.w  #UCTXSTT、&UCB0CTLW0      ;I2C start+address+RX_data

          MOV.w  UCB0RXBUF、R7

          BIS.w  #UCTXSTP、&UCB0CTLW0       

          MOV.w  UCB0RXBUF、R8                  ;ACK + NACK + STOP

 

          JMP $                              ;跳转至当前位置'$'

                                          ;(无限循环)

 

;------------------------------------------------------------------

          常见的 INTVEC                ;中断矢量

;------------------------------------------------------------------

          org    reset_vector          ;Reset Vector

          DW    复位

          结束

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    > BIS.w #UCTXSTT、&UCB0CTLW0 ;开始+地址
    > MOV.w #0x00AA、UCB0TXBUF ;ACK+Command DS1621 (读取温度)
    > MOV.w #0x00EE、UCB0TXBUF ;ACK+Command DS1621 (启动温度转换)

    您需要等待 UCB0IFG:UCTXIFG 变为高电平、然后再写入 UCB0TXBUF。 提前执行会导致字节被丢弃。 [参考用户指南(SLAU445H)、图24-12。] 然后、当 SLA 字节完成时、MSP430将 SCL 保持在低电平、等待您加载 TXBUF。

    我没有看到 I2C 的任何汇编示例、但您需要"while ((UCB0IFG&UCTXIFG)=0)/*empty*/;"的效果
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    谢谢!

    工作的 ASM 代码样本会写入 I2C 总线:

    示例1 -将1个字节传输到 I2C 总线(不会自动生成停止)---------------

     //配置 GPIO
        BIS.b #BIT2+BIT3、P1SEL0            ;I2C 引脚
        BIC.b #BIT2+BIT3、&P1DIR
        BIC.w #LOCKLPM5、PM5CTL0          ;解锁 I/O 引脚

    //将 USCI_B0配置为 I2C 模式  
        BIS.w #UCSWRST、&UCB0CTLW0
        BIS.w #UCMST、&UCB0CTLW0         ; I2C 主机模式
        BIS.w #UCMODE_3、&UCB0CTLW0     ;eUSCI_B 模式= I2C
        MOV.w #0x0100、UCB0BRW           ;波特率= SMCLK/100
        BIS.w  #UCASTP_0、&UCB0CTLW1    ;00 =无自动停止生成。
                                         ;停止条件在用户置位 UCTXSTP 位后生成。
                                         ;UCBxTBCNT 中的值无关。
        BIC.w  #UCSWRST、 &UCB0CTLW0    ;

       BIS.w #UCTXSTT、&UCB0CTLW0       ;I2C start+ I2C 地址

    W1位。w #UCTXIFG0、&UCB0IFG
       JNC W1
       MOV.w #0x00EE、UCB0TXBUF         ;I2C TX_DATA = EE

    W2位。w #UCTXIFG0、&UCB0IFG
       JNC w2.
       BIS.w #UCTXSTP、&UCB0CTLW0       ; I2C 停止

    示例2 -将3个字节传输到 I2C 总线(无自动停止生成功能)---------------

     //配置 GPIO
        BIS.b #BIT2+BIT3、P1SEL0            ;I2C 引脚
        BIC.b #BIT2+BIT3、&P1DIR
        BIC.w #LOCKLPM5、PM5CTL0          ;解锁 I/O 引脚

    //将 USCI_B0配置为 I2C 模式  
        BIS.w #UCSWRST、&UCB0CTLW0
        BIS.w #UCMST、&UCB0CTLW0         ; I2C 主机模式
        BIS.w #UCMODE_3、&UCB0CTLW0     ;eUSCI_B 模式= I2C
        MOV.w #0x0100、UCB0BRW           ;波特率= SMCLK/100
        BIS.w  #UCASTP_0、&UCB0CTLW1    ;00 =无自动停止生成。
                                         ;停止条件在用户置位 UCTXSTP 位后生成。
                                         ;UCBxTBCNT 中的值无关。
       BIC.w  #UCSWRST、 &UCB0CTLW0    ;

       BIS.w #UCTXSTT、&UCB0CTLW0        ;I2C start+ I2C 地址

    W1位。w #UCTXIFG0、&UCB0IFG
       JNC W1
       MOV.w #0x00EE、UCB0TXBUF          ; I2C TX_DATA=EE

    W2位。w #UCTXIFG0、&UCB0IFG
       JNC w2.
       MOV.w #0x0022、UCB0TXBUF          ;I2C TX_DATA=22

    W3位。w #UCTXIFG0、&UCB0IFG
       JNC W3
       MOV.w #0x00AA、UCB0TXBUF         ; I2C TX_DATA=AA

    W4位。w #UCTXIFG0、&UCB0IFG
       JNC W4
       BIS.w #UCTXSTP、&UCB0CTLW0       ; I2C 停止

    示例3 -将1个字节传输到 I2C 总线(自动停止生成)----------------------------------------------------------

     //配置 GPIO
        BIS.b #BIT2+BIT3、P1SEL0            ;I2C 引脚
        BIC.b #BIT2+BIT3、&P1DIR
        BIC.w #LOCKLPM5、PM5CTL0          ;解锁 I/O 引脚

    //将 USCI_B0配置为 I2C 模式  
        BIS.w #UCSWRST、&UCB0CTLW0
        BIS.w #UCMST、&UCB0CTLW0         ; I2C 主机模式
        BIS.w #UCMODE_3、&UCB0CTLW0    ;eUSCI_B 模式= I2C
        MOV.w #0x0100、UCB0BRW           ;波特率= SMCLK/100
        BIS.w  #UCASTP_2、&UCB0CTLW1    ;02 = 字节计数器值达到 UCBxTBCNT 后自动生成停止条件。
                                         ;UCBCNTIFG 在字节计数器达到阈值时置1。
       BIC.w  #UCSWRST、 &UCB0CTLW0     

       MOV.w #0x0001、UCB0TBCNT          ;将1字节传输到 I2C  

       BIS.w #UCTXSTT、&UCB0CTLW0       ;I2C start+ I2C 地址

    W1位。w #UCTXIFG0、&UCB0IFG
       JNC W1
       MOV.w #0x00EE、UCB0TXBUF         ;I2C  TX_DATA=EE + I2C 自动停止

    示例4 -将3个字节传输到 I2C 总线(自动停止生成)----------------------------------------------------------

     //配置 GPIO
        BIS.b #BIT2+BIT3、P1SEL0                 ;I2C 引脚
        BIC.b #BIT2+BIT3、&P1DIR
        BIC.w #LOCKLPM5、PM5CTL0               ;解锁 I/O 引脚

    //将 USCI_B0配置为 I2C 模式  
        BIS.w #UCSWRST、&UCB0CTLW0
        BIS.w #UCMST、&UCB0CTLW0         ; I2C 主机模式
        BIS.w #UCMODE_3、&UCB0CTLW0     ;eUSCI_B 模式= I2C
        MOV.w #0x0100、UCB0BRW           ;波特率= SMCLK/100
        BIS.w  #UCASTP_2、&UCB0CTLW1    ;02 = 字节计数器值达到 UCBxTBCNT 后自动生成停止条件。
                                         ;UCBCNTIFG 在字节计数器达到阈值时置1。
       BIC.w  #UCSWRST、 &UCB0CTLW0     

       MOV.w #0x0003、UCB0TBCNT          ;将3字节传输到 I2C  

       BIS.w #UCTXSTT、&UCB0CTLW0       ; I2C 开始+ I2C 地址

    W1位。w #UCTXIFG0、&UCB0IFG
       JNC W1
       MOV.w #0x00EE、UCB0TXBUF         ; I2C TX_DATA=EE

    W2位。w #UCTXIFG0、&UCB0IFG
       JNC w2.
       MOV.w #0x0022、UCB0TXBUF          ;I2C  TX_DATA=22

    W3位。w #UCTXIFG0、&UCB0IFG
       JNC W3
       MOV.w #0x00AA、UCB0TXBUF         ;I2C  TX_DATA=AA + I2C 自动停止

     ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    写入 I2C 总线-好的! 已解决

     

    如何读取 I2C 总线?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    设置 UCTR=0、然后设置 UCTXSTT。 每次 UCRXIFG 变为高电平、都会从 UCB0RXBUF 中提取一个字节。 如果 STP=2、器件将在 TBCNT 字节之后为您发出 Stop 命令。 (顺便说一下、我没有看到您在上面设置 UCTR=1、但示波器跟踪功能会声称您确实这样做了。 是否有缺失?)

    例如、上面的读取温度(0xAA)序列、无需发出 UCTXSTP、只需设置 UCTL=0、然后立即设置 UCTXSTT。 这将为您提供一个重复启动、DS1621数据表中说这很好。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    大家好、Bruce:感谢您对此主题的支持。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    //读取 I2C (2字节)
        BIC.w #UCTR、&UCB0CTLW0
        BIS.w #UCTXSTT、&UCB0CTLW0

    RD1位.w #UCRXIFG0、&UCB0IFG
       Jnc RD1
       MOV.w UCB0RXBUF、R7

    RD2位。w #UCRXIFG0、&UCB0IFG
       JNC RD2
       MOV.w UCB0RXBUF、R8

       BIS.w #UCTXSTP,&UCB0CTLW0;I2C 停止

    //读取 I2C (1字节)
        BIC.w #UCTR、&UCB0CTLW0
        BIS.w #UCTXSTT、&UCB0CTLW0

    读数3位.w #UCRXIFG0、&UCB0IFG
       JNC 读数3
       MOV.w UCB0RXBUF、R7

       BIS.w #UCTXSTP,&UCB0CTLW0;I2C 停止

    为什么插入9个额外的 SCL 周期?
    如何摆脱它们?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    简短答案:在读取 UCB0RXBUF 之前、将 UCTXSTP 设置上移一行。

    一旦您读取 RXBUF、I2C 单元将继续获取下一个字节、包括堆叠您刚刚读取的字节。 因此、您需要在读取最后一个字节的 RXBUF 之前设置 TXSTP。 [参考 UG (SLAU445H)秒 24.3.5.2.2,第6段]。

    msp43fr231x_eusci_i2c_standard_master.c 示例说明了这一点、尽管它会提前发出停止命令。 (我在 FR2433示例套件中看不到此示例、我不知道原因。)
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    //读取 I2C - 1字节
       BIC.w #UCTR、&UCB0CTLW0       ; I2C=RX
       BIS.w #UCTXSTT、&UCB0CTLW0   ;I2C 启动
    RD1位.w #UCRXIFG0、&UCB0IFG
       Jnc RD1
       BIS.w #UCTXSTP,&UCB0CTLW0   ;I2C 停止
       MOV.w UCB0RXBUF、R7


    R7 = 0019h 而不是8019h (确定!)
    但是 UCB0RXBUF = 0080h!!!
    如何确保第二个字节未被读取?

    样例5 -将2 个字节接收到 I2C 总线(没有自动停止生成功能)---------------

    读取两个字节-有效!

    //读取 I2C - 2字节  
       BIC.w  #UCTR、   &UCB0CTLW0     ; I2C=RX
       BIS.w #UCTXSTT、&UCB0CTLW0    ;I2C 启动

    RD1位.w #UCRXIFG0、&UCB0IFG
       Jnc RD1
       BIS.w #UCTXSTP,&UCB0CTLW0    ;I2C 停止
       MOV.w UCB0RXBUF、R7
    RD2位。w #UCRXIFG0、&UCB0IFG
       JNC RD2
       BIS.w #UCTXSTP,&UCB0CTLW0    ;I2C 停止
       MOV.w UCB0RXBUF、R8


    R7 = 0019h R8 = 0080h

    样例6 -将1 个字节接收到 I2C 总线(没有自动停止生成功能)---------------

    //读取 I2C - 1字节
       BIC.w #UCTR、&UCB0CTLW0              ; I2C=RX
       BIS.w #UCTXSTT+UCTXSTP、&UCB0CTLW0;I2C start+stop
    RD1位.w #UCRXIFG0、&UCB0IFG
       Jnc RD1
       MOV.w UCB0RXBUF、R7


    R7 = 001Ah

     

    仅当在一条命令中启动+停止时、才可接收8个数据位。 是这样吗?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我不知道答案。 这似乎与该段落中描述的行为不匹配。 (可能有一个脚注。) 我通常在 UCASTP=2的情况下使用 TBCNT、所以硬件为我完成所有这些。

    实际上、读取额外的字节会要求传感器提供一些额外的(不需要的)工作、但我在 DS 中看不到会导致错误结果的情况。 在任何情况下、您都不会在 RXBUF 中看到0119h (或8019h)、因为高电平位始终为0。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    谢谢!
    抱歉。 我做了一个排印错误。 R7 = 8019h (更正了上面我的问题)

    据我所知、仅在一条命令中开始+停止时接收8位数据的数据。

    如果停止不在同一命令行中、则器件读取2个字节!

    是这样吗?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您的帖子是否在我看不到的时候发生了变化?

    不管怎样、您现在似乎有了一个解决方案。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    德州仪器会回答什么问题?