Nvidia Thor 平台Ofilm 5MP(OX05B1S)相机温度读取方案

39 阅读6分钟

1. 说明:模组内部包括ISP(OAX4000)和Sensor(OX05B1S)两部分,本方案均已提供获取方法。

2. OAX4000 温度读取方案

 2.1 寄存器方案

        直接读取0x4030和0x4031寄存器,同0x912C和0x912D寄存器。

0x4030[7:0]: OAX4000 temperature integer part, same as 0x912C[7:0]
0X4031[7:0]: OAX4000 temperature decimal part, same as 0x912D[7:0] 

2.2 hostcmd方案

        基于v4l2-subdev 增加 ioctl 操作command

diff --git a/nvidia-oot/drivers/media/i2c/nv_ox05b1s.c b/nvidia-oot/drivers/media/i2c/nv_ox05b1s.c
index 0a245383a..60b51ae19 100644
--- a/nvidia-oot/drivers/media/i2c/nv_ox05b1s.c
+++ b/nvidia-oot/drivers/media/i2c/nv_ox05b1s.c
@@ -206,6 +206,7 @@ static struct mutex serdes_lock__;
 #define VIDIOC_PRIVATE_IOCTL_ISP_UPGRADE_FIRMWARE      _IOW('V', BASE_VIDIOC_PRIVATE + 2, uint32_t)
 #define VIDIOC_PRIVATE_IOCTL_ISP_GET_FIRMWARE_VERSION  _IOR('V', BASE_VIDIOC_PRIVATE + 3, uint32_t)
 #define VIDIOC_PRIVATE_IOCTL_ISP_RESET _IO('V', BASE_VIDIOC_PRIVATE + 4)
+#define VIDIOC_PRIVATE_IOCTL_ISP_READ_REG      _IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct reg_8)
 
 bool SendCmd_Sensor_stream_on(struct ox05b1s *priv);
 bool SendCmd_Sensor_stream_off(struct ox05b1s *priv);
@@ -3323,6 +3324,16 @@ long ox05b1s_v4l2subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *ar
                dev_info(tc_dev->dev, "Isp reset\n");
                ret = OAX4000_reset(priv);
                break;
+       case VIDIOC_PRIVATE_IOCTL_ISP_READ_REG:
+       {
+               struct reg_8 *reg_io = (struct reg_8 *)arg;
+               // dev_info(tc_dev->dev, "Isp read reg: 0x%x\n", reg_io->addr);
+               ret = ox05b1s_read_reg(s_data, reg_io->addr, &reg_io->val);
+               // if (ret == 0) {
+                       // dev_info(tc_dev->dev, "Read reg 0x%x: 0x%x\n", reg_io->addr, reg_io->val);
+               // }
+               break;
+       }
        // ignore cmd:3224131130
        case VIDIOC_CROPCAP:
                break;

3. OX05B1S 温度读取方案

 3.1 寄存器方案

0x40F0[7:0]: sensor temperature integer part
0x40F1[7:0]: sensor temperature decimal part

 3.2 hostcmd 方案

        缺点:不宜高频读取,容易与FW不停更新sccb,造成系统繁忙,报time out。

        基于v4l2-subdev 增加 ioctl 操作command和oax4000 hostcmd。

diff --git a/nvidia-oot/drivers/media/i2c/nv_ox05b1s.c b/nvidia-oot/drivers/media/i2c/nv_ox05b1s.c
index 60b51ae19..c5e4be145 100644
--- a/nvidia-oot/drivers/media/i2c/nv_ox05b1s.c
+++ b/nvidia-oot/drivers/media/i2c/nv_ox05b1s.c
@@ -207,9 +207,11 @@ static struct mutex serdes_lock__;
 #define VIDIOC_PRIVATE_IOCTL_ISP_GET_FIRMWARE_VERSION  _IOR('V', BASE_VIDIOC_PRIVATE + 3, uint32_t)
 #define VIDIOC_PRIVATE_IOCTL_ISP_RESET _IO('V', BASE_VIDIOC_PRIVATE + 4)
 #define VIDIOC_PRIVATE_IOCTL_ISP_READ_REG      _IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct reg_8)
+#define VIDIOC_PRIVATE_IOCTL_ISP_HOSTCMD_READ_REG      _IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct reg_8)
 
 bool SendCmd_Sensor_stream_on(struct ox05b1s *priv);
 bool SendCmd_Sensor_stream_off(struct ox05b1s *priv);
+bool SendCmd_sensor_temperature_get(struct ox05b1s *priv);
 bool SendCmd_ISP_stream_on(struct ox05b1s *priv);
 bool SendCmd_ISP_stream_off(struct ox05b1s *priv);
 bool SendCmd_PageWrite(struct ox05b1s *priv, unsigned char* buf, uint16_t pgIdx);
