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.

[参考译文] MSP430F5342:MSP430F5342 I2C:在传输到 EEPROM 后、线路状态保持繁忙

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/712373/msp430f5342-msp430f5342-i2c-line-state-keeps-busy-after-transmissions-to-eeprom

器件型号:MSP430F5342


您好、来自德国 Rastatt、

为了集成 EEPROM、我在上述板上开发了 I2C 驱动器
它将保存我们的应用的一些参数数据。

引脚4.1已配置为 UCB1SDA (数据线路)、
引脚4.2保持 I2C 时钟   UCB.S (时钟线)。

我打算使用 UCB1STAT 寄存器中的 BUSY 标志来获得一个合适的时序。

软件基于中的 IAR/TI 示例
  IAR 嵌入式工作平台\430\examples\DriverLib examples\MSP430F5xx_6xx\USCI_B_i2c、
  项目"USCI_B_i2c_ex3_masterTxSingle.c"
  文件"USCI_B_i2c"已重写为"EEP_i2c.c"、但有其不同之处
  发送后、忙标志等待复位。

例如、将函数"USCI_B_I2C_masterSendMultiByteStartWithTimeout"返工为
                     "eep_I2C_masterSendMultiByteStartWithTimeout"。


//================================================
//代码片段:
//================================================

uint8_t EEP_I2C_masterSendMultiByteStartWithTimeout (uint16_t baseAddress、
                                                   uint8_t txData、
                                                   uint32_t 超时)

  uint32_t TMO;
  
  
  TMO =超时;
  
  //存储当前发送中断使能
  uint8_t txieStatus = HWREG8 (baseAddress + OFS_UCBxIE)& UCTXIE;

  //禁用发送中断使能
  HWREG8 (baseAddress + OFS_UCBxIE)&=~(UCTXIE);

  //发送启动条件。
  HWREG8 (baseAddress + OFS_UCBxCTL1)|= UCTR + UCTXSTT;

  //轮询发送中断标志。
  while ((!(HWREG8 (baseAddress + OFS_UCBxIFG)& UCTXIFG))&-TMO)
  {
    ;
  }

  //检查传输是否超时
  if (TMO = 0)
  {
    返回(STATUS_IFG1);
  }

 //================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================
 //==>到目前为止、代码是从原始代码中接管的:
 //发出启动事件,发送从器件地址...
 //================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================
 
  TMO =超时;
  
  
  
  //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  //程序将在下面的循环中挂起,因为忙状态仍然存在(如果未注释掉!)。
  //这应确保在总线再次就绪之前不会完成下一个传输!
  //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  
  while ((HWREG8 (baseAddress + OFS_UCBxSTAT)& UCBBUSY)&&-TMO)
  {
    ;
  }

  //检查传输是否超时
  if (TMO = 0)
  {
    返回((uint8_t) STATUS_BSY);
  }

 //================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================
 //==>添加了此代码... 等待线路状态更改为"非忙"
 //================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================

//发送单字节数据。
  HWREG8 (baseAddress + OFS_UCBxTXBUF)= txData;

  //恢复发送中断使能
  HWREG8 (baseAddress + OFS_UCBxIE)|= txieStatus;

  return ((uint8_t) status_Success);
 
 //================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================
 //=>再次原始代码... 发送要写入 EEPROM 的地址的第一个字节...
 //不要发送“停止”事件! (防止地址字节被写入 EEPROM)。
 //================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================
  


//================================================
//代码片段结束
//================================================


下一个地址字节以及所有后续数据字节将被发送到 EEP 内部
缓冲器、直到停止事件触发将数据字节写入指定的地址
发送的前2个字节。

注释掉忙线检查代码、然后在之间插入长延迟时间间隔(请参阅下面的代码)

单个函数调用使事情正常工作--尽管线路一直处于繁忙状态,直到发送停止事件。

=>但是、这当然会使过程太慢、无法在真实项目中使用!

//================================================
//代码片段2.
//================================================

uint8_t EEPROReadPage (uint16_t 地址、uint8_t * pui8RcvBuf、uint8_t 长度、uint32_t 超时)

