美文网首页物联网loT从业者物联网相关技术研究
NRF52832学习笔记(19)——TWI(I2C)接口使用

NRF52832学习笔记(19)——TWI(I2C)接口使用

作者: Leung_ManWah | 来源:发表于2020-05-26 14:55 被阅读0次

    一、硬件连接

    功能口 引脚
    SCL 5
    SDA 4

    二、移植文件

    注意:以下出现缺失common.h文件错误,去除即可。uint8改为uint8_t或unsigned char或自己宏定义
    链接:https://pan.baidu.com/s/1ZXjGinAEGDFYyk3JCzYV3Q 提取码:4990
    board_i2c.cboard_i2c.h 两个文件加入工程的Application文件夹下


    2.1 board_i2c.c

    /*********************************************************************
     * INCLUDES
     */
    #include "nrf_drv_twi.h"
    #include "app_util_platform.h"
    
    #include "board_i2c.h"
    #include "common.h"
    
    static void twi_handleEvent(nrf_drv_twi_evt_t const *pEvent, void *pContext);
    static void mergeRegisterAndData(uint8 *pTxBuf, uint8 regAddr, uint8 *pData, uint16 dataLen);
    
    /*********************************************************************
     * LOCAL VARIABLES
     */
    static const nrf_drv_twi_t s_twiHandle = NRF_DRV_TWI_INSTANCE(TWI_INSTANCE_ID);
    
    volatile static bool s_twiTxDone = false;                   // 发送完成标志
    volatile static bool s_twiRxDone = false;                   // 接收完成标志   
    
    static uint8 s_twiWriteDataBuffer[TWI_MAX_NUM_TX_BYTES];
    
    /*********************************************************************
     * PUBLIC FUNCTIONS
     */
    /**
     @brief TWI(I2C)驱动初始化
     @param 无
     @return 无
    */
    void I2C_Init(void)
    {
        uint32 errCode;
        
        // 初始化TWI配置结构体
        const nrf_drv_twi_config_t twiConfig =
        {
            .scl                = BOARD_TWI_SCL_IO,             // 配置TWI SCL引脚
            .sda                = BOARD_TWI_SDA_IO,             // 配置TWI SDA引脚
            .frequency          = NRF_TWI_FREQ_400K,            // 配置TWI时钟频率
            .interrupt_priority = APP_IRQ_PRIORITY_HIGH         // TWI中断优先级设置
        };
        
        // 初始化TWI
        errCode = nrf_drv_twi_init(&s_twiHandle, &twiConfig, twi_handleEvent, NULL);
        APP_ERROR_CHECK(errCode);
        
        // 使能TWI
        nrf_drv_twi_enable(&s_twiHandle);
    }
    
    /**
     @brief TWI(I2C)写数据函数
     @param slaveAddr -[in] 从设备地址
     @param regAddr -[in] 寄存器地址
     @param pData -[in] 写入数据
     @param dataLen -[in] 写入数据长度
     @return 错误码
    */
    uint16 I2C_WriteData(uint8 slaveAddr, uint8 regAddr, uint8 *pData, uint16 dataLen)
    {
        // This burst write function is not optimal and needs improvement.
        // The new SDK 11 TWI driver is not able to do two transmits without repeating the ADDRESS + Write bit byte
        uint32 errCode;
        uint32 timeout = TWI_TIMEOUT;
        // Merging MPU register address and p_data into one buffer.
        mergeRegisterAndData(s_twiWriteDataBuffer, regAddr, pData, dataLen);
        // Setting up transfer
        nrf_drv_twi_xfer_desc_t xferDesc;
        xferDesc.address = slaveAddr;
        xferDesc.type = NRF_DRV_TWI_XFER_TX;
        xferDesc.primary_length = dataLen + 1;
        xferDesc.p_primary_buf = s_twiWriteDataBuffer;
    
        // Transferring
        errCode = nrf_drv_twi_xfer(&s_twiHandle, &xferDesc, 0);
    
        while((!s_twiTxDone) && --timeout);
        if(!timeout)
        {
            return NRF_ERROR_TIMEOUT;
        }
        s_twiTxDone = false;
    
        return errCode; 
    }
    
    /**
     @brief TWI(I2C)读数据函数
     @param slaveAddr -[in] 从设备地址
     @param regAddr -[in] 寄存器地址
     @param pData -[in] 读出数据
     @param dataLen -[in] 读出数据长度
     @return 错误码
    */
    uint16 I2C_ReadData(uint8 slaveAddr, uint8 regAddr, uint8 *pData, uint16 dataLen)
    {
        uint32 errCode;
        uint32 timeout = TWI_TIMEOUT;
    
        errCode = nrf_drv_twi_tx(&s_twiHandle, slaveAddr, &regAddr, 1, false);
        if(errCode != NRF_SUCCESS)
        {
            return errCode;
        }
    
        while((!s_twiTxDone) && --timeout); 
        if(!timeout)
        {
            return NRF_ERROR_TIMEOUT;
        }
        s_twiTxDone = false;
    
        errCode = nrf_drv_twi_rx(&s_twiHandle, slaveAddr, pData, dataLen);
        if(errCode != NRF_SUCCESS)
        {
            return errCode;
        }
    
        timeout = TWI_TIMEOUT;
        while((!s_twiRxDone) && --timeout);
        if(!timeout)
        {
            return NRF_ERROR_TIMEOUT;
        }
        s_twiRxDone = false;
        
        return errCode;
    }
    
    /**
     @brief 开启TWI(I2C)
     @param 无
     @return 无
    */
    void I2C_Enable(void)
    {
        nrf_drv_twi_enable(&s_twiHandle);
    }
    
    /**
     @brief 禁用TWI(I2C)
     @param 无
     @return 无
    */
    void I2C_Disable(void)
    {
        nrf_drv_twi_disable(&s_twiHandle);
    }
    
    
    /*********************************************************************
     * LOCAL FUNCTIONS
     */
    /**
     @brief TWI事件处理函数
     @param pEvent -[in] TWI事件
     @return 无
    */
    static void twi_handleEvent(nrf_drv_twi_evt_t const *pEvent, void *pContext)
    {
        // 判断TWI事件类型
        switch(pEvent->type)
        {
            // 传输完成事件
            case NRF_DRV_TWI_EVT_DONE:
                switch(pEvent->xfer_desc.type)
                {
                    case NRF_DRV_TWI_XFER_TX:
                        s_twiTxDone = true;
                        break;
                    case NRF_DRV_TWI_XFER_TXTX:
                        s_twiTxDone = true;
                        break;
                    case NRF_DRV_TWI_XFER_RX:
                        s_twiRxDone = true;
                        break;
                    case NRF_DRV_TWI_XFER_TXRX:
                        s_twiRxDone = true;
                        break;
                    default:
                        break;
                }
                break;
            
            case NRF_DRV_TWI_EVT_ADDRESS_NACK:
                break;
            
            case NRF_DRV_TWI_EVT_DATA_NACK:
                break;
            
            default:
                break;
        }   
    }
    
    /**
     @brief 合并寄存器地址和待写入数据
     @param pTxBuf -[in] 写入缓冲区
     @param regAddr -[in] 寄存器地址
     @param pData -[in] 写入数据
     @param dataLen -[in] 写入数据长度
     @return 无
    */
    static void mergeRegisterAndData(uint8 *pTxBuf, uint8 regAddr, uint8 *pData, uint16 dataLen)
    {
        pTxBuf[0] = regAddr;
        memcpy((pTxBuf + 1), pData, dataLen);
    }
    
    /****************************************************END OF FILE****************************************************/
    

    2.2 board_i2c.h

    #ifndef _BOARD_I2C_H_
    #define _BOARD_I2C_H_
    
    /*********************************************************************
     * INCLUDES
     */
    #include "common.h"
    
    /*********************************************************************
     * DEFINITIONS
     */
    // TWI驱动程序实例ID,ID和外设编号对应,0:TWI0 1:TWI1
    #define TWI_INSTANCE_ID                 0
    
    #define BOARD_TWI_SCL_IO                5       // 时钟线引脚  
    #define BOARD_TWI_SDA_IO                4       // 数据线引脚
    
    #define TWI_MAX_NUM_TX_BYTES            14      // TWI TX buffer size
    #define TWI_TIMEOUT                     10000 
    
    /*********************************************************************
     * API FUNCTIONS
     */
    void I2C_Init(void);
    uint16 I2C_WriteData(uint8 slaveAddr, uint8 regAddr, uint8 *pData, uint16 dataLen);
    uint16 I2C_ReadData(uint8 slaveAddr, uint8 regAddr, uint8 *pData, uint16 dataLen);
    void I2C_Enable(void);
    void I2C_Disable(void);
    
    #endif /* _BOARD_I2C_H_ */
    

    三、API调用

    需包含头文件 board_i2c.h

    I2C_Init

    功能 初始化I2C驱动
    函数定义 void I2C_Init(void)
    参数
    返回

    I2C_WriteData

    功能 I2C写入数据
    函数定义 I2C_WriteData(uint8 slaveAddr, uint8 regAddr, uint8 *pData, uint16 dataLen)
    参数 slaveAddr:从地址
    regAddr:寄存器地址
    pData:写入数据
    dataLen:写入数据长度
    返回

    I2C_ReadData

    功能 I2C读出数据
    函数定义 I2C_ReadData(uint8 slaveAddr, uint8 regAddr, uint8 *pData, uint16 dataLen)
    参数 slaveAddr:从地址
    regAddr:寄存器地址
    pData:读出数据
    dataLen:读出数据长度
    返回

    I2C_Enable

    功能 开启I2C,实现低功耗配合I2C_Disable使用
    函数定义 void I2C_Enable(void)
    参数
    返回

    I2C_Disable

    功能 禁用I2C,实现低功耗配合I2C_Enable使用
    函数定义 void I2C_Disable(void)
    参数
    返回

    四、SDK配置

    点击 sdk_config.h 文件


    选择 Configuration Wizard

    nRF_Drivers 中勾选TWI及TWIM相关选项


    nRF_Drivers 中添加文件

    五、使用例子

    1)添加头文件

    #include "board_i2c.h"
    

    2)添加初始化代码(SDK15.3 中 ble_peripheral 的 ble_app_template 工程 main() 函数中)
    加入 i2c_Init() 并在初始化后调用 I2C_Disable 进入低功耗,在需要用I2C时调用 I2C_Enable 开启I2C 注意:I2C开启到读取数据至少延迟20毫秒

    int main(void)
    {
        bool erase_bonds;
    
        /*-------------------------- 外设驱动初始化 ---------------------------*/
        // Initialize.
        log_init();                                                                 // 日志驱动初始化                                                                  
        timers_init();                                                              // 定时器驱动初始化(在此加入自定义定时器)
        I2C_Init();
        
        /*-------------------------- 蓝牙协议栈初始化 ---------------------------*/
        power_management_init();
        ble_stack_init();                                                           // 协议栈初始化
        gap_params_init();
        gatt_init();
        advertising_init();                                                         // 广播初始化
        services_init();                                                            // 服务初始化
        conn_params_init();                                                         // 连接参数初始化
        peer_manager_init();
        
        /*-------------------------- 开启应用 ---------------------------*/
        // Start execution.
        NRF_LOG_INFO("Template example started."); 
        advertising_start(erase_bonds);                                             // 开启广播 
        application_timers_start();                                                 // 定时器应用开启(在此开启自定义定时器)  
        I2C_Disable();                                                              // 禁用I2C,进入低功耗模式
        
        // Enter main loop.
        for(;;)
        {
            idle_state_handle();
        }
    }
    

    3)写入数据

    #define BMA4_I2C_ADDR_PRIMARY   UINT8_C(0x18)
    #define BMA4_FIFO_CONFIG_0_ADDR     UINT8_C(0X48)
    
    uint8 value = 0x02;
    I2C_WriteData(BMA4_I2C_ADDR_PRIMARY, BMA4_FIFO_CONFIG_0_ADDR, &value, 1);
    

    4)读出数据

    I2C_Enable();
    DelayMs(20);                                                    // I2C开启到读取数据至少延迟20毫秒
    I2C_ReadData(BMA4_I2C_ADDR_PRIMARY, BMA4_INT_STAT_0_ADDR, &value, 1);
    I2C_Disable();
    

    • 由 Leung 写于 2020 年 5 月 26 日

    • 参考:青风电子社区
        Nordic系列芯片讲解五( Nordic sdk中nrf_drv_twi的使用)

    相关文章

      网友评论

        本文标题:NRF52832学习笔记(19)——TWI(I2C)接口使用

        本文链接:https://www.haomeiwen.com/subject/icnmahtx.html