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.

[参考译文] MSP432P401R:I2C主接收问题

Guru**** 2538950 points


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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/582850/msp432p401r-i2c-master-reception-issue

部件号:MSP432P401R

您好,

我正在尝试从从属设备(24lc04 FRAM)接收我已传输的相同数据(传输成功,通过SDA获得数据突发)。

下面是我的代码,Pls建议我是否正确地从从属设备接收数据?? 以及如何验证?


/* I2C从属设备的从属设备地址*/
#define slaver_address      0x50
#define NUM_OF_RX_Bytes   10.

/*静态*/
静态uint8_t TXData[10]={0x06,0x3A,0x1E,0x39,0x1C, 0x79,0x5D,0x6C,0x0C,0x01};
静态uint8_t TXByteCtr = 1;
静态uint8_t已发送= 0;

静态uint8_t RXData[NUM_OF_RX_bytes];
静态易失性UINT32_t xferIndex;
静态挥发性双刀头止动Sent;

/* I2C主配置参数*/
const eUSI_I2C_MasterConfig i2cConfig =

       EUSCI_B_I2C_CLOCKSOURCE_SMCLK,         // SMCLK时钟源
       300万,                               // SMCLK = 3MHz
       EUSCI_B_I2C_SET_DATA_RATE_100KBPS     ,//所需的I2C时钟为100kHz
       0,                                     //无字节计数器阈值
       EUSCI_B_I2C_NO_AUTO_STOP               //无自动停止
};


内部主(无效)

   易失性UINT32_t ii;

   /*禁用监视 程序*/
   WDT_A_HoldTimer();

   P2->DIR = BIT7;
   port_init();//               初始化端口

       INIT_LCD();
   已发送= 0;
   /*为I2C选择端口1 -将引脚6,7设置为输入主模块功能,
    *  (UCB0SIMO/UCB0SDA,UCB0SOMI/UCB.S.)。
    */
  GPIO _setAsPeripheralModuleFunctionInputPin (GPIO_PORT_P1,
           GPIO _PIN6 + GPIO _PIN7,GPIO主要模块功能);
   stopSent =假;
//   memset (RXData,0x00,NUM_OF_REC_Bytes);

   /*在100kHz的频率下将I2C主设备初始化到SMCLK,没有自动停止*/
  I2C_initMaster (EUSI_B0_BASE,&i2cConfig);

   /*指定从属地址*/
   I2C_setSlaveAddress (EUSCI_B0_BASE,SLAVE_ADDRESS);

   /*将主中继器设置为传输模式*/
   I2C_setMode (EUSI_B0_BBASE,EUSI_B_I2C_Transmit_mode);

   /*启用I2C模块以启动操作*/
   I2C_enableModule (EUSI_B0_BASE);

   /*启用并清除中断标志*/
   I2C_clearInterruptFlag (EUSI_B0_BASE,
         EUSCI_B_I2C_Transmit_INTERRUPT0 + EUSCI_B_I2C_NAK_INTERRUPT);
   //启用主接收中断
   I2C_enableInterrupt (EUSCI_B0_BBASE,EUSCI_B_I2C_Transmit_INTERRUPT0 + EUSCI_B_I2C_NAK_interrupt);
   interrup_enableSleepOnIsrExit();
   interrup_enableInterrupt (INT_EUSCIB0);
   I2C_masterSendStart (EUSI_B0_BASE);

   同时(1)
   {
       while (I2C_masterIsStopSent (EUSCI_B0_BBASE)== EUSCI_B_I2C_Sending停止);
       //发送初始启动条件

       I2C_masterSendMultiByteStart (EUSI_B0_BASE,TXData[0]);

       interrup_enableSleepOnIsrExit();
       PCM_gotoLPM0InterruptSafe ();

      /* intToStr (数据,分辨率,1);
      Display2 (res);*/
   }
}

/*******************************************************************************
 * eUSCIB0 ISR。 重复的启动和传输/接收操作发生
 *在本ISR内。
 ***************** /
void EUSCIB0_IRQHandler (void)

   UINT_FAST16_t状态;

      状态= I2C_getEnabledInterruptStatus (EUSI_B0_BASE);
      I2C_clearInterruptFlag (EUSI_B0_BASE,STATUS);

      IF (状态和EUSCI_B_I2C_NAK_INTERRUPT)
      {
         I2C_masterSendMultiByteStart (EUSI_B0_BASE,TXData[0]);
      }

      IF (状态和EUSCI_B_I2C_Transmit_INTERRUPT0)
      {
          //检查字节计数器
          如果(!sent)
          {
              //发送下一个数据并递减字节计数器
              I2C_masterSendMultiByteNext(EUSI_B0_BASE,TXData[TXByteCtr ]);
              已发送= 1;
          }
          否则
          {

              I2C_masterSendMultiByteStop (EUSI_B0_BASE);
              interrupT_disableSleepOnIsrExit();
              TXByteCtr ++;
              IF (TXByteCtr > 10)
                 TXByteCtr ++;

                // 在接收模式下设置
                    I2C_setMode (EUSCI_B0_BBASE,EUSCI_B_I2C_receive模式);
                    I2C_clearInterruptFlag (EUSI_B0_BBASE,EUSI_B_I2C_Receive_INTERRUPT0);
                    I2C_enableInterrupt (EUSI_B0_BBASE,EUSI_B_I2C_receive _INTERRUPT0);
//                    I2C_masterReceiveStart (EUSCI_B0_BASE);
   //                 I2C_DisableInterrupt (EUSCI_B0_BBASE,EUSCI_B_I2C_Transmit_INTERRUPT0);

              已发送= 0;
          }
      }
      IF (状态和EUSCI_B_I2C_Receive_INTERRUPT0)
      {
         p2->out ^= BIT7;
         RXData[xferIndex+]= I2C_masterReceiveMultiByteNext (EUSCI_B0_BASE);

         数据= RXData[xferIndex];

         //如果在末尾,则重置索引
         IF (xferIndex == NUM_OF_RX_bytes)
            xferIndex = 0;

         I2C_setMode (EUSI_B0_BBASE,EUSI_B_I2C_Transmit_mode);

         //启用I2C模块以启动操作
         I2C_enableModule (EUSI_B0_BASE);
         //启用并清除中断标志
         I2C_clearInterruptFlag (EUSI_B0_BASE,
               EUSCI_B_I2C_Transmit_INTERRUPT0 + EUSCI_B_I2C_NAK_INTERRUPT);
         //启用主接收中断
         I2C_enableInterrupt (EUSCI_B0_BBASE,EUSCI_B_I2C_Transmit_INTERRUPT0 + EUSCI_B_I2C_NAK_interrupt);
//         I2C_masterSendStart (EUSCI_B0_BASE);
//         I2C_DisableInterrupt (EUSCI_B0_BBASE,EUSCI_B_I2C_Receive_INTERRUPT0);
      }
}

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

    您好,
    您要做的是写入寄存器以读取,一旦中断返回其发送,您就可以更改配置以接收8位值,并且您必须启用中断才能接收!

    所以我改变了你的代码。 尝试将断点放在IF (状态和EUSCI_B_I2C_Receive_INTERRUPT0)内


    //检查字节计数器
    如果(!sent)

    //发送下一个数据并递减字节计数器
    I2C_masterSendMultiByteNext(EUSI_B0_BASE,TXData[TXByteCtr ]);
    已发送= 1;
    }
    否则


    I2C_masterSendMultiByteStop (EUSI_B0_BASE);
    interrupT_disableSleepOnIsrExit();
    TXByteCtr ++;
    IF (TXByteCtr > 10)
    TXByteCtr ++;

    //在接收模式下设置
    I2C_setMode (EUSCI_B0_BBASE,EUSCI_B_I2C_receive模式);
    I2C_masterReceiveStart (EUSCI_B0_BASE);
    I2C_enableInterrupt (EUSI_B0_BBASE,EUSCI_B_I2C_receive _INTERRUPT0);<----------- 我改变了

    已发送= 0;
    }

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好,
    我在代码中做了这一更改并尝试了,但现在波形仅在开机时到达,几秒钟后SDA和SCL再次变为低电平。 当我添加“I2C_masterReceiveStart(EUSSCI_B0_BASE);”语句时就发生了这种情况。
    同时,它还需要在whiles(1)中调用API -“I2C_masterSendMultiByteStart(EUSI_B0_base, TXData[0]);”
    否则它不会连续发送数据。 这意味着程序没有运行(状态和EUSCI_B_I2C_NAK_INTERRUPT)和(状态和EUSCI_B_I2C_Transmit_INTERRUPT0)?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    在您的代码中,您通过执行以下操作将MCU发送到休眠状态:“ PCM_gotoLPM0InterruptSafe ();”

    如果发生中断,他将被唤醒。

    为什么不在while ()循环之前发送指令,并在两个中断中设置中断点,一个用于传输,另一个用于接收。

    调试您的代码并测量两条线路SDA SCL以了解I2C通信。  

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

    我已经评论了指令"PCM_gotoLPM0InterruptSafe ();" 现在正在获取波形,即使保留指令->"I2C_masterReceiveStart(EUSSCI_B0_BACB)"。

    通过在此API中设置断点-> I2C_masterSendMultiByteNext(EUSI_B0_BASE,TXData[TXByteCtr ]); 开始知道这一点

    程序在该处运行并传输数据 (请参阅下图以获取该行)。

    但程序未在接收端机时运行,通过在行-> RXData[xferIndex++]= I2C_masterReceiveMultiByteNext(EUSI_B0_BASE中放置断点进行检查;

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    Furst将传输I2C从While循环中取出。
    先把它放在前面。 在中断例程中的“发送”和“接收”中设置中断点。
    并测量逻辑时钟SDA和SCL。 您必须检查您发送的内容是否确实存在,以及从属设备是否发送接收数据。
    逐步执行。 您可以让MCU在循环时休眠。 如果中断已修复,请确保将其唤醒。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    更改您的代码:

    IF (状态和EUSCI_B_I2C_Transmit_INTERRUPT0)

    I2C_setMode (EUSCI_B0_BBASE,EUSCI_B_I2C_receive模式);
    I2C_clearInterruptFlag (EUSI_B0_BBASE,EUSI_B_I2C_Receive_INTERRUPT0);
    I2C_enableInterrupt (EUSI_B0_BBASE,EUSI_B_I2C_receive _INTERRUPT0);
    I2C_masterReceiveStart (EUSCI_B0_BASE);
    }
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    1)如果我从whiles()回路中取出“I2C_masterSendMultiByteStart(EUSSCI_B0_BBASE,TXData[0]”,则它将停止传输(未获得任何SDA/SCL输出)。 因为它不在内部->

      IF (状态和EUSCI_B_I2C_NAK_INTERRUPT)

      {

      I2C_masterSendMultiByteStart (EUSI_B0_BASE,TXData[0]);

      }

    2) IF (状态和EUSCI_B_I2C_Transmit_INTERRUPT0)
          {

              //检查字节计数器
              如果(!sent)
              {
                  //发送下一个数据并递减字节计数器
                  I2C_masterSendMultiByteNext(EUSI_B0_BASE,TXData[TXByteCtr ]);

                  已发送= 1;
              }
              否则
              {

                  I2C_masterSendMultiByteStop (EUSI_B0_BASE);
                  interrupt_disableSleepOnIsrExit();------------------------------- >>如果删除此指令,程序进入接收中断但意外获得SDA (请参阅下面的图)
               // 在接收模式下设置
                  I2C_setMode (EUSCI_B0_BBASE,EUSCI_B_I2C_receive模式);
                  I2C_clearInterruptFlag (EUSI_B0_BBASE,EUSI_B_I2C_Receive_INTERRUPT0);
                  I2C_enableInterrupt (EUSI_B0_BBASE,EUSI_B_I2C_receive _INTERRUPT0);
                  I2C_masterReceiveStart (EUSCI_B0_BASE);

                  TXByteCtr ++;
                  IF (TXByteCtr > 10)
                     TXByteCtr = 1;

                  已发送= 0;
              }
          }

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您测量的不正确。
    您希望看到主从之间的一次数据传输。
    将send命令从while循环中取出。 当您测量SCL和SDA时,您必须在SCL上触发示波器,并在信号到达时将触发器启动停止。
    现在这个函数Interrupt_disableSleepOnIsrExit();正如我所知,如果在MCU休眠期间发生其他中断,不要让MCU唤醒。 所以你想评论一下。
    首先不要设置任何休息点,在您的示波器上,您必须看到第一个通信。 一旦你看到它,试着解释他的"逻辑时钟"(不是波)。
    你必须学习如何在示波器上测量并解释I2C通信,发送什么以及阅读什么。
    我不能为你这样做。