(笑声)
(笑声)

  adrLo =(uint8_t)(地址和0x00FF);
  adrHi =(uint8_t)((地址和0xFF00)>> 8);

  RetVal = EEP_I2C_masterSendMultiByteStartWithTimeout (USCI_B1_base、adrHi、timeout);
  if (retval!= STATUS_SUCCESS){while (1);}
  
  //=>等待很长...
  {cntr= delay;while ( cntr --);}
  RetVal = EEP_I2C_masterSendMultiByteNextWithTimeout (USCI_B1_base、adrLo、timeout);
  if (retval!= STATUS_SUCCESS){while (1);}
  
  //=>等待很长...
  {cntr= delay;while ( cntr --);}

  eep_I2C_ReceivmasterMultiByteStart (USCI_B1_base);
  
  //=>等待很长...
  {cntr= delay;while ( cntr --);}


  for (bufNdx=0;bufNdx<NCHARS -1;bufNdx++)
  {
     RcvBuf[bufNdx]= EEP_I2C_masterReceiveMultiByteNext (USCI_B1_base);
   
     //=>等待很长...
    {cntr= delay;while ( cntr --);}
  }

...
(笑声)

//================================================
//代码片段2结束
//================================================


问题是 :为什么发送后忙状态仍然存在?
                       是否有权变措施(即获取适当时序的另一种方法)?
                 
谢谢、大家好
Goetz




