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.

[参考译文] MSP430FR2676:msp430fr2676硬件 I2C 接收数据错误

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1075861/msp430fr2676-msp430fr2676-hardware-i2c-receiving-data-error

部件号:MSP430FR2676
“线程: LP5562测试”中讨论的其它部件

msp430fr2676硬件 I2C 首次执行接收一个额外的字节数据。

MCLK 16M,SMCLK 16M,I2C 速率400K,  从设备 lp5562,IDE CCS10

第一个

其他

i2c.h

//*****************************************************************************
//
//! ucb1_i2c.h - \b EUSCI_B1_I2C驱动程序头文件
//!
//! @author  CVZTS
//! @date    2022-01-27
//! @version V100R001SP0001
//
//*****************************************************************************

#ifndef __DRIVER_UCB1_I2C_H__
#define __DRIVER_UCB1_I2C_H__

#ifdef __cplusplus
extern "C" {
#endif

/*
 *  =============================== 返回码定义 =================================
 */
#define UCB1_I2C_SUCCESS        (0)     // 执行成功
#define UCB1_I2C_ERROR_BUSY     (-1)    // 数据总线忙
#define UCB1_I2C_ERROR_NAK      (-2)    // 设备未应答

/*
 *  ================================ 全局定义 ==================================
 */
#define UCB1_I2C_CS_SMCLK       (0)    // I2C模块时钟源SMCLK
#define UCB1_I2C_CS_ACLK        (1)    // I2C模块时钟源ACLK
#define UCB1_I2C_RATE_100K      (0)    // I2C接口速率100KBps
#define UCB1_I2C_RATE_400K      (1)    // I2C接口速率400KBps

/*
 *  ================================== API ====================================
 */

//*****************************************************************************
//
//! \brief 初始化UCB1_I2C接口
//!
//! \param[in] clkSrc  I2C模块时钟源
//!                    - \b UCB1_I2C_CS_SMCLK
//!                    - \b UCB1_I2C_CS_ACLK
//!
//! \param[in] clock   I2C模块时钟源频率(Hz)
//!
//! \param[in] rate    I2C接口速率
//!                    - \b UCB1_I2C_RATE_100K
//!                    - \b UCB1_I2C_RATE_400K
//!
//! \return none    
//! \note   none
//
//*****************************************************************************
extern void drv_InitUCB1I2C(uint8_t clkSrc, uint32_t clock, uint8_t rate);

//*****************************************************************************
//
//! \brief 设置设备地址
//!
//! \param[in] addr 设备地址
//!
//! \return none
//! \note   none
//
//*****************************************************************************
extern void drv_UCB1I2CSetSlaveAddress(uint8_t addr);

//*****************************************************************************
//
//! \brief 获取设备地址
//!
//! \param none
//!
//! \return 设备地址
//!
//! \note   none
//
//*****************************************************************************
extern uint8_t drv_UCB1I2CGetSlaveAddress(void);

//*****************************************************************************
//
//! \brief 设置I2C最大错误重试次数
//!
//! \param[in] retNum  最大重试次数(0-255)
//!
//! \return none
//! \note   none
//
//*****************************************************************************
extern void drv_UCB1I2CSetRetriesNumber(uint8_t retNum);

//*****************************************************************************
//
//! \brief 获取I2C最大错误重试次数
//!
//! \param none
//!
//! \return 最大错误重试次数
//!
//! \note   none
//
//*****************************************************************************
extern uint8_t drv_UCB1I2CGetRetriesNumber(void);

//*****************************************************************************
//
//! \brief I2C读取多字节数据
//!
//! \param[in] regAddr  起始寄存器地址
//! \param[in] dataPtr  保存已读取数据的指针
//! \param[in] size     读取数据多大小
//!
//! \return 如果成功返回  \b UCB1_I2C_SUCCESS
//!         否则返回      \b UCB1_I2C_ERROR_BUSY or \b UCB1_I2C_ERROR_NAK
//! \note   none
//
//*****************************************************************************
extern int16_t drv_UCB1I2CReadMultiByte(uint8_t regAddr, uint8_t *dataPtr, uint16_t size);

#ifdef __cplusplus
}
#endif

