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.

[参考译文] 使用 I2C 主设备发送数据时出现问题(MSP430FR2355)

Guru**** 2390180 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/1162827/problems-sending-data-with-the-i2c-master-msp430fr2355

主题中讨论的其他器件:MSP430FR2355

大家好、

我使用 MSP430FR2355控制器、同时希望通过 I2C 读取和写入 EEPROM。 在使用其他控制器之前、我不熟悉 MSP 控制器。
出于测试目的、我使用了 TI 的示例 Eusci_b_I2C_ex4_masterTXMultiple。
我已经配置了 IO_Ports、因此我已经可以发送一些内容。 也就是说、如果我使用 EUSCI_B_I2C_masterSendMultiByteStart 函数并发送0x50作为数据、例如、它永远不会工作。 数据0x21始终显示在逻辑分析仪中。 无论我希望通过此函数发送什么数据。 我还使用了示例 Eusci_b_i2c_masterTXSingle、我遇到了相同的问题。 有人知道问题是什么、可以帮助我吗? 我还使用了该示例、它始终发送0x21。
感谢你的帮助

#include "driverlib.h"
#include "Board.h"
#include <stdint.h>
#include "I2C/I2C_Interface.h"

//*****************************************************************************
//
//Set the address for slave module. This is a 7-bit address sent in the
//following format:
//[A6:A5:A4:A3:A2:A1:A0:RS]
//
//A zero in the "RS" position of the first byte means that the master
//transmits (sends) data to the selected slave, and a one in this position
//means that the master receives data from the slave.
//
//*****************************************************************************
#define SLAVE_ADDRESS 0b10100001

#define EEPROM_Address_R 0b10100001//0xA1           ///A1 A3  AF AD
#define EEPROM_Address_W 0b10100000//0xA0           ///A0 A2  AE AC

unsigned char EEPROM_Read(unsigned int add);         //Random Address Read
//*****************************************************************************
//
//Target frequency for SMCLK in kHz
//
//*****************************************************************************
#define CS_SMCLK_DESIRED_FREQUENCY_IN_KHZ   1000

//*****************************************************************************
//
//SMCLK/FLLRef Ratio
//
//*****************************************************************************
#define CS_SMCLK_FLLREF_RATIO   30

// Pointer to TX data
uint8_t TXData = 0;
uint8_t TXByteCtr;

void main(void)
{
    WDT_A_hold(WDT_A_BASE);

    //Set DCO FLL reference = REFO
    CS_initClockSignal(
            CS_FLLREF,
            CS_REFOCLK_SELECT,
            CS_CLOCK_DIVIDER_1
        );

    //Set Ratio and Desired MCLK Frequency and initialize DCO
    CS_initFLLSettle(
            CS_SMCLK_DESIRED_FREQUENCY_IN_KHZ,
            CS_SMCLK_FLLREF_RATIO
            );

    //Set ACLK = VLO with frequency divider of 1
    CS_initClockSignal(
            CS_ACLK,
            CS_VLOCLK_SELECT,
            CS_CLOCK_DIVIDER_1
            );

    //Set SMCLK = DCO with frequency divider of 1
    CS_initClockSignal(
            CS_SMCLK,
            CS_DCOCLKDIV_SELECT,
            CS_CLOCK_DIVIDER_1
            );

    //Set MCLK = DCO with frequency divider of 1
    CS_initClockSignal(
            CS_MCLK,
            CS_DCOCLKDIV_SELECT,
            CS_CLOCK_DIVIDER_1
            );

    // Configure Pins for I2C
    GPIO_setAsPeripheralModuleFunctionInputPin(
        GPIO_PORT_UCB0SCL,
        GPIO_PIN_UCB0SCL,
        GPIO_FUNCTION_UCB0SCL
    );
    GPIO_setAsPeripheralModuleFunctionInputPin(
        GPIO_PORT_UCB0SDA,
        GPIO_PIN_UCB0SDA,
        GPIO_FUNCTION_UCB0SDA
    );

    /*
     * Disable the GPIO power-on default high-impedance mode to activate
     * previously configured port settings
     */
    PMM_unlockLPM5();

    EUSCI_B_I2C_initMasterParam param = {0};
    param.selectClockSource = EUSCI_B_I2C_CLOCKSOURCE_SMCLK;
    param.i2cClk = CS_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);

    //Specify slave address
    EUSCI_B_I2C_setSlaveAddress(EUSCI_B0_BASE,
            SLAVE_ADDRESS
            );

    //Set Master in receive mode
    EUSCI_B_I2C_setMode(EUSCI_B0_BASE,
            EUSCI_B_I2C_TRANSMIT_MODE
            );

    //Enable I2C Module to start operations
    EUSCI_B_I2C_enable(EUSCI_B0_BASE);

    EUSCI_B_I2C_clearInterrupt(EUSCI_B0_BASE,
            EUSCI_B_I2C_TRANSMIT_INTERRUPT0 +
            EUSCI_B_I2C_NAK_INTERRUPT
            );
    //Enable master Receive interrupt
    EUSCI_B_I2C_enableInterrupt(EUSCI_B0_BASE,
            EUSCI_B_I2C_TRANSMIT_INTERRUPT0 +
            EUSCI_B_I2C_NAK_INTERRUPT
            );
