Skip to content

Commit 5a11101

Browse files
geohotComma Device
and
Comma Device
authored
camerad: imx390 support (commaai#23966)
* something is output * min stuff * visible picture * pics look good * maybe * whole sensor * fix all cameras * support both cameras * autoexposure for imx390 * fix imx390 blacklevel * touchups * put gain in db scale * inline and fix max exposure Co-authored-by: Comma Device <device@comma.ai>
1 parent 6c7d178 commit 5a11101

File tree

6 files changed

+146
-48
lines changed

6 files changed

+146
-48
lines changed

selfdrive/camerad/cameras/camera_common.cc

+6-3
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ class Debayer {
5252
CL_CHECK(clReleaseProgram(prg_debayer));
5353
}
5454

55-
void queue(cl_command_queue q, cl_mem cam_buf_cl, cl_mem buf_cl, int width, int height, float gain, cl_event *debayer_event) {
55+
void queue(cl_command_queue q, cl_mem cam_buf_cl, cl_mem buf_cl, int width, int height, float gain, float black_level, cl_event *debayer_event) {
5656
CL_CHECK(clSetKernelArg(krnl_, 0, sizeof(cl_mem), &cam_buf_cl));
5757
CL_CHECK(clSetKernelArg(krnl_, 1, sizeof(cl_mem), &buf_cl));
5858

@@ -62,6 +62,7 @@ class Debayer {
6262
const size_t globalWorkSize[] = {size_t(width), size_t(height)};
6363
const size_t localWorkSize[] = {debayer_local_worksize, debayer_local_worksize};
6464
CL_CHECK(clSetKernelArg(krnl_, 2, localMemSize, 0));
65+
CL_CHECK(clSetKernelArg(krnl_, 3, sizeof(float), &black_level));
6566
CL_CHECK(clEnqueueNDRangeKernel(q, krnl_, 2, NULL, globalWorkSize, localWorkSize, 0, 0, debayer_event));
6667
} else {
6768
if (hdr_) {
@@ -165,13 +166,15 @@ bool CameraBuf::acquire() {
165166

166167
if (debayer) {
167168
float gain = 0.0;
168-
169+
float black_level = 42.0;
169170
#ifndef QCOM2
170171
gain = camera_state->digital_gain;
171172
if ((int)gain == 0) gain = 1.0;
173+
#else
174+
if (camera_state->camera_id == CAMERA_ID_IMX390) black_level = 64.0;
172175
#endif
173176

174-
debayer->queue(q, camrabuf_cl, cur_rgb_buf->buf_cl, rgb_width, rgb_height, gain, &event);
177+
debayer->queue(q, camrabuf_cl, cur_rgb_buf->buf_cl, rgb_width, rgb_height, gain, black_level, &event);
175178
} else {
176179
assert(rgb_stride == camera_state->ci.frame_stride);
177180
CL_CHECK(clEnqueueCopyBuffer(q, camrabuf_cl, cur_rgb_buf->buf_cl, 0, 0, cur_rgb_buf->len, 0, 0, &event));

selfdrive/camerad/cameras/camera_common.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525
#define CAMERA_ID_LGC920 6
2626
#define CAMERA_ID_LGC615 7
2727
#define CAMERA_ID_AR0231 8
28-
#define CAMERA_ID_MAX 9
28+
#define CAMERA_ID_IMX390 9
29+
#define CAMERA_ID_MAX 10
2930

3031
const int UI_BUF_COUNT = 4;
3132
const int YUV_BUFFER_COUNT = Hardware::EON() ? 100 : 40;

selfdrive/camerad/cameras/camera_qcom2.cc

+78-27
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
#include "selfdrive/common/swaglog.h"
2323
#include "selfdrive/camerad/cameras/sensor2_i2c.h"
2424

25+
// For debugging:
26+
// echo "4294967295" > /sys/module/cam_debug_util/parameters/debug_mdl
27+
2528
extern ExitHandler do_exit;
2629

2730
const size_t FRAME_WIDTH = 1928;
@@ -39,6 +42,14 @@ CameraInfo cameras_supported[CAMERA_ID_MAX] = {
3942
.bayer_flip = 1,
4043
.hdr = false
4144
},
45+
[CAMERA_ID_IMX390] = {
46+
.frame_width = FRAME_WIDTH,
47+
.frame_height = FRAME_HEIGHT,
48+
.frame_stride = FRAME_STRIDE,
49+
.bayer = true,
50+
.bayer_flip = 1,
51+
.hdr = false
52+
},
4253
};
4354

4455
const float DC_GAIN = 2.5;
@@ -160,8 +171,15 @@ void clear_req_queue(int fd, int32_t session_hdl, int32_t link_hdl) {
160171
// ************** high level camera helpers ****************
161172

162173
void CameraState::sensors_start() {
163-
int start_reg_len = sizeof(start_reg_array) / sizeof(struct i2c_random_wr_payload);
164-
sensors_i2c(start_reg_array, start_reg_len, CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG);
174+
if (camera_id == CAMERA_ID_AR0231) {
175+
int start_reg_len = sizeof(start_reg_array_ar0231) / sizeof(struct i2c_random_wr_payload);
176+
sensors_i2c(start_reg_array_ar0231, start_reg_len, CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG, true);
177+
} else if (camera_id == CAMERA_ID_IMX390) {
178+
int start_reg_len = sizeof(start_reg_array_imx390) / sizeof(struct i2c_random_wr_payload);
179+
sensors_i2c(start_reg_array_imx390, start_reg_len, CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG, false);
180+
} else {
181+
assert(false);
182+
}
165183
}
166184

167185
void CameraState::sensors_poke(int request_id) {
@@ -181,7 +199,7 @@ void CameraState::sensors_poke(int request_id) {
181199
release_fd(multi_cam_state->video0_fd, cam_packet_handle);
182200
}
183201

184-
void CameraState::sensors_i2c(struct i2c_random_wr_payload* dat, int len, int op_code) {
202+
void CameraState::sensors_i2c(struct i2c_random_wr_payload* dat, int len, int op_code, bool data_word) {
185203
// LOGD("sensors_i2c: %d", len);
186204
uint32_t cam_packet_handle = 0;
187205
int size = sizeof(struct cam_packet)+sizeof(struct cam_cmd_buf_desc)*1;
@@ -199,7 +217,7 @@ void CameraState::sensors_i2c(struct i2c_random_wr_payload* dat, int len, int op
199217
i2c_random_wr->header.count = len;
200218
i2c_random_wr->header.op_code = 1;
201219
i2c_random_wr->header.cmd_type = CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR;
202-
i2c_random_wr->header.data_type = CAMERA_SENSOR_I2C_TYPE_WORD;
220+
i2c_random_wr->header.data_type = data_word ? CAMERA_SENSOR_I2C_TYPE_WORD : CAMERA_SENSOR_I2C_TYPE_BYTE;
203221
i2c_random_wr->header.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD;
204222
memcpy(i2c_random_wr->random_wr_payload, dat, len*sizeof(struct i2c_random_wr_payload));
205223

@@ -220,7 +238,7 @@ static cam_cmd_power *power_set_wait(cam_cmd_power *power, int16_t delay_ms) {
220238
return (struct cam_cmd_power *)(unconditional_wait + 1);
221239
};
222240

223-
void CameraState::sensors_init() {
241+
int CameraState::sensors_init() {
224242
int video0_fd = multi_cam_state->video0_fd;
225243
uint32_t cam_packet_handle = 0;
226244
int size = sizeof(struct cam_packet)+sizeof(struct cam_cmd_buf_desc)*2;
@@ -239,17 +257,17 @@ void CameraState::sensors_init() {
239257
switch (camera_num) {
240258
case 0:
241259
// port 0
242-
i2c_info->slave_addr = 0x20;
260+
i2c_info->slave_addr = (camera_id == CAMERA_ID_AR0231) ? 0x20 : 0x34;
243261
probe->camera_id = 0;
244262
break;
245263
case 1:
246264
// port 1
247-
i2c_info->slave_addr = 0x30;
265+
i2c_info->slave_addr = (camera_id == CAMERA_ID_AR0231) ? 0x30 : 0x36;
248266
probe->camera_id = 1;
249267
break;
250268
case 2:
251269
// port 2
252-
i2c_info->slave_addr = 0x20;
270+
i2c_info->slave_addr = (camera_id == CAMERA_ID_AR0231) ? 0x20 : 0x34;
253271
probe->camera_id = 2;
254272
break;
255273
}
@@ -263,8 +281,15 @@ void CameraState::sensors_init() {
263281
probe->addr_type = CAMERA_SENSOR_I2C_TYPE_WORD;
264282
probe->op_code = 3; // don't care?
265283
probe->cmd_type = CAMERA_SENSOR_CMD_TYPE_PROBE;
266-
probe->reg_addr = 0x3000; //0x300a; //0x300b;
267-
probe->expected_data = 0x354; //0x7750; //0x885a;
284+
if (camera_id == CAMERA_ID_AR0231) {
285+
probe->reg_addr = 0x3000;
286+
probe->expected_data = 0x354;
287+
} else if (camera_id == CAMERA_ID_IMX390) {
288+
probe->reg_addr = 0x330;
289+
probe->expected_data = 0x1538;
290+
} else {
291+
assert(false);
292+
}
268293
probe->data_mask = 0;
269294

270295
//buf_desc[1].size = buf_desc[1].length = 148;
@@ -293,7 +318,7 @@ void CameraState::sensors_init() {
293318
power->count = 1;
294319
power->cmd_type = CAMERA_SENSOR_CMD_TYPE_PWR_UP;
295320
power->power_settings[0].power_seq_type = 0;
296-
power->power_settings[0].config_val_low = 19200000; //Hz
321+
power->power_settings[0].config_val_low = (camera_id == CAMERA_ID_AR0231) ? 19200000 : 24000000; //Hz
297322
power = power_set_wait(power, 10);
298323

299324
// 8,1 is this reset?
@@ -341,14 +366,15 @@ void CameraState::sensors_init() {
341366

342367
LOGD("probing the sensor");
343368
int ret = do_cam_control(sensor_fd, CAM_SENSOR_PROBE_CMD, (void *)(uintptr_t)cam_packet_handle, 0);
344-
assert(ret == 0);
345369

346370
munmap(i2c_info, buf_desc[0].size);
347371
release_fd(video0_fd, buf_desc[0].mem_handle);
348372
munmap(power_settings, buf_desc[1].size);
349373
release_fd(video0_fd, buf_desc[1].mem_handle);
350374
munmap(pkt, size);
351375
release_fd(video0_fd, cam_packet_handle);
376+
377+
return ret;
352378
}
353379

354380
void CameraState::config_isp(int io_mem_handle, int fence, int request_id, int buf0_mem_handle, int buf0_offset) {
@@ -561,9 +587,10 @@ void CameraState::enqueue_req_multi(int start, int n, bool dp) {
561587

562588
// ******************* camera *******************
563589

564-
void CameraState::camera_init(MultiCameraState *multi_cam_state_, VisionIpcServer * v, int camera_id, int camera_num_, unsigned int fps, cl_device_id device_id, cl_context ctx, VisionStreamType rgb_type, VisionStreamType yuv_type) {
590+
void CameraState::camera_init(MultiCameraState *multi_cam_state_, VisionIpcServer * v, int camera_id_, int camera_num_, unsigned int fps, cl_device_id device_id, cl_context ctx, VisionStreamType rgb_type, VisionStreamType yuv_type) {
565591
LOGD("camera init %d", camera_num);
566592
multi_cam_state = multi_cam_state_;
593+
camera_id = camera_id_;
567594
assert(camera_id < std::size(cameras_supported));
568595
ci = cameras_supported[camera_id];
569596
assert(ci.frame_width != 0);
@@ -586,17 +613,24 @@ void CameraState::camera_init(MultiCameraState *multi_cam_state_, VisionIpcServe
586613
}
587614

588615
void CameraState::camera_open() {
616+
int ret;
589617
sensor_fd = open_v4l_by_name_and_index("cam-sensor-driver", camera_num);
590618
assert(sensor_fd >= 0);
591619
LOGD("opened sensor for %d", camera_num);
592620

593621
// probe the sensor
594622
LOGD("-- Probing sensor %d", camera_num);
595-
sensors_init();
623+
ret = sensors_init();
624+
if (ret != 0) {
625+
LOGD("AR0231 init failed, trying IMX390");
626+
camera_id = CAMERA_ID_IMX390;
627+
ret = sensors_init();
628+
}
629+
assert(ret == 0);
596630

597631
// create session
598632
struct cam_req_mgr_session_info session_info = {};
599-
int ret = do_cam_control(multi_cam_state->video0_fd, CAM_REQ_MGR_CREATE_SESSION, &session_info, sizeof(session_info));
633+
ret = do_cam_control(multi_cam_state->video0_fd, CAM_REQ_MGR_CREATE_SESSION, &session_info, sizeof(session_info));
600634
LOGD("get session: %d 0x%X", ret, session_info.session_hdl);
601635
session_handle = session_info.session_hdl;
602636

@@ -675,10 +709,13 @@ void CameraState::camera_open() {
675709
config_isp(0, 0, 1, buf0_handle, 0);
676710

677711
LOG("-- Configuring sensor");
678-
sensors_i2c(init_array_ar0231, std::size(init_array_ar0231), CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG);
679-
//sensors_i2c(start_reg_array, std::size(start_reg_array), CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMON);
680-
//sensors_i2c(stop_reg_array, std::size(stop_reg_array), CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMOFF);
681-
712+
if (camera_id == CAMERA_ID_AR0231) {
713+
sensors_i2c(init_array_ar0231, std::size(init_array_ar0231), CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG, true);
714+
} else if (camera_id == CAMERA_ID_IMX390) {
715+
sensors_i2c(init_array_imx390, std::size(init_array_imx390), CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG, false);
716+
} else {
717+
assert(false);
718+
}
682719

683720
// config csiphy
684721
LOG("-- Config CSI PHY");
@@ -1008,14 +1045,28 @@ void CameraState::set_camera_exposure(float grey_frac) {
10081045
}
10091046
// LOGE("ae - camera %d, cur_t %.5f, sof %.5f, dt %.5f", camera_num, 1e-9 * nanos_since_boot(), 1e-9 * buf.cur_frame_data.timestamp_sof, 1e-9 * (nanos_since_boot() - buf.cur_frame_data.timestamp_sof));
10101047

1011-
uint16_t analog_gain_reg = 0xFF00 | (new_g << 4) | new_g;
1012-
struct i2c_random_wr_payload exp_reg_array[] = {
1013-
{0x3366, analog_gain_reg},
1014-
{0x3362, (uint16_t)(dc_gain_enabled ? 0x1 : 0x0)},
1015-
{0x3012, (uint16_t)exposure_time},
1016-
};
1017-
sensors_i2c(exp_reg_array, sizeof(exp_reg_array)/sizeof(struct i2c_random_wr_payload),
1018-
CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG);
1048+
if (camera_id == CAMERA_ID_AR0231) {
1049+
uint16_t analog_gain_reg = 0xFF00 | (new_g << 4) | new_g;
1050+
struct i2c_random_wr_payload exp_reg_array[] = {
1051+
{0x3366, analog_gain_reg},
1052+
{0x3362, (uint16_t)(dc_gain_enabled ? 0x1 : 0x0)},
1053+
{0x3012, (uint16_t)exposure_time},
1054+
};
1055+
sensors_i2c(exp_reg_array, sizeof(exp_reg_array)/sizeof(struct i2c_random_wr_payload), CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG, true);
1056+
} else if (camera_id == CAMERA_ID_IMX390) {
1057+
// if gain is sub 1, we have to use exposure to mimic sub 1 gains
1058+
uint32_t real_exposure_time = (gain < 1.0) ? (exposure_time*gain) : exposure_time;
1059+
// invert real_exposure_time, max exposure is 2
1060+
real_exposure_time = (exposure_time >= 0x7cf) ? 2 : (0x7cf - exposure_time);
1061+
uint32_t real_gain = int((10*log10(fmax(1.0, gain)))/0.3);
1062+
//printf("%d expose: %d gain: %f = %d\n", camera_num, exposure_time, gain, real_gain);
1063+
struct i2c_random_wr_payload exp_reg_array[] = {
1064+
{0x000c, real_exposure_time&0xFF}, {0x000d, real_exposure_time>>8},
1065+
{0x0010, real_exposure_time&0xFF}, {0x0011, real_exposure_time>>8},
1066+
{0x0018, real_gain&0xFF}, {0x0019, real_gain>>8},
1067+
};
1068+
sensors_i2c(exp_reg_array, sizeof(exp_reg_array)/sizeof(struct i2c_random_wr_payload), CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG, false);
1069+
}
10191070
}
10201071

10211072
void camera_autoexposure(CameraState *s, float grey_frac) {

selfdrive/camerad/cameras/camera_qcom2.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ class CameraState {
4040

4141
void sensors_start();
4242
void sensors_poke(int request_id);
43-
void sensors_i2c(struct i2c_random_wr_payload* dat, int len, int op_code);
44-
void sensors_init();
43+
void sensors_i2c(struct i2c_random_wr_payload* dat, int len, int op_code, bool data_word);
44+
int sensors_init();
4545

4646
void camera_open();
4747
void camera_init(MultiCameraState *multi_cam_state, VisionIpcServer * v, int camera_id, int camera_num, unsigned int fps, cl_device_id device_id, cl_context ctx, VisionStreamType rgb_type, VisionStreamType yuv_type);
@@ -62,6 +62,7 @@ class CameraState {
6262
int frame_id_last;
6363
int idx_offset;
6464
bool skipped;
65+
int camera_id;
6566

6667
CameraBuf buf;
6768
};
@@ -73,7 +74,6 @@ typedef struct MultiCameraState {
7374
int device_iommu;
7475
int cdm_iommu;
7576

76-
7777
CameraState road_cam;
7878
CameraState wide_road_cam;
7979
CameraState driver_cam;

selfdrive/camerad/cameras/real_debayer.cl

+11-12
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
22

3-
const half black_level = 42.0;
4-
53
const __constant half3 color_correction[3] = {
64
// post wb CCM
75
(half3)(1.82717181, -0.31231438, 0.07307673),
@@ -39,7 +37,7 @@ half3 color_correct(half3 rgb) {
3937
return ret;
4038
}
4139

42-
half val_from_10(const uchar * source, int gx, int gy) {
40+
inline half val_from_10(const uchar * source, int gx, int gy, half black_level) {
4341
// parse 12bit
4442
int start = gy * FRAME_STRIDE + (3 * (gx / 2));
4543
int offset = gx % 2;
@@ -49,7 +47,7 @@ half val_from_10(const uchar * source, int gx, int gy) {
4947

5048
// normalize
5149
pv = max(0.0h, pv - black_level);
52-
pv *= 0.00101833h; // /= (1024.0f - black_level);
50+
pv /= (1024.0f - black_level);
5351

5452
// correct vignetting
5553
if (CAM_NUM == 1) { // fcamera
@@ -89,7 +87,8 @@ half phi(half x) {
8987

9088
__kernel void debayer10(const __global uchar * in,
9189
__global uchar * out,
92-
__local half * cached
90+
__local half * cached,
91+
float black_level
9392
)
9493
{
9594
const int x_global = get_global_id(0);
@@ -102,7 +101,7 @@ __kernel void debayer10(const __global uchar * in,
102101

103102
int out_idx = 3 * x_global + 3 * y_global * RGB_WIDTH;
104103

105-
half pv = val_from_10(in, x_global, y_global);
104+
half pv = val_from_10(in, x_global, y_global, black_level);
106105
cached[localOffset] = pv;
107106

108107
// don't care
@@ -118,22 +117,22 @@ __kernel void debayer10(const __global uchar * in,
118117
if (x_local < 1) {
119118
localColOffset = x_local;
120119
globalColOffset = -1;
121-
cached[(y_local + 1) * localRowLen + x_local] = val_from_10(in, x_global-1, y_global);
120+
cached[(y_local + 1) * localRowLen + x_local] = val_from_10(in, x_global-1, y_global, black_level);
122121
} else if (x_local >= get_local_size(0) - 1) {
123122
localColOffset = x_local + 2;
124123
globalColOffset = 1;
125-
cached[localOffset + 1] = val_from_10(in, x_global+1, y_global);
124+
cached[localOffset + 1] = val_from_10(in, x_global+1, y_global, black_level);
126125
}
127126

128127
if (y_local < 1) {
129-
cached[y_local * localRowLen + x_local + 1] = val_from_10(in, x_global, y_global-1);
128+
cached[y_local * localRowLen + x_local + 1] = val_from_10(in, x_global, y_global-1, black_level);
130129
if (localColOffset != -1) {
131-
cached[y_local * localRowLen + localColOffset] = val_from_10(in, x_global+globalColOffset, y_global-1);
130+
cached[y_local * localRowLen + localColOffset] = val_from_10(in, x_global+globalColOffset, y_global-1, black_level);
132131
}
133132
} else if (y_local >= get_local_size(1) - 1) {
134-
cached[(y_local + 2) * localRowLen + x_local + 1] = val_from_10(in, x_global, y_global+1);
133+
cached[(y_local + 2) * localRowLen + x_local + 1] = val_from_10(in, x_global, y_global+1, black_level);
135134
if (localColOffset != -1) {
136-
cached[(y_local + 2) * localRowLen + localColOffset] = val_from_10(in, x_global+globalColOffset, y_global+1);
135+
cached[(y_local + 2) * localRowLen + localColOffset] = val_from_10(in, x_global+globalColOffset, y_global+1, black_level);
137136
}
138137
}
139138

0 commit comments

Comments
 (0)