首先感谢电子产品世界和恩智浦公司的信任能够参加本次对FRDM-MCXA156开发板的评测。
FRDM-MCXA156基于Arm Cortex-M33 拥有一个I3C接口。开发板板载P3T1755温度传感器可以通过I3C(12.5MHZ)和I2C(3.4MHZ)数据接口读取P3T1755寄存器。I3C的设备并不常见,之前少有涉猎,所以先从I3C入手开始评测。
恩智浦提供了I3C相关例程,位于:SDK_2_16_100_FRDM-MCXA156\boards\frdmmcxa156\driver_examples\i3c\master_read_sensor_p3t1755
本文试图对该例程进行解读。
一、硬件连接
通过I3C0(P0_16、P0_17)连接P3T1755。
二、P3T1755
The P3T1755 is a temperature-to-digital converter from -40 °C to +125 °C range. It uses an on-chip band gap
temperature sensor and A-to-D conversion technique with an overtemperature detection. The device contains a
number of configuration and data registers to store the device settings, such as device operation mode, and a
temperature register (Temp) to store the digital temp reading that can be communicated by a controller via the
2-wire serial I3C (up to 12.5 MHz) and I2C (up to 3.4 MHz) interface.
SDA、SCL是I3C接口,在I3C模式下ALERT不起作用。A0、A1、A2用于用户自定义设备地址,开发板上这3个引脚接地。
P3T1755做为从机使用,数据手册上给出了地址的确定方法:
可以得出从机地址为0x48(SENSOR_SLAVE_ADDR)
三、源码解读
1、BOARD_InitPins();
初始化I3C0
const port_pin_config_t port0_16_pin83_config = {/* Internal pull-up/down resistor is disabled */ kPORT_PullDisable, /* Low internal pull resistor value is selected. */ kPORT_LowPullResistor, /* Fast slew rate is configured */ kPORT_FastSlewRate, /* Passive input filter is disabled */ kPORT_PassiveFilterDisable, /* Open drain output is disabled */ kPORT_OpenDrainDisable, /* Low drive strength is configured */ kPORT_LowDriveStrength, /* Normal drive strength is configured */ kPORT_NormalDriveStrength, /* Pin is configured as I3C0_SDA */ kPORT_MuxAlt10, /* Digital input enabled */ kPORT_InputBufferEnable, /* Digital input is not inverted */ kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ kPORT_UnlockRegister}; /* PORT0_16 (pin 83) is configured as I3C0_SDA */ PORT_SetPinConfig(PORT0, 16U, &port0_16_pin83_config); const port_pin_config_t port0_17_pin84_config = {/* Internal pull-up/down resistor is disabled */ kPORT_PullDisable, /* Low internal pull resistor value is selected. */ kPORT_LowPullResistor, /* Fast slew rate is configured */ kPORT_FastSlewRate, /* Passive input filter is disabled */ kPORT_PassiveFilterDisable, /* Open drain output is disabled */ kPORT_OpenDrainDisable, /* Low drive strength is configured */ kPORT_LowDriveStrength, /* Normal drive strength is configured */ kPORT_NormalDriveStrength, /* Pin is configured as I3C0_SCL */ kPORT_MuxAlt10, /* Digital input enabled */ kPORT_InputBufferEnable, /* Digital input is not inverted */ kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ kPORT_UnlockRegister}; /* PORT0_17 (pin 84) is configured as I3C0_SCL */ PORT_SetPinConfig(PORT0, 17U, &port0_17_pin84_config);
2、I3C初始化
I3C_MasterGetDefaultConfig(&masterConfig); masterConfig.baudRate_Hz.i2cBaud = EXAMPLE_I2C_BAUDRATE; masterConfig.baudRate_Hz.i3cPushPullBaud = EXAMPLE_I3C_PP_BAUDRATE; masterConfig.baudRate_Hz.i3cOpenDrainBaud = EXAMPLE_I3C_OD_BAUDRATE; masterConfig.enableOpenDrainStop = false; masterConfig.disableTimeout = true; I3C_MasterInit(EXAMPLE_MASTER, &masterConfig, I3C_MASTER_CLOCK_FREQUENCY); /* Create I3C handle. */ I3C_MasterTransferCreateHandle(EXAMPLE_MASTER, &g_i3c_m_handle, &masterCallback, NULL);
3、设置P3T1755动态地址p3t1755_set_dynamic_address()
#define SENSOR_SLAVE_ADDR 0x48U #define SENSOR_ADDR 0x08U #define CCC_RSTDAA 0x06U #define CCC_SETDASA 0x87 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(EXAMPLE_MASTER, &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(EXAMPLE_MASTER, &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(EXAMPLE_MASTER, &masterXfer); }
这一步基于数据手册的这个图解:
在 p3t1755_set_dynamic_address(void)中,首先对地址做了一个复位操作,然后将I3C从机指定地址为SENSOR_ADDR(0x08U),考虑到I3C是7h(7位),所以做了一个SENSOR_ADDR << 1左移1位的操作。
CCC是I3C Common Command Codes的缩写。P3T1755 supports CCCs that allow the controller to control multiple targets through a broadcast command at once or individual targets through direct commands这些指令如下:
本例中用到了0x06、0x87指令。
RESET 地址,需要发送0X7E,0x06
设置动态地址:
4、p3t1755初始化
p3t1755Config.writeTransfer = I3C_WriteSensor; p3t1755Config.readTransfer = I3C_ReadSensor; p3t1755Config.sensorAddress = SENSOR_ADDR; P3T1755_Init(&p3t1755Handle, &p3t1755Config);
指定了I3C读写p3t1755寄存器的处理函数和I3C从机地址。
5、I3C_ReadSensor()
P3T1755_ReadReg函数会调用I3C_ReadSensor。
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(EXAMPLE_MASTER, &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; }
I3C_MasterTransferNonBlocking向从机发送I3C数据实现读取P3T1755寄存器。
regAddress取值:
6、温度读取及计算
/* Registers. */ #define P3T1755_TEMPERATURE_REG (0x00U) #define P3T1755_CONFIG_REG (0x01U) status_t P3T1755_ReadTemperature(p3t1755_handle_t *handle, double *temperature) { status_t result = kStatus_Success; uint8_t data[2]; uint16_t temp; result = P3T1755_ReadReg(handle, P3T1755_TEMPERATURE_REG, &data[0], 2); if (result == kStatus_Success) { temp = (((uint16_t)data[0] << 8U) | (uint16_t)data[1]) >> 4U; *temperature = (double)temp * 0.0625; } return result; }
四、运行效果