#endif // __DRIVER_UCB1_I2C_H__

I2C.c.

//*****************************************************************************
//
//! ucb1_i2c.c - \b EUSCI_B1_I2C驱动程序源文件
//!
//! @author  CVZTS
//! @date    2022-02-05
//! @version V100R001SP0001
//
//*****************************************************************************

/*
 *  =============================== 头文件引入 =================================
 */
#include "board.h"
#include "ucb1_i2c.h"
#include "uartprint/uartprint.h"

/*
 *  ================================ 全局定义 ==================================
 */
#define I2C_RETRIES_MAX     (3)     // 最大重试次数

/*
 *  ================================ 数据结构 ==================================
 */

// UCB1_I2C 信息存储块数据结构
typedef struct t_UCB1I2CBlock
{
    uint8_t retriesNumber;    // 最大重试次数
} UCB1I2CBlock;

/*
 *  ================================ 全局变量 ==================================
 */

// UCB1_I2C模块时钟源列表
static uint8_t g_clockSourceList[2] =
{
    [UCB1_I2C_CS_SMCLK] = EUSCI_B_I2C_CLOCKSOURCE_SMCLK,
    [UCB1_I2C_CS_ACLK]  = EUSCI_B_I2C_CLOCKSOURCE_ACLK
};

// UCB1_I2C接口速率列表
static uint32_t g_rateList[2] = 
{
    [UCB1_I2C_RATE_100K] = EUSCI_B_I2C_SET_DATA_RATE_100KBPS,
    [UCB1_I2C_RATE_400K] = EUSCI_B_I2C_SET_DATA_RATE_400KBPS
};

// UCB1_I2C 信息存储块
static UCB1I2CBlock g_block = {0};

/*
 *  ================================ 内部函数 ==================================
 */


/*
 *  ================================== API ====================================
 */

//*****************************************************************************
//
//! \brief 初始化UCB1_I2C接口
//!
//! \param[in] clkSrc  I2C模块时钟源
//!                    - \b UCB1_I2C_CS_SMCLK
//!                    - \b UCB1_I2C_CS_ACLK
//!
//! \param[in] clock   I2C模块时钟源频率(Hz)
//!
//! \param[in] rate    I2C接口速率
//!                    - \b UCB1_I2C_RATE_100K
//!                    - \b UCB1_I2C_RATE_400K
//!
//! \return none    
//! \note   none
//
//*****************************************************************************
void drv_InitUCB1I2C(uint8_t clkSrc, uint32_t clock, uint8_t rate)
{

    //
    // 设置I2C错误最大重试次数
    //
    g_block.retriesNumber = I2C_RETRIES_MAX;

    //
    // EUSCIA重新映射源选择
    //
    SYSCFG3 |= USCIB1RMP;

    //
    // EUSCI_B1_I2C 初始化
    //
    EUSCI_B_I2C_initMasterParam _param = {0};
    _param.selectClockSource    = g_clockSourceList[clkSrc];
    _param.i2cClk               = clock;
    _param.dataRate             = g_rateList[rate];
    _param.byteCounterThreshold = 0;
    _param.autoSTOPGeneration   = EUSCI_B_I2C_NO_AUTO_STOP;
    MAP_EUSCI_B_I2C_initMaster(EUSCI_B1_BASE, &_param);

    //
    // 设置I2C为传输模式
    //
    MAP_EUSCI_B_I2C_setMode(EUSCI_B1_BASE, EUSCI_B_I2C_TRANSMIT_MODE);

    //
    // 启用I2C模块
    //
    EUSCI_B_I2C_enable(EUSCI_B1_BASE);

    //
    // 清除I2C中断标志
    //
    
    MAP_EUSCI_B_I2C_clearInterrupt(EUSCI_B1_BASE, 
                                   EUSCI_B_I2C_NAK_INTERRUPT +
                                   EUSCI_B_I2C_TRANSMIT_INTERRUPT0 + 
                                   EUSCI_B_I2C_RECEIVE_INTERRUPT0);
    
}