//    while(1)
//    {
        __delay_cycles(500);                   // Delay between transmissions
//        TXByteCtr = 4;                          // Load TX byte counter
//        TXData = 0;

        while (EUSCI_B_I2C_SENDING_STOP == EUSCI_B_I2C_masterIsStopSent(EUSCI_B0_BASE));

        EUSCI_B_I2C_masterSendMultiByteStart(EUSCI_B0_BASE, 0x50);

        EUSCI_B_I2C_masterSendMultiByteStart(EUSCI_B0_BASE, 0x47);

        EUSCI_B_I2C_masterSendMultiByteStart(EUSCI_B0_BASE, 0x32);

        //__bis_SR_register(CPUOFF + GIE);        // Enter LPM0 w/ interrupts

        // Remain in LPM0 until all data
        // is TX'd
        // Increment data byte
//    }

        while(1)
        {}
}

//------------------------------------------------------------------------------
// The USCIAB0TX_ISR is structured such that it can be used to transmit any
// number of bytes by pre-loading TXByteCtr with the byte count. Also, TXData
// points to the next byte to transmit.
//------------------------------------------------------------------------------
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCI_B0_VECTOR
__interrupt
#elif defined(__GNUC__)
__attribute__((interrupt(USCI_B0_VECTOR)))
#endif
void USCIB0_ISR(void)
{
    switch(__even_in_range(UCB0IV, USCI_I2C_UCBIT9IFG))
  {
        case USCI_NONE:             // No interrupts break;
            break;
        case USCI_I2C_UCALIFG:      // Arbitration lost
            break;
        case USCI_I2C_UCNACKIFG:    // NAK received (master only)
            //resend start if NACK
            EUSCI_B_I2C_masterSendStart(EUSCI_B0_BASE);
            break;
        case USCI_I2C_UCTXIFG0:     // TXIFG0
            // Check TX byte counter
//            if (TXByteCtr)
//            {
//                EUSCI_B_I2C_masterSendMultiByteNext(EUSCI_B0_BASE, TXData++);
//                // Decrement TX byte counter
//                TXByteCtr--;
//            }
//            else
//            {
//                EUSCI_B_I2C_masterSendMultiByteStop(EUSCI_B0_BASE);
//                // Exit LPM0
//                __bic_SR_register_on_exit(CPUOFF);
//            }
            break;
        default:
            break;
  }
}

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

    >#define SLAVE_ADDRESS 0b10100001

    这不是一个7位地址。 R/W 位不是地址的一部分。 顶部1位被删除、这将导致0x21地址。

    我怀疑您的意思(但请查看您的 EEPROM 数据表):

    > #define SLAVE_ADDRESS 0b01010000  // I2C 地址= 0x50

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

    Bruce、您好!
    我现在已将从器件地址更改为0x50、如图所示、我现在从 EEPROM 获得 ACK。 但现在始终发送 Setup 写入0x50。 在第一张图片中、我已通过 PIC 控制器成功读取具有 I2C 的 EEPROM。 它如何与 MSP 的功能配合使用。 我还想发送 Setup 读取、但如果我将0x50分配给从器件地址、它不起作用。 我需要写入0x50、0x15地址空间、读取0x50、然后读出我的0xAA。

    //*****************************************************************************
    #define SLAVE_ADDRESS 0b01010000//0b10100001
    
    #define EEPROM_Address_R 0b10100001//0xA1           ///A1 A3  AF AD
    #define EEPROM_Address_W 0b10100000//0xA0           ///A0 A2  AE AC
    
    unsigned char EEPROM_Read(unsigned int add);         //Random Address Read
    //*****************************************************************************
    //
    //Target frequency for SMCLK in kHz
    //
    //*****************************************************************************
    #define CS_SMCLK_DESIRED_FREQUENCY_IN_KHZ   1000
    
    //*****************************************************************************
    //
    //SMCLK/FLLRef Ratio
    //
    //*****************************************************************************
    #define CS_SMCLK_FLLREF_RATIO   30
    
    // Pointer to TX data
    uint8_t TXData = 0;
    uint8_t TXByteCtr;
    
    void main(void)
    {
        WDT_A_hold(WDT_A_BASE);
    
        //Set DCO FLL reference = REFO
        CS_initClockSignal(
                CS_FLLREF,
                CS_REFOCLK_SELECT,
                CS_CLOCK_DIVIDER_1
            );
    
        //Set Ratio and Desired MCLK Frequency and initialize DCO
        CS_initFLLSettle(
                CS_SMCLK_DESIRED_FREQUENCY_IN_KHZ,
                CS_SMCLK_FLLREF_RATIO
                );
    
        //Set ACLK = VLO with frequency divider of 1
        CS_initClockSignal(
                CS_ACLK,
                CS_VLOCLK_SELECT,
                CS_CLOCK_DIVIDER_1
                );
    
        //Set SMCLK = DCO with frequency divider of 1
        CS_initClockSignal(
                CS_SMCLK,
                CS_DCOCLKDIV_SELECT,
                CS_CLOCK_DIVIDER_1
                );
    
        //Set MCLK = DCO with frequency divider of 1
        CS_initClockSignal(
                CS_MCLK,
                CS_DCOCLKDIV_SELECT,
                CS_CLOCK_DIVIDER_1
                );
    
        // Configure Pins for I2C
        GPIO_setAsPeripheralModuleFunctionInputPin(
            GPIO_PORT_UCB0SCL,
            GPIO_PIN_UCB0SCL,
            GPIO_FUNCTION_UCB0SCL
        );
        GPIO_setAsPeripheralModuleFunctionInputPin(
            GPIO_PORT_UCB0SDA,
            GPIO_PIN_UCB0SDA,
            GPIO_FUNCTION_UCB0SDA
        );
    
        /*
         * Disable the GPIO power-on default high-impedance mode to activate
         * previously configured port settings
         */
        PMM_unlockLPM5();
    
        EUSCI_B_I2C_initMasterParam param = {0};
        param.selectClockSource = EUSCI_B_I2C_CLOCKSOURCE_SMCLK;
        param.i2cClk = CS_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);
    
        Specify slave address
        EUSCI_B_I2C_setSlaveAddress(EUSCI_B0_BASE,
                SLAVE_ADDRESS
                );
    
        //Set Master in receive mode
        EUSCI_B_I2C_setMode(EUSCI_B0_BASE,
                EUSCI_B_I2C_TRANSMIT_MODE
                );
    
        //Enable I2C Module to start operations
        EUSCI_B_I2C_enable(EUSCI_B0_BASE);
    
        EUSCI_B_I2C_clearInterrupt(EUSCI_B0_BASE,
                EUSCI_B_I2C_TRANSMIT_INTERRUPT0 +
                EUSCI_B_I2C_NAK_INTERRUPT
                );
        //Enable master Receive interrupt
        EUSCI_B_I2C_enableInterrupt(EUSCI_B0_BASE,
                EUSCI_B_I2C_TRANSMIT_INTERRUPT0 +
                EUSCI_B_I2C_NAK_INTERRUPT
                );
    //    while(1)
    //    {
           // __delay_cycles(500);                   // Delay between transmissions
    //        TXByteCtr = 4;                          // Load TX byte counter
    //        TXData = 0;
    
            counterA++;
            //while (EUSCI_B_I2C_SENDING_STOP == EUSCI_B_I2C_masterIsStopSent(EUSCI_B0_BASE));
            EUSCI_B_I2C_masterSendMultiByteStart(EUSCI_B0_BASE, EEPROM_Address_W);
           __delay_cycles(50);
            counterB++;
            //while (EUSCI_B_I2C_SENDING_STOP == EUSCI_B_I2C_masterIsStopSent(EUSCI_B0_BASE));
            EUSCI_B_I2C_masterSendMultiByteStart(EUSCI_B0_BASE, 0x15);
            counterC++;
            __delay_cycles(50);
            EUSCI_B_I2C_masterSendMultiByteStart(EUSCI_B0_BASE, EEPROM_Address_R);
            counterD++;
            __delay_cycles(50);
            EUSCI_B_I2C_masterReceiveSingle(EUSCI_B0_BASE);
            counterE++;
           // __delay_cycles(500);
    //        while (EUSCI_B_I2C_SENDING_STOP == EUSCI_B_I2C_masterIsStopSent(EUSCI_B0_BASE));
    //        EUSCI_B_I2C_masterSendMultiByteStart(EUSCI_B0_BASE, 0x32);
    //        //__delay_cycles(500);
    //        while (EUSCI_B_I2C_SENDING_STOP == EUSCI_B_I2C_masterIsStopSent(EUSCI_B0_BASE));
           // __bis_SR_register(CPUOFF + GIE);        // Enter LPM0 w/ interrupts
    //
    //         Remain in LPM0 until all data
    //         is TX'd
    //         Increment data byte
    //    }
    
            while(1)
            {}
    }
    
    //------------------------------------------------------------------------------
    // The USCIAB0TX_ISR is structured such that it can be used to transmit any
    // number of bytes by pre-loading TXByteCtr with the byte count. Also, TXData
    // points to the next byte to transmit.
    //------------------------------------------------------------------------------
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector=USCI_B0_VECTOR
    __interrupt
    #elif defined(__GNUC__)
    __attribute__((interrupt(USCI_B0_VECTOR)))
    #endif
    void USCIB0_ISR(void)
    {
        switch(__even_in_range(UCB0IV, USCI_I2C_UCBIT9IFG))
      {
            case USCI_NONE:             // No interrupts break;
                break;
            case USCI_I2C_UCALIFG:      // Arbitration lost
                break;
            case USCI_I2C_UCNACKIFG:    // NAK received (master only)
                //resend start if NACK
                EUSCI_B_I2C_masterSendStart(EUSCI_B0_BASE);
                break;
            case USCI_I2C_UCTXIFG0:     // TXIFG0
                // Check TX byte counter
    //            if (TXByteCtr)
    //            {
    //                EUSCI_B_I2C_masterSendMultiByteNext(EUSCI_B0_BASE, TXData++);
    //                // Decrement TX byte counter
    //                TXByteCtr--;
    //            }
    //            else
    //            {
    //                EUSCI_B_I2C_masterSendMultiByteStop(EUSCI_B0_BASE);
    //                // Exit LPM0
    //                __bic_SR_register_on_exit(CPUOFF);
    //            }
                break;
            default:
                break;
      }
    }
    

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

    1) SendMultiByteStart()作为具有 SendMultiByteNext 和 SendMultiByteFinish 的组工作,即您调用 Start (一次)然后调用 Next (N-2次),然后调用 Finish (一次)以发送多字节事务。 您反复调用 Start、它会生成一个1字节(写入)事务的序列、这通常不是您想要的(使用 EEPROM)。

    1A)对于读取、执行(1)中的序列(对 Finish()的调用除外)来发送(EEPROM)存储器地址。 然后调用 EUSCI_B_I2C_masterReceiveStart 来执行重复启动并切换到读取模式。 然后调用 EUSCI_B_I2C_masterReceiveSingle (N-1次)、然后调用 EUSCI_B_I2C_masterReceiveMultiByteFinish 来接收最终字节。

    2)对于单字节(写入)事务、请使用 EUSCI_B_I2C_masterSendSingleByte ()。

    3) 3) I2C 单元为您发送 SLA 字节(地址+ R/W)、因此没有理由(永远)使用 EEPROM_Address_W/R

    4) 4)多字节函数设计为在没有中断的情况下运行、因此无需调用 clearInterrupt 和 enableInterrupt。

    [编辑:(5)您使用的是什么 EEPROM (器件型号)? 它们各不相同。]

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

    您好、Bruce、
    感谢您的回答、我现在使用这些命令进行了试用。 我现在可以从 EEPROM 读取1个字节。 但是、如果我调用两次命令以从其他地址读取、为什么它不起作用。 我是否忘记了另一条命令?

            EUSCI_B_I2C_masterSendStart(EUSCI_B0_BASE);
    
            EUSCI_B_I2C_masterSendSingleByte(EUSCI_B0_BASE, 0x36);
    
            EUSCI_B_I2C_masterReceiveStart(EUSCI_B0_BASE);
    
            EUSCI_B_I2C_masterReceiveMultiByteFinish(EUSCI_B0_BASE);

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

    它看起来是 这样的

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

    >      EUSCI_B_I2C_masterSendStart (EUSCI_B0_BASE);

    删除此行。 这最多是不必要的(SendSingleByte 执行整个事务)、在您的第二次调用中、它将启动读取、而不是写入。