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.

[参考译文] MSP430FR2355:I2C 从模式、监控 UCTR 和 UCTXIFX0以及 UCRXIFG0需要一些时间

Guru**** 2532080 points
Other Parts Discussed in Thread: MSP430FR2355

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1065644/msp430fr2355-i2c-slave-mode-monitor-uctr-and-uctxifx0-and-ucrxifg0-takes-some-time

器件型号:MSP430FR2355

您好!  

我在 I2C 从模式下运行 MSP430fr2355。 由于重复启动以及我希望对同一寄存器进行读写操作、我需要知道发送或接收方向。 我测试了以下内容:

driverlib 函数、在16MHz 时钟下花费了大约500个时钟周期:  

CheckStatus_UCBxCTLW0 = EUSCI_B_I2C_getMode (EUSCI_B0_BASE);
bitUCTR =((checkStatus_UCBxCTLW0 & UCTR)>> 4);

if (bitUCTR = 0x01){
  MasterWriteMode = 0;
  MasterReadMode = 1;

否则{
  MasterWriteMode = 1;
  MasterReadMode = 0;

我尝试的另一种方法是直接使用寄存器、该寄存器在 16MHz 时钟下也花费了大约300个时钟周期:  

MasterReadMode =(((UCB0IFG & UCTXIFG0)>> 1);
MasterWriteMode = UCB0IFG & UCRXIFG0;

主器件读/写意味着主器件正在从 MSP430从器件读取或写入 MSP430从器件。

我尝试的另一种方法是直接监控 UCBxCTLW0中的 UCTR 位、此处未对此进行说明。  

我遇到的问题是、当我在没有任何断点或 _delay_cycles (300)的情况下进行调试时、代码无法正常工作、因为它为我提供了检测到的主模式的错误状态。 例如、如果主器 件正在写入 MSP430从器件、则硬件会立即检测到该模式、但标志在另外300个时钟周期左右不会更新。  

我可以在代码中保留延迟、但我真的不喜欢这样的延迟。 从设备无法知道主设备将在高级模式下发送什么内容。  

数据表都指示 UCTR 位是要监控的位、但它无法正常工作或速度慢于我希望看到的速度。 当我处于 RX 模式接收寄存器地址时、我需要检测它。  

谢谢

Sagi  

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

     硬件会立即检测到该模式、但标志不会在另300个时钟周期左右更新

    何时"立即"? 在接收到 SLA 字节后、(从器件) I2C 单元才知道是读取还是写入。 使用400kHz I2C 时钟时、发送 SLA 字节(9位)至少需要(9/400kHz)=22.5usec 或(22.5*16)=360时钟(16MHz)、测量自开始条件结束时算起。

    在用户指南(SLAU445I)中的何处插入 delay_cycles ()?

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

    您好、Bruce、  

    感谢你的答复。

    等待时钟的数量是有道理的、但我很困惑为什么在收到 SLA 后需要等待标志、这就是为什么标志在那里、所以硬件在程序中等待而不是我。

    我要附上我的代码、以便您可以看到我在做什么。 在坚果壳中、我从 SLA=0x60读取和写入。 写入时、数据传输为0x60W 0x10 0xAA 0xBB、用于写入两个字节。 为了进行读取、主器件正在执行从器件返回的重复起始0x60W 0x10 0x60R 0xxx 0xxx 两个字节。 您可以在下图中看到重复开始的读取事务。  

    在 SLAU445I 中、没有一个图是我看到的、因为我的主设备正在使用重复起始。 但我看到读数有问题、因此图24-9更像是我所看到的内容、但并非完全正确。 不完全是因为我使用寄存器地址模式 RX_REG_ADDRESS_MODE 来启动延迟。 如果我重复启动、我不确定这是正确的状态。  

    我很困惑、因为 SLAU445I 未概述重复启动期间发生的情况、以及在 SLA/W 和寄存器之后收到另一个 SLA/R 时发生的情况。 不管怎样、我需要知道何时监控 UCTR 标志、我不确定将监控代码放在何处并决定是读取还是写入。  

    我假设在第一个 SLA/W 0x60W 之后、MSP430检测到正在调用它、UCTR 是接收模式、 然后、它接收0x10、我处理状态 RX_REG_ADDRESS_MODE 并调用 checkUCTRbit()、由于在16MHz 时等待300个时钟周期、它允许 SLA/R 0x60R 进入并更新标志、在等待我调用 I2C_Slave_ProcessCMD (ReceiveRegAddr)之后; 它将根据用于读取或写入的 UCTR 位更改状态。 我希望有更好的方法来处理这一重复的开始。 欢迎提出任何建议。  

    出于某种原因、当主器件写入时、我不会看到相同的延迟、我假设标志已更新、因为我没有获得重复启动、因此没有其他 SLA/R   

    代码用于读取和写入、但我必须在主器件中打开时钟拉伸才能使其正常工作。  

    这是状态机的代码。 在案例 USCI_I2C_UCRXIFG0部分以及  RX_REG_ADDRESS_MODE 和 checkUCTRbit ()中查看中断矢量。

    代码目前有点乱、抱歉。 我刚才添加了用于具有2字节缓冲器的 R/W 的寄存器0x10。

    //******************************************************************************
    //I2C Slave with 3 different register data response.
    //Slave address is 0x48 (7-bit).
    //register address | Data byte length
    //0x00             | 0x01
    //0x01             | 0x02
    //0x02             | 0x06
    //
    //                                     /|\ /|\
    //                   MSP430FR2355      4.7k |
    //                 -----------------    |  4.7k
    //            /|\ |             P1.3|---+---|-- I2C Clock (UCB0SCL)
    //             |  |                 |       |
    //             ---|RST          P1.2|-------+-- I2C Data (UCB0SDA)
    //                |                 |
    
    //******************************************************************************
    #include <msp430.h>
    #include "driverlib.h"
    //#include "IQmathLib.h"
    #include <stdint.h>
    
    #define LED_GRN_OUT    P1OUT
    #define LED_GRN_BIT    GPIO_PIN6
    #define LED_GRN_PORT   GPIO_PORT_P6
    #define LED_RED_OUT    P6OUT
    #define LED_RED_BIT    GPIO_PIN0
    #define LED_RED_PORT   GPIO_PORT_P1
    
    
    #define SLAVE_ADDR  0x60
    
    // CMD_TYPE_X_SLAVE are example register address commands the master sends to the slave.
    #define CMD_TYPE_0_SLAVE      0 //0x00
    #define CMD_TYPE_1_SLAVE      1 //0x01
    #define CMD_TYPE_2_SLAVE      2 //0x02
    
    // CMD_TYPE_X_MASTER are example register address commands the slave sends to the master.
    #define CMD_TYPE_0_MASTER      3 //0x03
    #define CMD_TYPE_1_MASTER      4 //0x04
    #define CMD_TYPE_2_MASTER      5 //0x05
    
    #define CMD_TYPE_10_MS       0x10 //
    
    
    #define TYPE_0_LENGTH   2
    #define TYPE_1_LENGTH   2
    #define TYPE_2_LENGTH   6
    
    #define READ_RESULT_REGISTER
    
    #define MAX_BUFFER_SIZE     20
    
    //SlaveTypeX are example response buffers initialized in the slave, they will be sent by the slave to the master.
    uint8_t SlaveType2 [TYPE_2_LENGTH] = {0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
    uint8_t SlaveType1 [TYPE_1_LENGTH] = {0x50, 0x60};   //This will be the actual temperature reading. format is 50.50 Deg C.
    uint8_t SlaveType0 [TYPE_0_LENGTH] = {0x60, 0x40};   //This will allow reading the temperature setpoint. format is 60.40 Deg C.
    
    //MasterTypeX are example response buffers initialized in the slave, they will be sent by the master to the slave.
    uint8_t MasterType2 [TYPE_2_LENGTH] = {0x00};
    uint8_t MasterType1 [TYPE_1_LENGTH] = {0x00, 0x00};
    uint8_t MasterType0 [TYPE_0_LENGTH] = {0x40, 0x30};   //This is the temperature setpoint. format is 40.30 Deg C.
    
    uint8_t MS_ModeType10 [TYPE_0_LENGTH] = {0x01, 0x02};   //Test for R/W register
    
    uint8_t ReceiveRegAddr = 0;                     //The Register Address/Command to use
    uint8_t ReceiveBuffer[MAX_BUFFER_SIZE] = {0};   //ReceiveBuffer: Buffer used to receive data in the ISR
    uint8_t RXByteCtr = 0;                          //RXByteCtr: Number of bytes left to receive
    uint8_t ReceiveIndex = 0;                       //ReceiveIndex: The index of the next byte to be received in ReceiveBuffer
    uint8_t TransmitBuffer[MAX_BUFFER_SIZE] = {0};  //TransmitBuffer: Buffer used to transmit data in the ISR
    uint8_t TXByteCtr = 0;                          //TXByteCtr: Number of bytes left to transfer
    uint8_t TransmitIndex = 0;                      //TransmitIndex: The index of the next byte to be transmitted in TransmitBuffer
    
    uint8_t MasterWriteMode = 0;                    //Master Write to the slave, the slave will be in RX mode.
    uint8_t MasterReadMode = 0;                     //Master Read from the slave, the slave will be in TX mode.
    uint8_t bitUCTR = 0;                            //This monitors the UCTR bit (Transmit or Receive)
    uint8_t checkStatus_UCBxCTLW0 = 0;
    
    
    
    // General I2C State Machine ***************************************************
    typedef enum I2C_ModeEnum{
        IDLE_MODE,
        NC_MODE,
        TX_REG_ADDRESS_MODE,
        RX_REG_ADDRESS_MODE,
        TX_DATA_MODE,
        RX_DATA_MODE,
        SWITCH_TO_RX_MODE,
        SWITCH_TO_TX_MODE,
        TIMEOUT_MODE,
        NACK_MODE
    } I2C_Mode;
    
    /* Used to track the state of the software state machine*/
    I2C_Mode SlaveMode = RX_REG_ADDRESS_MODE;
    
    //Functions prototype:
    void I2C_Slave_ProcessCMD(uint8_t cmd);
    void I2C_Slave_TransactionDone(uint8_t cmd);
    void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count);
    void initClockTo16MHz();
    void initI2C();
    void initGPIO();
    void checkUCTRbit();
    
    
    // MAIN ******************************************************************************
    int main(void) {
        WDT_A_hold(WDT_A_BASE);   // Stop watchdog timer
        FRCTL0 = FRCTLPW | NWAITS_2;
    
    
        initClockTo16MHz();
        initGPIO();
        initI2C();
    
        __enable_interrupt();       // Enable maskable interrupt
    
        while (1){
            GPIO_toggleOutputOnPin(LED_RED_PORT, LED_RED_BIT);
            GPIO_toggleOutputOnPin(LED_GRN_PORT, LED_GRN_BIT);
            _delay_cycles(1000000);
    
    
        }
    
    }
    
    // I2C Interrupt ***************************************************************
    #pragma vector = USCI_B0_VECTOR
    __interrupt void USCI_B0_ISR(void)
    
    {
      uint8_t rx_val = 0;                       //Value read from UCB0RXBUF
      switch(__even_in_range(UCB0IV, USCI_I2C_UCBIT9IFG))
      {
        case USCI_NONE:          break;         // UCIV Vector 0: No interrupts
        case USCI_I2C_UCALIFG:   break;         // UCIV Vector 2: ALIFG, Arbitration Lost Interrupt
        case USCI_I2C_UCNACKIFG:                // UCIV Vector 4: NACKIFG, Not Acknowledge Interrupt
          break;
        case USCI_I2C_UCSTTIFG:           // UCIV Vector 6: STTIFG, Start condition detected
            //UCB0IE &= ~UCSTTIE;                     //Disable Start condition Interrupt
         // bitUCTR = (UCB0CTLW0 >> 0x04) & 0x01;   //Checking UCTR bit for read or write. UCTR RX=0, TX=1.
         // if (bitUCTR == 0x01){
         //     MasterWriteMode = 0;
         //     MasterReadMode = 1;
         // }
         // else {
         //     MasterWriteMode = 1;
         //     MasterReadMode = 0;
         //     I2C_Slave_ProcessCMD(ReceiveRegAddr);
         // }
            break;
        case USCI_I2C_UCSTPIFG:                 // UCIV Vector 8: STPIFG, Stop condition detected Interrupt
            UCB0IFG &= ~(UCTXIFG0);
            break;
        case USCI_I2C_UCRXIFG3:  break;         // UCIV Vector 10: RXIFG3
        case USCI_I2C_UCTXIFG3:  break;         // UCIV Vector 12: TXIFG3
        case USCI_I2C_UCRXIFG2:  break;         // UCIV Vector 14: RXIFG2
        case USCI_I2C_UCTXIFG2:  break;         // UCIV Vector 16: TXIFG2
        case USCI_I2C_UCRXIFG1:  break;         // UCIV Vector 18: RXIFG1
        case USCI_I2C_UCTXIFG1:  break;         // UCIV Vector 20: TXIFG1
        case USCI_I2C_UCRXIFG0:                 // UCIV Vector 22: RXIFG0
            rx_val = UCB0RXBUF;
            switch (SlaveMode)
            {
              case (RX_REG_ADDRESS_MODE):
                  ReceiveRegAddr = rx_val;
                  //Check if the register address exist. If not, Send a NACK to release the clock line. Each register should be listed.
                  if (
                              rx_val == CMD_TYPE_0_SLAVE    ||
                              rx_val == CMD_TYPE_1_SLAVE    ||
                              rx_val == CMD_TYPE_2_SLAVE    ||
                              rx_val == CMD_TYPE_0_MASTER   ||
                              rx_val == CMD_TYPE_1_MASTER   ||
                              rx_val == CMD_TYPE_2_MASTER   ||
                              rx_val == CMD_TYPE_10_MS) {
    
                              checkUCTRbit();
                              I2C_Slave_ProcessCMD(ReceiveRegAddr);
                              //UCB0IE |= UCSTTIE;                //Enable Start condition Interrupt to check if restart
    
                              }
    
                  else {
                      ReceiveIndex = 0;
                      TransmitIndex = 0;
                      RXByteCtr = 0;
                      TXByteCtr = 0;
                      UCB0CTLW0 |= UCTXNACK;            //Send a NACK by setting the NACK bit
                      UCB0CTLW0 |= UCSWRST;             //Reset the I2C internal state machine
                      UCB0CTLW0 &= ~UCTXNACK;           //Set the NACK bit = 0
                      SlaveMode = RX_REG_ADDRESS_MODE;  //Return the state machine to receive registers
                      UCB0CTLW0 &= ~UCSWRST;            //Take the I2C internal state machine out of reset
                      UCB0IE &= ~(UCTXIE);              //TX Interrupt disable
                      UCB0IE |= UCRXIE;                 //RX Interrupt enable
                      }
    
                  break;
              case (RX_DATA_MODE):
                  ReceiveBuffer[ReceiveIndex++] = rx_val;
                  RXByteCtr--;
                  if (RXByteCtr == 0)
                  {
                      //Done Receiving MSG
                      SlaveMode = RX_REG_ADDRESS_MODE;
                      UCB0IE &= ~(UCTXIE);
                      UCB0IE |= UCRXIE;                          // Enable RX interrupt
                      I2C_Slave_TransactionDone(ReceiveRegAddr);
                  }
                  break;
              default:
                  __no_operation();
                  break;
            }
            break;
        case USCI_I2C_UCTXIFG0:                 // Vector 24: TXIFG0
            switch (SlaveMode)
            {
              case (TX_DATA_MODE):
                  UCB0TXBUF = TransmitBuffer[TransmitIndex++];
                  TXByteCtr--;
                  if (TXByteCtr == 0)
                  {
                      //Done Transmitting MSG
                      SlaveMode = RX_REG_ADDRESS_MODE;
                      UCB0IE &= ~(UCTXIE);
                      UCB0IE |= UCRXIE;                          // Enable RX interrupt
                      I2C_Slave_TransactionDone(ReceiveRegAddr);
                  }
                  break;
              default:
                  __no_operation();
                  break;
            }
            break;                              // Interrupt Vector: I2C Mode: UCTXIFG
        default:
            break;
      }
    }
    
    void I2C_Slave_ProcessCMD(uint8_t cmd) //cmd = register address received.
    {
        ReceiveIndex = 0;
        TransmitIndex = 0;
        RXByteCtr = 0;
        TXByteCtr = 0;
    
        switch (cmd)
        {
            case (CMD_TYPE_0_SLAVE):                      //Send register 0x00 from slave to Master
                SlaveMode = TX_DATA_MODE;
                TXByteCtr = TYPE_0_LENGTH;
                //Fill the TransmitBuffer
                CopyArray(SlaveType0, TransmitBuffer, TYPE_0_LENGTH);
                UCB0IE &= ~UCRXIE;                       // Disable RX interrupt
                UCB0IE |= UCTXIE;                        // Enable TX interrupt
                break;
            case (CMD_TYPE_1_SLAVE):                     //Send register 0x01 from slave to Master
                SlaveMode = TX_DATA_MODE;
                TXByteCtr = TYPE_1_LENGTH;
                //Fill the TransmitBuffer
                CopyArray(SlaveType1, TransmitBuffer, TYPE_1_LENGTH);
                UCB0IE &= ~UCRXIE;                       // Disable RX interrupt
                UCB0IE |= UCTXIE;                        // Enable TX interrupt
                break;
            case (CMD_TYPE_2_SLAVE):                     //Send register 0x02 from slave to Master
                SlaveMode = TX_DATA_MODE;
                TXByteCtr = TYPE_2_LENGTH;
                //Fill the TransmitBuffer
                CopyArray(SlaveType2, TransmitBuffer, TYPE_2_LENGTH);
                UCB0IE &= ~UCRXIE;                       // Disable RX interrupt
                UCB0IE |= UCTXIE;                        // Enable TX interrupt
                break;
            case (CMD_TYPE_0_MASTER):
                SlaveMode = RX_DATA_MODE;
                RXByteCtr = TYPE_0_LENGTH;
                UCB0IE &= ~UCTXIE;                       // Disable TX interrupt
                UCB0IE |= UCRXIE;                        // Enable RX interrupt
                break;
            case (CMD_TYPE_1_MASTER):
                SlaveMode = RX_DATA_MODE;
                RXByteCtr = TYPE_1_LENGTH;
                UCB0IE &= ~UCTXIE;                       // Disable TX interrupt
                UCB0IE |= UCRXIE;                        // Enable RX interrupt
                break;
            case (CMD_TYPE_2_MASTER):
                SlaveMode = RX_DATA_MODE;
                RXByteCtr = TYPE_2_LENGTH;
                UCB0IE &= ~UCTXIE;                       // Disable TX interrupt
                UCB0IE |= UCRXIE;                        // Enable RX interrupt
                break;
            case (CMD_TYPE_10_MS):
                    if (MasterWriteMode){
                        SlaveMode = RX_DATA_MODE;
                        RXByteCtr = TYPE_0_LENGTH;
                        UCB0IE &= ~UCTXIE;               // Disable TX interrupt
                        UCB0IE |= UCRXIE;                // Enable RX interrupt
                         break;
                    }
                    else {
                        SlaveMode = TX_DATA_MODE;
                        TXByteCtr = TYPE_0_LENGTH;
                        //Fill the TransmitBuffer
                        CopyArray(MS_ModeType10, TransmitBuffer, TYPE_0_LENGTH);
                        UCB0IE &= ~UCRXIE;                // Disable RX interrupt
                        UCB0IE |= UCTXIE;                 // Enable TX interrupt
                        break;
                    }
    
    
            default:
                __no_operation();
                break;
        }
    }
    
    void I2C_Slave_TransactionDone(uint8_t cmd)
    {
        switch (cmd)
        {
            case (CMD_TYPE_0_SLAVE):                    //Register 0x00 was sent to the slave
                break;
            case (CMD_TYPE_1_SLAVE):                    //Register 0x01 was sent to the slave
                break;
            case (CMD_TYPE_2_SLAVE):                    //Register 0x02 was sent to the slave
                break;
            case (CMD_TYPE_0_MASTER):
                CopyArray(ReceiveBuffer, MasterType0, TYPE_0_LENGTH);
                break;
            case (CMD_TYPE_1_MASTER):
                CopyArray(ReceiveBuffer, MasterType1, TYPE_1_LENGTH);
                break;
            case (CMD_TYPE_2_MASTER):
                CopyArray(ReceiveBuffer, MasterType2, TYPE_2_LENGTH);
                break;
            case (CMD_TYPE_10_MS):
                    if (MasterWriteMode){
                        CopyArray(ReceiveBuffer, MS_ModeType10, TYPE_0_LENGTH);
                        break;
                    }
                    else {
                        break;
                    }
    
            default:
                __no_operation();
                break;
        }
    }
    
    void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count)
    {
        uint8_t copyIndex = 0;
        for (copyIndex = 0; copyIndex < count; copyIndex++)
        {
            dest[copyIndex] = source[copyIndex];
        }
    }
    
    void initClockTo16MHz()
    {
        // Configure two FRAM waitstate as required by the device datasheet for MCLK
        // operation beyond 8MHz _before_ configuring the clock system.
        FRCTL0 = FRCTLPW | NWAITS_2;
    
        __bis_SR_register(SCG0);    // disable FLL
        CSCTL3 |= SELREF__REFOCLK;  // Set REFO as FLL reference source
        CSCTL0 = 0;                 // clear DCO and MOD registers
        CSCTL1 &= ~(DCORSEL_7);     // Clear DCO frequency select bits first
        CSCTL1 |= DCORSEL_5;        // Set DCO = 16MHz
        CSCTL2 = FLLD_0 + 487;      // set to fDCOCLKDIV = (FLLN + 1)*(fFLLREFCLK/n)
                                    //                   = (487 + 1)*(32.768 kHz/1)
                                    //                   = 16 MHz
    
        __delay_cycles(3);
        __bic_SR_register(SCG0);                        // enable FLL
        while(CSCTL7 & (FLLUNLOCK0 | FLLUNLOCK1));      // FLL locked
    
        CSCTL4 = SELMS__DCOCLKDIV | SELA__REFOCLK;
    }
    
    // Device Initialization *******************************************************
    void initGPIO()
    {
        GPIO_setAsOutputPin(GPIO_PORT_P1, GPIO_PIN0);    //LED1
        GPIO_setAsOutputPin(GPIO_PORT_P6, GPIO_PIN6);    //LED2
    
        //Configure I2C pins, Pins 1.2 and 1.3, these are bi-directional pins.
        //P1SEL0 |= BIT2 | BIT3;
        //P1SEL1 &= ~(BIT2 | BIT3);
    
        GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P1, GPIO_PIN2, GPIO_PRIMARY_MODULE_FUNCTION); //I2C SDA
        GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P1, GPIO_PIN3, GPIO_PRIMARY_MODULE_FUNCTION); //I2C SCL
    
    
        PM5CTL0 &= ~LOCKLPM5;
    }
    
    void initI2C()
    {
        //UCB0CTLW0 = UCSWRST;                      // Software reset enabled
        //UCB0CTLW0 |= UCMODE_3 | UCSYNC;           // I2C mode, sync mode
        //UCB0I2COA0 = SLAVE_ADDR | UCOAEN;         // Own Address and enable
        //UCB0CTLW0 &= ~UCSWRST;                    // clear reset register
        //UCB0IE |= UCRXIE + UCSTPIE;               //Register UCBxI2CIE (page 471 family guide),RX Interrupt enable, stop condition enable,
    
        //Initialize Slave
        EUSCI_B_I2C_initSlaveParam param = {0};
        param.slaveAddress = SLAVE_ADDR;
        param.slaveAddressOffset = EUSCI_B_I2C_OWN_ADDRESS_OFFSET0;
        param.slaveOwnAddressEnable = EUSCI_B_I2C_OWN_ADDRESS_ENABLE;
        EUSCI_B_I2C_initSlave(EUSCI_B0_BASE, &param);
    
        //EUSCI_B_I2C_setMode (EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_MODE);//EUSCI_B_I2C_RECEIVE_MODE);
        EUSCI_B_I2C_enable(EUSCI_B0_BASE);
        //EUSCI_B_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0 + EUSCI_B_I2C_STOP_INTERRUPT + EUSCI_B_I2C_START_INTERRUPT );
        EUSCI_B_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0 + EUSCI_B_I2C_STOP_INTERRUPT);
    
        //Timeout
        //EUSCI_B_I2C_setTimeout(EUSCI_B0_BASE,EUSCI_B_I2C_TIMEOUT_34_MS);
    
    }
    
    void checkUCTRbit()
    {
        _delay_cycles(300);
        //checkStatus_UCBxCTLW0 = EUSCI_B_I2C_getMode(EUSCI_B0_BASE);
        //bitUCTR = ((checkStatus_UCBxCTLW0 & UCTR) >> 4);
    
        MasterReadMode  = ((UCB0IFG & UCTXIFG0) >> 1);
        MasterWriteMode = UCB0IFG & UCRXIFG0;
    
        //if (bitUCTR == 0x01){
        //    MasterWriteMode = 0;
        //    MasterReadMode = 1;
        //}
        //else {
        //    MasterWriteMode = 1;
        //    MasterReadMode = 0;
        //}
    }
    

    在下图中、您可以看到读取事务、并且可以看到 SLA 0x60R 之后的重复开始和延迟。  

    我使用模拟发现2来连接 MSP430。 AD2是主器件、MSP430是从器件。  

    在另一个主题中、我感到惊讶的是、TI 没有一个 I2C 从设备的示例代码可用于对同一寄存器进行读取和写入、这正是我在这里尝试使用寄存器0x10执行的操作。 您是否知道是否存在类似的代码?

    欢迎提出任何意见。  

    谢谢

    Sagi  

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

    在接收到 RXIFG 后、您可以检查 UCTR 或 RXIFG、但在读取 RXBUF 后(尤其是)会清除 RXIFG。 我想您看到了两件事:

    1) 1)在 I2C 写入时、直到下一个字节到达(至少360个 CPU 时钟之后)、您才会看到另一个 RXIFG。

    2) 2)读取 RXBUF 会释放 I2C 流控制以发送 ACK。 如果主器 件想要读取某个内容、它会立即发出重复启动命令(对于 AD2、可能非常快)、这意味着当您看到 UCTR 已经无效。

    唯一可以说的是(a)在您看到 RXIFG 置位时、您处于从机接收器模式、(b) TXIFG 和从机发送器也是如此。

    --------

    一段时间前、我写了一个骨架 I2C 从器件进行实验。 它使用了一个非常简单(但非常常见)的模型:一组字节寄存器(我想是16)、可由主器件读取和写入。 主器件可以自动递增的方式读取或写入连续寄存器(多字节事务)。 所有寄存器都没有副作用(这不是实验的目的)、但它们可能会有一些额外的代码。

    它有3个状态:

    1)寄存器值(存储器中的简单 uint8_t 数组)

    2) 2)数组的索引。

    3)当前事务中的字节计数器(有效为0或>0)。

    其全部逻辑:

    1) 1)在一个 STTIFG 上:计数器= 0。

    2)在 TXIFG 上:TXBUF=Registers [index+];

    3)在 RXIFG 上、如果(计数器=0)索引=RXBUF、否则寄存器[index+]=RXBUF;++COUNTER

    使用合适的边界检查和初始化/跟踪、我认为大约有100行代码。