//*****************************************************************************
//
//! \brief 设置设备地址
//!
//! \param[in] addr 设备地址
//!
//! \return none
//! \note   none
//
//*****************************************************************************
void drv_UCB1I2CSetSlaveAddress(uint8_t addr)
{
    EUSCI_B_I2C_setSlaveAddress(EUSCI_B1_BASE, addr);
}

//*****************************************************************************
//
//! \brief 获取设备地址
//!
//! \param none
//!
//! \return 设备地址
//!
//! \note   none
//
//*****************************************************************************
uint8_t drv_UCB1I2CGetSlaveAddress(void)
{
    return (HWREG16(EUSCI_B1_BASE + OFS_UCBxI2CSA));
}

//*****************************************************************************
//
//! \brief 设置I2C最大错误重试次数
//!
//! \param[in] retNum  最大重试次数(0-255)
//!
//! \return none
//! \note   none
//
//*****************************************************************************
void drv_UCB1I2CSetRetriesNumber(uint8_t retNum)
{
    g_block.retriesNumber = retNum;
}

//*****************************************************************************
//
//! \brief 获取I2C最大错误重试次数
//!
//! \param none
//!
//! \return 最大错误重试次数
//!
//! \note   none
//
//*****************************************************************************
uint8_t drv_UCB1I2CGetRetriesNumber(void)
{
    return (g_block.retriesNumber);
}

//*****************************************************************************
//
//! \brief I2C读取多字节数据
//!
//! \param[in] regAddr  起始寄存器地址
//! \param[in] dataPtr  保存已读取数据的指针
//! \param[in] size     读取数据多大小
//!
//! \return 如果成功返回  \b UCB1_I2C_SUCCESS
//!         否则返回      \b UCB1_I2C_ERROR_BUSY or \b UCB1_I2C_ERROR_NAK
//! \note   none
//
//*****************************************************************************
int16_t drv_UCB1I2CReadMultiByte(uint8_t regAddr, uint8_t *dataPtr, uint16_t size)
{
    //
    //! 等待总线空闲
    //! 如果累计重试次数等于最大错误重试次数
    //! 返回 \b UCB1_I2C_ERROR_BUSY
    //
    uint8_t _retNum = 0;
    
    while(MAP_EUSCI_B_I2C_isBusBusy(EUSCI_B1_BASE))
    {
        _retNum++;
    
        if (_retNum == g_block.retriesNumber)
        {
            return (UCB1_I2C_ERROR_BUSY);
        }
        
    }

    //
    // 设置I2C为传输模式
    //
    MAP_EUSCI_B_I2C_setMode(EUSCI_B1_BASE, EUSCI_B_I2C_TRANSMIT_MODE);

    //
    // 发送写入数据开始信号
    //
    MAP_EUSCI_B_I2C_masterSendStart(EUSCI_B1_BASE);

    //
    // 等待开始信号
    //
    while(EUSCI_B_I2C_SENDING_START == MAP_EUSCI_B_I2C_masterIsStartSent(EUSCI_B1_BASE));

    //
    // 如果设备未应答
    //
    if (MAP_EUSCI_B_I2C_getInterruptStatus(EUSCI_B1_BASE, EUSCI_B_I2C_NAK_INTERRUPT))
    {
        //
        // 发送停止信号
        //
        MAP_EUSCI_B_I2C_masterSendMultiByteStop(EUSCI_B1_BASE);
    
        //
        // 等待停止信号发送
        //
        while (EUSCI_B_I2C_SENDING_STOP == MAP_EUSCI_B_I2C_masterIsStopSent(EUSCI_B1_BASE));
    
        //
        // 清除中断标志
        //
        
        MAP_EUSCI_B_I2C_clearInterrupt(EUSCI_B1_BASE, 
                                       EUSCI_B_I2C_NAK_INTERRUPT +
                                       EUSCI_B_I2C_TRANSMIT_INTERRUPT0 + 
                                       EUSCI_B_I2C_RECEIVE_INTERRUPT0 + 
                                       EUSCI_B_I2C_BYTE_COUNTER_INTERRUPT);
    
        //
        // 返回错误代码
        //
        return (UCB1_I2C_ERROR_NAK);
    }

    //
    // 发送寄存器地址
    //
    MAP_EUSCI_B_I2C_masterSendMultiByteNext(EUSCI_B1_BASE, regAddr);

    //
    // 清除Tx中断标志
    //
    MAP_EUSCI_B_I2C_clearInterrupt(EUSCI_B1_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0);

    //
    // 发送接收起始信号
    //
    MAP_EUSCI_B_I2C_masterReceiveStart(EUSCI_B1_BASE);

    //
    // 等待开始信号生成
    //
    while(EUSCI_B_I2C_SENDING_START == MAP_EUSCI_B_I2C_masterIsStartSent(EUSCI_B1_BASE));

    for (uint16_t i = 0; i < size; i++)
    {
        //
        // 接收数据
        //
        dataPtr[i] = MAP_EUSCI_B_I2C_masterReceiveSingle(EUSCI_B1_BASE);
    }

    //
    // 发送停止信号
    //
    MAP_EUSCI_B_I2C_masterReceiveMultiByteStop(EUSCI_B1_BASE);

    //
    // 轮询等待停止信号发送完成
    //
    while (EUSCI_B_I2C_SENDING_STOP == MAP_EUSCI_B_I2C_masterIsStopSent(EUSCI_B1_BASE));

    return (UCB1_I2C_SUCCESS);
}

