背景
I2C总线接口,能够使多路设备挂在一个总线上,通过时分复用的方式实现硬件接口占用的降低。但其也存在一些缺点,一是因为需要协商机制,以确保从设备的正确响应,导致带宽浪费,而I2C总线标准中,即使最高速率3.4Mbit/s,也会在重度负荷时出现带宽不足的情况。二是I2C接口,若从设备有消息需更新至主设备端,单纯的I2C接口无法解决通知问题,需额外增加状态通知链路解决该问题。为解决以上问题,I3C标准应运而生。
I3C标准介绍
I3C,全称为Improved Inter-Integrated Circuit,是一种由MIPI联盟发布的通信总线接口标准。作为I2C(Inter-Integrated Circuit)的升级版,I3C不仅继承了I2C的2线传输特性,还在性能、功耗和扩展性方面进行了显著的改进。以下是对I3C接口特点的详细介绍,特别是它相对于I2C的改善之处:
一、传输速率和性能的大幅提升
I3C支持更高的数据传输速率。在标准CMOS I/O上,它支持最低10Mbps的数据速率,相比I2C有了显著的提升。此外,I3C还具有高性能的高数据速率(HDR)模式选项,理论最大速率可达到39.5Mbps(实际有效传输速率约为33.3Mbps),这远超过了I2C的通信速度。
二、功耗效率的改进
I3C在功耗方面也有所优化。它最低支持1.2V电平(同时支持1.8V/3.3V,不支持5V),在相同的电平标准下,I3C的整体功耗远小于I2C,这使得I3C成为更为节能的通信接口。
三、动态寻址和多主设备支持
与I2C的静态寻址不同,I3C采用了动态寻址方式。这意味着从设备的地址可以由当前的主控制器在初始化后动态分配,提供了更为灵活的设备配置和管理方式。
I3C支持多主机和多从机配置,增强了总线系统的可扩展性和灵活性。这种多主设备的支持使得多个控制器能够共享同一条总线,从而简化了系统设计和布线。
四、高级功能和中断机制
I3C提供了高级电源管理功能,如睡眠模式,以进一步降低功耗。
它还支持带内中断功能,这意味着从设备可以通过I3C总线产生中断并通知主控制器,从而节省了一根额外的中断线,简化了系统布线并降低了成本。
五、广泛的兼容性和应用前景
I3C向下兼容I2C,这使得现有的I2C设备可以无缝地集成到I3C系统中,保护了用户的投资并简化了升级过程。
由于其高性能、低功耗和灵活的配置选项,I3C在移动无线传感器系统、可穿戴设备以及其他需要高效、低功耗通信的应用领域具有广阔的应用前景。
P3T1755简介
P3T1755是一款高性能的数字温度传感器,它基于I3C/I2C总线通信,提供了极高的温度测量精度和广泛的工作温度范围。以下是关于P3T1755的详细简介:
一、产品概述
P3T1755是一款精确的温度数字转换器,其测量精度达到了±0.5°C,温度测量范围覆盖从-40°C到+125°C。该传感器集成了片上带隙温度传感器,并采用先进的模数转换技术,确保温度数据的准确性和可靠性。
二、主要特性
高精度测量:P3T1755的测量精度高达±0.5°C,能够满足各种高精度温度测量需求。
宽温度范围:支持从-40°C到+125°C的宽温度范围,适用于各种环境条件下的温度监测。
多种工作模式:P3T1755可配置为连续转换模式、单一转换模式或关闭模式,以满足不同应用场景的需求。
超温检测功能:具有超温检测功能,能够在温度超过设定阈值时产生警报,确保系统安全。
通信接口:支持2线串行I3C(高达12.5MHz)和I2C(高达3.4MHz)作为通信接口,方便与其他设备进行数据交换。
三、技术规格
温度分辨率:0.0625°C,确保温度数据的精确性。
温度寄存器:始终存储12位二进制补码数据,方便数据处理和存储。
I3C特性:支持带内中断功能(IBI),使用同一总线报告警报中断。
四、应用领域
P3T1755广泛应用于各种需要高精度温度测量的领域,如工业自动化、环境监测、医疗设备、汽车电子等。其高性能和可靠性使其成为这些领域中不可或缺的传感器之一。
FRDM-MCXN947上硬件接口
原理图P3T1755接线
板卡上P3T1755位置
MCUXpresso Config Tool配置
1. 下载MCX-N947板卡SDK,打开MCUXpresso Config Tools软件,导入SDK,创建基础工程(带串口打印版本)。
2. 增加I3C引脚定义
3. 增加I3C模块功能配置
4. 增加时钟树配置
5. 重新生成工程
代码编写
编写p3t1755驱动文件
p3t1755.h
#ifndef __P3T1755_H_ #define __P3T1755_H_ #include "fsl_common.h" /* Registers. */ #define P3T1755_TEMPERATURE_REG (0x00U) #define P3T1755_CONFIG_REG (0x01U) /*! @brief Define sensor access function. */ typedef status_t (*sensor_write_transfer_func_t)(uint8_t deviceAddress, uint32_t regAddress, uint8_t *regData, size_t dataSize); typedef status_t (*sensor_read_transfer_func_t)(uint8_t deviceAddress, uint32_t regAddress, uint8_t *regData, size_t dataSize); typedef struct _p3t1755_handle { sensor_write_transfer_func_t writeTransfer; sensor_read_transfer_func_t readTransfer; uint8_t sensorAddress; } p3t1755_handle_t; typedef struct _p3t1755_config { sensor_write_transfer_func_t writeTransfer; sensor_read_transfer_func_t readTransfer; uint8_t sensorAddress; } p3t1755_config_t; status_t P3T1755_Init(p3t1755_handle_t *handle, p3t1755_config_t *config); status_t P3T1755_WriteReg(p3t1755_handle_t *handle, uint32_t regAddress, uint8_t *regData, size_t dataSize); status_t P3T1755_ReadReg(p3t1755_handle_t *handle, uint32_t regAddress, uint8_t *regData, size_t dataSize); status_t P3T1755_ReadTemperature(p3t1755_handle_t *handle, double *temperature); #endif /* __P3T1755_H_ */
p3t1755.c
#include "p3t1755.h" status_t P3T1755_WriteReg(p3t1755_handle_t *handle, uint32_t regAddress, uint8_t *regData, size_t dataSize) { status_t result; result = handle->writeTransfer(handle->sensorAddress, regAddress, regData, dataSize); return (result == kStatus_Success) ? result : kStatus_Fail; } status_t P3T1755_ReadReg(p3t1755_handle_t *handle, uint32_t regAddress, uint8_t *regData, size_t dataSize) { status_t result; result = handle->readTransfer(handle->sensorAddress, regAddress, regData, dataSize); return (result == kStatus_Success) ? result : kStatus_Fail; } status_t P3T1755_Init(p3t1755_handle_t *handle, p3t1755_config_t *config) { assert(handle != NULL); assert(config != NULL); assert(config->writeTransfer != NULL); assert(config->readTransfer != NULL); handle->writeTransfer = config->writeTransfer; handle->readTransfer = config->readTransfer; handle->sensorAddress = config->sensorAddress; return kStatus_Success; } status_t P3T1755_ReadTemperature(p3t1755_handle_t *handle, double *temperature) { status_t result = kStatus_Success; uint8_t data[2]; result = P3T1755_ReadReg(handle, P3T1755_TEMPERATURE_REG, &data[0], 2); if (result == kStatus_Success) { *temperature = (double)((((uint16_t)data[0] << 8U) | (uint16_t)data[1]) >> 4U); *temperature = *temperature * 0.0625; } return result; }
编写程序应用层程序
main.c
#include <string.h> /* SDK Included Files */ #include "board.h" #include "clock_config.h" #include "fsl_debug_console.h" #include "fsl_i3c.h" #include "p3t1755.h" #include "peripherals.h" #include "pin_mux.h" /******************************************************************************* * Definitions ******************************************************************************/ #define SENSOR_SLAVE_ADDR 0x48U #define I3C_TIME_OUT_INDEX 100000000U #define SENSOR_ADDR 0x08U #define CCC_RSTDAA 0x06U #define CCC_SETDASA 0x87 /******************************************************************************* * Prototypes ******************************************************************************/ static void i3c_master_callback(I3C_Type *base, i3c_master_handle_t *handle, status_t status, void *userData); /******************************************************************************* * Variables ******************************************************************************/ volatile status_t g_completionStatus; volatile bool g_masterCompletionFlag; i3c_master_handle_t g_i3c_m_handle; p3t1755_handle_t p3t1755Handle; const i3c_master_transfer_callback_t masterCallback = { .slave2Master = NULL, .ibiCallback = NULL, .transferComplete = i3c_master_callback}; /******************************************************************************* * Code ******************************************************************************/ static void i3c_master_callback(I3C_Type *base, i3c_master_handle_t *handle, status_t status, void *userData) { if (status == kStatus_Success) { g_masterCompletionFlag = true; } g_completionStatus = status; } status_t I3C_WriteSensor(uint8_t deviceAddress, uint32_t regAddress, uint8_t *regData, size_t dataSize) { status_t result = kStatus_Success; i3c_master_transfer_t masterXfer = {0}; uint32_t timeout = 0U; masterXfer.slaveAddress = deviceAddress; masterXfer.direction = kI3C_Write; masterXfer.busType = kI3C_TypeI3CSdr; masterXfer.subaddress = regAddress; masterXfer.subaddressSize = 1; masterXfer.data = regData; masterXfer.dataSize = dataSize; masterXfer.flags = kI3C_TransferDefaultFlag; g_masterCompletionFlag = false; g_completionStatus = kStatus_Success; result = I3C_MasterTransferNonBlocking(I3C1_PERIPHERAL, &g_i3c_m_handle, &masterXfer); if (kStatus_Success != result) { return result; } while (!g_masterCompletionFlag) { timeout++; if ((g_completionStatus != kStatus_Success) || (timeout > I3C_TIME_OUT_INDEX)) { break; } } if (timeout == I3C_TIME_OUT_INDEX) { result = kStatus_Timeout; } result = g_completionStatus; return result; } status_t I3C_ReadSensor(uint8_t deviceAddress, uint32_t regAddress, uint8_t *regData, size_t dataSize) { status_t result = kStatus_Success; i3c_master_transfer_t masterXfer = {0}; uint32_t timeout = 0U; masterXfer.slaveAddress = deviceAddress; masterXfer.direction = kI3C_Read; masterXfer.busType = kI3C_TypeI3CSdr; masterXfer.subaddress = regAddress; masterXfer.subaddressSize = 1; masterXfer.data = regData; masterXfer.dataSize = dataSize; masterXfer.flags = kI3C_TransferDefaultFlag; g_masterCompletionFlag = false; g_completionStatus = kStatus_Success; result = I3C_MasterTransferNonBlocking(I3C1_PERIPHERAL, &g_i3c_m_handle, &masterXfer); if (kStatus_Success != result) { return result; } while (!g_masterCompletionFlag) { timeout++; if ((g_completionStatus != kStatus_Success) || (timeout > I3C_TIME_OUT_INDEX)) { break; } } if (timeout == I3C_TIME_OUT_INDEX) { result = kStatus_Timeout; } result = g_completionStatus; return result; } status_t p3t1755_set_dynamic_address(void) { status_t result = kStatus_Success; i3c_master_transfer_t masterXfer = {0}; uint8_t g_master_txBuff[1]; /* Reset dynamic address. */ g_master_txBuff[0] = CCC_RSTDAA; masterXfer.slaveAddress = 0x7E; masterXfer.data = g_master_txBuff; masterXfer.dataSize = 1; masterXfer.direction = kI3C_Write; masterXfer.busType = kI3C_TypeI3CSdr; masterXfer.flags = kI3C_TransferDefaultFlag; result = I3C_MasterTransferBlocking(I3C1_PERIPHERAL, &masterXfer); if (result != kStatus_Success) { return result; } /* Assign dynmic address. */ memset(&masterXfer, 0, sizeof(masterXfer)); g_master_txBuff[0] = CCC_SETDASA; masterXfer.slaveAddress = 0x7E; masterXfer.data = g_master_txBuff; masterXfer.dataSize = 1; masterXfer.direction = kI3C_Write; masterXfer.busType = kI3C_TypeI3CSdr; masterXfer.flags = kI3C_TransferNoStopFlag; result = I3C_MasterTransferBlocking(I3C1_PERIPHERAL, &masterXfer); if (result != kStatus_Success) { return result; } memset(&masterXfer, 0, sizeof(masterXfer)); g_master_txBuff[0] = SENSOR_ADDR << 1; masterXfer.slaveAddress = SENSOR_SLAVE_ADDR; masterXfer.data = g_master_txBuff; masterXfer.dataSize = 1; masterXfer.direction = kI3C_Write; masterXfer.busType = kI3C_TypeI3CSdr; masterXfer.flags = kI3C_TransferDefaultFlag; return I3C_MasterTransferBlocking(I3C1_PERIPHERAL, &masterXfer); } int main(void) { status_t result = kStatus_Success; i3c_master_config_t masterConfig; p3t1755_config_t p3t1755Config; double temperature; CLOCK_SetClkDiv(kCLOCK_DivI3c1FClk, 6U); CLOCK_AttachClk(kPLL0_to_I3C1FCLK); BOARD_InitPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); BOARD_InitBootPeripherals(); PRINTF("I3C master read sensor data.\r\n"); /* Create I3C handle. */ I3C_MasterTransferCreateHandle(I3C1_PERIPHERAL, &g_i3c_m_handle, &masterCallback, NULL); p3t1755_set_dynamic_address(); p3t1755Config.writeTransfer = I3C_WriteSensor; p3t1755Config.readTransfer = I3C_ReadSensor; p3t1755Config.sensorAddress = SENSOR_ADDR; P3T1755_Init(&p3t1755Handle, &p3t1755Config); while (1) { result = P3T1755_ReadTemperature(&p3t1755Handle, &temperature); if (result != kStatus_Success) { PRINTF("P3T1755 read temperature failed.\r\n"); } else { PRINTF("Temperature:%f \r\n", temperature); } SDK_DelayAtLeastUs(1000000, CLOCK_GetCoreSysClkFreq()); } }
结果验证
程序编写完毕后,编译代码并下载至板卡端,查看运行结果:
I3C master read sensor data. Temperature:28.750000 Temperature:28.812500 Temperature:28.812500 Temperature:28.812500 Temperature:28.750000 Temperature:28.750000 Temperature:29.000000 Temperature:29.250000 Temperature:29.687500 Temperature:30.000000 Temperature:30.250000 Temperature:30.500000 Temperature:30.750000 Temperature:30.937500 Temperature:31.125000 Temperature:31.312500 Temperature:31.437500 Temperature:31.562500 Temperature:31.687500 Temperature:31.875000
从结果上看,MCX-N947已经可以读取信息,且手指放在板卡背面温度传感器对应位置时,可监测到传感器读取到的温度值在逐步上升,因此可以判定温度值读取正确。