Goetz

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

    您好!

    欢迎来到论坛! 为了便于将来参考,当使用语法 Highlighter 工具(类似于“ ")找到"插入代码、附加文件等..." 单击"回复"按钮后显示的链接。

    [引用 USER="Goetz Borkowski"]我打算使用 UCB1STAT 寄存器中的 BUSY 标志来获得一个合适的时序。

    遗憾的是、我想我不会遵循您尝试测量的时间安排。 概括而言、请帮助我了解您正在尝试执行的操作以及修改代码示例的原因。

    供其他人参考、这里是原始代码示例。

    eusci_b_i2c_ex3_masterTxMultiple.c

    /*-版权所有-、BSD
    *版权所有(c) 2016、德州仪器(TI)公司
    *保留所有权利。
    *
    *
    只要
    符合以下条件*、允许以源代码和二进制形式重新分发和使用:
    *
    *源代码的重新分发必须保留上述版权
    声明*、此条件列表和以下免责声明。
    *
    ***二进制形式的再发行必须在
    
    *随发行提供的文档和/或其他材料中复制上述版权声明、本条件列表和以下免责声明。
    *
    ***未经
    
    事先书面许可、不得使用德州仪器公司的名称或*其贡献者的名称认可或推广从本软件衍生的产品*。
    *
    *本软件由版权所有者和贡献者"按原样"提供
    *、
    
    不承担任何明示或暗示的保证、包括但不限于*适销性和特定用途适用性的暗示保证*。 在任何情况下、版权所有者或
    *贡献者都不对任何直接、间接、偶然、特殊、
    *模范、 或相应的损害(包括但不限于
    *采购替代产品或服务;丧失使用、数据或利润;
    *或业务中断)、但出于任何责任理论
    、*无论是在合同中、严格责任还是由于
    使用本软件而以任何方式产生的侵权行为(包括疏忽或*其他)
    、*即使已获悉可能会发生此类损坏。
    *--/copyrights-*/
    #include "driverlib.h"
    
    //********
    //! 此示例展示了如何将 I2C 模块配置为主器件//
    ! 中断驱动模式下的多字节传输。 从器件的地址
    //! 模块的设置。
    //!
    //! MSP430F5xx_6xx 演示- USCI_B0 I2C 主器件 TX 多个字节到 MSP430从
    器件//!
    //! 说明:此演示通过 I2C 总线连接两个 MSP430。 主
    器件//! 发送到从器件。 这是主代码。 它很好
    //! 传输一组数据并演示如何实现 I2C
    //! 主发送器使用 USCI_B0 TX 中断发送多个字节。
    //! ACLK = n/a、MCLK = SMCLK = BRCLK =默认 DCO =~1.045MHz
    //!
    //! /|\/|\
    //! MSP430F67791A 10k MSP430F67791A
    //! 从器件 || 主器件
    //! -------- |||---
    //! -|XIN P2.6/UCB0SDA|-|-|-+-|P2.6/UCB0SDA XIN|-
    //! | || | |
    //! -|XOUT || | XOUT|-
    //! | P2.5/UCB.S.|<---- >|P2.5/UCB.S. |
    //! | | | |
    //!
    //! 此示例使用以下外设和 I/O 信号。 您必须
    //! 查看这些内容并根据您自己的董事会需要进行更改:
    //! - I2C 外设
    //! - GPIO 端口外设(用于 I2C 引脚)
    //! - SCL2
    //! - SDA//
    !
    //! 此示例使用以下中断处理程序。 要使用此示例
    //! 在您自己的应用程序中、您必须将这些中断处理程序添加到
    您的//! 矢量表。
    //! - USCI_B0_Vector。
    ////
    
    *********
    //
    //
    //设置从机模块的地址。 这是以
    //以下格式发送的7位地址:
    //[A6:A5:A4:A3:A1:A0:RS]
    //
    第一个字节的"RS"位置为零表示主
    设备//发送(发送)数据到所选的从设备,而在该位置为1
    表示主设备接收来自从设备的数据。
    ////
    *****************
    #define SLAVE_ADDRESS 0x48
    
    uint8_t TXData = 0; //指向 TX 数据
    uint8_t TXByteCtr 的指针;
    
    void main (void)
    {
    WDT_A_HOLD (WDT_A_base);
    
    //将 XT1频率设置为 UCS
    UCS_setExternalClockSource (32768、0);
    
    //为 I2C (UCB.S.、UCB0SDA)配置引脚
    //将 P2.5和 P2.6设置为模块功能输入
    GPIO_setPeripheralModuleFunctionInputPin (
    GPIO_PORT_P2、
    GPIO_PIN5 + GPIO_PIN6
    );
    
    EUSCI_B_I2C_initMasterParam param ={0};
    param.selectClockSource = EUSCI_B_I2C_CLOCKSOURCE_SMCLK;
    param.i2cClk = UCS_getSMCLK ();
    param.datarate = EUSCI_B_I2C_SET_DATA_RATE_400KBPS;
    param.byteCounterThreshold = 0;
    param.autoSTOPGeneration = EUSCI_B_I2C_NO_AUTO_STOP;
    EUSCI_B_I2C_initMaster (EUSCI_B0_BASE、param);
    
    //指定从器件地址
    EUSCI_B_I2C_setSlaveAddress (EUSCI_B0_BASE、
    从器件地址
    );
    
    //将主设备设置为接收模式
    EUSCI_B_I2C_setMode (EUSCI_B0_BASE、
    EUSCI_B_I2C_Transmit 模式
    );
    
    //启用 I2C 模块以启动操作
    EUSCI_B_I2C_ENABLE (EUSCI_B0_BASE);
    
    EUSCI_B_I2C_clearInterrupt (EUSCI_B0_BASE、
    EUSCI_B_I2C_Transmit INTERRUPT0 +
    EUSCI_B_I2C_NAK_INTERRUPT
    );
    
    //启用主机接收中断
    EUSCI_B_I2C_enableInterrupt (EUSCI_B0_BASE、
    EUSCI_B_I2C_Transmit INTERRUPT0 +
    EUSCI_B_I2C_NAK_INTERRUPT
    );
    while (1)
    {
    _DELAY_CYCLES (1000); //传输之间的延迟
    TXByteCtr = 4; //加载 TX 字节计数器
    TXData = 0;
    
    while (EUSCI_B_I2C_Sending _stop = EUSCI_B_I2C_masterIsStopSent)
    (EUSCI_B0_BASE)
    {
    ;
    }
    
    EUSCI_B_I2C_masterSendMultiByteStart (EUSCI_B0_BASE、
    TXData++);
    
    _bis_SR_register (CPUOFF + GIE); //输入带中断的 LPM0
    //保持在 LPM0中直到所有数据
    //是 TX
    //增加数据字节
    }
    }//------------------
    
    
    // USCIAB0TX_ISR 的结构使其可用于通过
    预加载带有字节计数的 TXByteCtr 来发送任何//字节数。 此外、TXData
    //指向要发送的下一个字节。
    ///----------------------------------
    #if defined (__TI_Compiler_version__)|| defined (__IAR_systems_icc_)
    #pragma vector=USCI_B0_vector
    __interrupt
    #elif defined (__GNU__)
    __attribute__(interrupt (USCI_B0_vector)))#endif USCI_B0_vector __interrupt #elif
    
    ISR (void
    
    switch (__evo_in_range (UCB0IV、0x1E))
    {
    情况0x00:break; //向量0:无中断中断;
    情况0x02:break;
    情况0x04:
    //重新发送启动(如果 NACK)
    EUSCI_B_I2C_masterSendStart (EUSCI_B0_BASE);
    中断; //向量4:NACKIFG 中断;
    情况0x18:
    IF (TXByteCtr) //检查 TX 字节计数器
    {
    EUSCI_B_I2C_masterSendMultiByteNext (EUSCI_B0_BASE、
    TXData++);
    TXByteCtr --; //减量 TX 字节计数
    器}
    其他
    {
    EUSCI_B_I2C_masterSendMultiByteStop (EUSCI_B0_BASE);
    
    _BIC_SR_REGISTER_ON_EXIT (CPUOFF); //退出 LPM0
    }
    中断; //向量26:TXIFG0中断;
    默认值:break;
    }
    } 

    此致、

    James

    MSP 客户应用