请致电  

void main(void)
{

    drv_InitUCB1I2C(UCB1_I2C_CS_SMCLK, CS_getSMCLK(), UCB1_I2C_RATE_400K);

    drv_UCB1I2CSetSlaveAddress(0x30);

    uint8_t _buff[10];

    while (1)
    {
        drv_UCB1I2CReadMultiByte(0x00, _buff, 10);
        __delay_cycles(50000);
    }
}

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

    您是否意味着第一个沟通良好,第二个和第三个沟通不好?

    如果代码的这一部分工作正常,您能否在调试模式下测试代码:

    对于(uint16_t i = 0;i < size;I++)

    //
    //接收数据
    //
    dataPTR[i]= map_EUSCI_B_I2C_masterReceiveSingle (EUSCI_B1_base);
    }

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

    第一个不好,第二个和第三个是好!

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

    第一不好,第二和第三好。

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

    如果代码的这一部分工作正常,您能否在调试模式下测试代码:

    对于(uint16_t i = 0;i < size;I++)

    //
    //接收数据
    //
    dataPTR[i]= map_EUSCI_B_I2C_masterReceiveSingle (EUSCI_B1_base);
    }

    请在“dataPTR[i]= map_EUSCI_B_I2C_ReceivmasterSingle (EUSCI_B1_base)”添加断点;

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

        //
        // 计算最后一字节数据的索引
        //
        uint16_t _lastIndex = size - 1;
    
        //
        // 接收数据(不包含最后一个字节)
        //
        for (int i = 0; i < _lastIndex; i++)
        {
            //
            // 轮询接收中断标志.
            //
            while (!MAP_EUSCI_B_I2C_getInterruptStatus(EUSCI_B1_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0));
        
            //
            // 接收数据
            //
            dataPtr[i] = MAP_EUSCI_B_I2C_masterReceiveMultiByteNext(EUSCI_B1_BASE);
        }
    
        //
        // 接收最后一个字节
        // 并且发送停止信号
        //
        dataPtr[_lastIndex] = MAP_EUSCI_B_I2C_masterReceiveMultiByteFinish(EUSCI_B1_BASE);
        
        

    谢谢你。 问题已解决。 发送停止信号后,需要再接收一个字节