@@ -224,9 +226,12 @@ int writeBurstRegister(struct ox05b1s *priv, uint32_t addr, unsigned char* pData
 int BurstWriteRegister(struct ox05b1s *priv, unsigned int addr, unsigned char* value, bool b16bitAddress, unsigned int num);
 int Clear_CRC(struct ox05b1s *priv);
 
+#define CMD_OUTPUT_VALUE_0 0x00                                (0x3C07)
+
 #define BURST_SIZE (32)
 // sensor related host command
 #define CMD_ACCESS_SCCB_SLAVE_DEVICE           (0x00)
+#define CMD_TEMP_GET                                           (0x02)
 // non-sensor related host command
 #define CMD_STREAMING_CTRL                                     (0x19)
 // extra system host command
@@ -2071,11 +2076,44 @@ bool SendCmd_Sensor_stream_off(struct ox05b1s *priv)
        para[4] = 0x00;                 //para num hi
        para[5] = 0x06;                 //para num lo
        para[6] = 0x00;                 //
-       para[7] = 0x00;                 //
-       para[8] = 0x01;                 //[7:4]:MTX portX gate control, [3:0]: MTX select
-       para[9] = 0x00;                 //
-       para[10] = 0x01;
-       para[11] = 0x00;
+    para[7] = 0x00;                 //
+    para[8] = 0x01;                 //[7:4]:MTX portX gate control, [3:0]: MTX select
+    para[9] = 0x00;                 //
+    para[10] = 0x01;
+    para[11] = 0x00;
+
+       return HostCmd_Sensor_Set(priv,para, para_num, 100);
+       #endif
+
+       return 0;
+}
+
+bool SendCmd_sensor_temperature_get(struct ox05b1s *priv)
+{
+       #ifdef CONFIG_ULTRON_POS
+       struct camera_common_data *s_data = priv->s_data;
+       uint8_t para_num = 12;
+       uint8_t para[12];
+       static ox05b1s_reg m_i2c_write_regs_2[1] = {
+               {0x4053, 0x00}
+       };
+       int rc = 0;
+
+       dev_info(&priv->i2c_client->dev, "SendCmd_sensor_temperature_get\n");
+    rc = regmap_write(s_data->regmap, m_i2c_write_regs_2[0].addr, m_i2c_write_regs_2[0].val);
+       if (rc < 0) {
+               dev_err(&priv->i2c_client->dev,"OAX4000:Failed to write 0x4053 rc %d", rc);
+               return 0;
+       }
+
+       para[0] = 0x00;         //crc
+       para[1] = 0x00;
+       para[2] = 0;//g_hc_seqIdx++;     // hc_seq_num
+       para[3] = CMD_TEMP_GET; //stream ctrl
+       para[4] = 0x00;                 //para num hi
+       para[5] = 0x01;                 //para num lo
+       para[6] = 0x00;                 //get sensor 0 temperature
+
        return HostCmd_Sensor_Set(priv,para, para_num, 100);
        #endif
 
@@ -3281,6 +3319,7 @@ long ox05b1s_v4l2subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *ar
        struct tegracam_device *tc_dev = to_tegracam_device(s_data);
        void* priv = NULL;
        uint32_t value;
+       struct reg_8 *reg_io = NULL;
 
        if (!arg) {
                dev_err(tc_dev->dev, "Null argument for cmd: %u\n", cmd);
@@ -3326,7 +3365,7 @@ long ox05b1s_v4l2subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *ar
                break;
        case VIDIOC_PRIVATE_IOCTL_ISP_READ_REG:
        {
-               struct reg_8 *reg_io = (struct reg_8 *)arg;
+               reg_io = (struct reg_8 *)arg;
                // dev_info(tc_dev->dev, "Isp read reg: 0x%x\n", reg_io->addr);
                ret = ox05b1s_read_reg(s_data, reg_io->addr, &reg_io->val);
                // if (ret == 0) {
@@ -3334,6 +3373,17 @@ long ox05b1s_v4l2subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *ar
                // }
                break;
        }
+       case VIDIOC_PRIVATE_IOCTL_ISP_HOSTCMD_READ_REG:
+       {
+               // reg_io = (struct reg_8 *)arg;
+               // dev_info(tc_dev->dev, "Isp read reg: 0x%x\n", reg_io->addr);
+               ret = SendCmd_sensor_temperature_get(priv);
+               // if (ret == 0) {
+                       // dev_info(tc_dev->dev, "Read reg 0x%x: 0x%x\n", reg_io->addr, reg_io->val);
+               // }
+               break;
+       }
+
        // ignore cmd:3224131130
        case VIDIOC_CROPCAP:
                break;

4. 计算公式

double calculate_tpm_temperature(int tpm_int, int tpm_dec) {
    const int threshold = 192;  // 0xC0 = 192
    
    if (tpm_int >= threshold) {
        return -1.0 * ((tpm_int - threshold) + tpm_dec / 256.0);
    } else {
        return tpm_int + tpm_dec / 256.0;
    }
}

5. 温度读取

struct reg_8 value = {0};

value.addr = 0x912c;
		ret = ioctl(fd, VIDIOC_PRIVATE_IOCTL_ISP_READ_REG, &value);
		if (ret < 0) {
			perror("Upgrade command failed to send.\n");
			//return ret;
		}
		temp_int = value.val;
		// printf("TEMP reg 0x912c, value: 0x%x\n", temp_int);

		value.addr = 0x912d;
		ret = ioctl(fd, VIDIOC_PRIVATE_IOCTL_ISP_READ_REG, &value);
		if (ret < 0) {
			perror("Upgrade command failed to send.\n");
			//return ret;
		}
		temp_dec = value.val;
		// printf("TEMP reg 0x912d, value: 0x%x\n", temp_dec);
		close(fd);

		// calc temperature
		double temp1 = calculate_tpm_temperature(temp_int, temp_dec);
		printf("TEMP %.2f°C (INT: %3d, DEC: %3d)\n\n", temp1, temp_int, temp_dec);

6. 测试结果

OAX4000读取结果:

OX05B1S 温度读取结果: