📄 camera_ov9640.c
字号:
static intfind_vctrl(int id){ int i; if (id < V4L2_CID_BASE || id > V4L2_CID_LAST_PRIV) return -EDOM; for (i = NUM_CONTROLS - 1; i >= 0; i--) if (control[i].qc.id == id) break; if (i < 0) i = -EINVAL; return i;}static intov9640_querymenu(struct v4l2_querymenu *qm){ /* No menu controls have been defined */ return -EINVAL;}static intov9640_query_control(struct v4l2_queryctrl *qc){ int i; i = find_vctrl(qc->id); if (i == -EINVAL) { qc->flags = V4L2_CTRL_FLAG_DISABLED; return 0; } if (i < 0) return -EINVAL; /* V4L2 filled in category and group, preserve them */ control[i].qc.category = qc->category; memcpy(control[i].qc.group, qc->group, sizeof(qc->group)); *qc = control[i].qc; return 0;}static int ov9640_write_control(struct vcontrol * lvc, u8 value){ struct camera_serial_bus * sbus = this->camif->sbus; u8 oldval, newval; u8 reg = lvc->reg; u8 mask = lvc->mask; int rc; value <<= lvc->start_bit; if (mask == 0xff) { newval = value; } else { if ((rc = sbus->read(reg, &oldval, 1))) return rc; oldval &= ~mask; /* Clear the masked bits */ value &= mask; /* Enforce mask on value */ newval = oldval | value; /* Set the desired bits */ } if ((rc = sbus->write(reg, &newval, 1))) return rc; if ((rc = sbus->read(reg, &newval, 1))) return rc; return (newval & mask) >> lvc->start_bit;}static int ov9640_read_control(struct vcontrol * lvc){ struct camera_serial_bus * sbus = this->camif->sbus; u8 val; u8 reg = lvc->reg; u8 mask = lvc->mask; int rc; if ((rc = sbus->read(reg, &val, 1))) return rc; return (val & mask) >> lvc->start_bit;}static intov9640_control(struct v4l2_control *vc, int write){ int i, val; struct vcontrol * lvc; i = find_vctrl(vc->id); if (i < 0) return -EINVAL; lvc = &control[i]; if (write) val = ov9640_write_control(lvc, vc->value); else val = ov9640_read_control(lvc); if (val >= 0) { vc->value = lvc->current_value = val; return 0; } else return val;}static intov9640_set_control(struct v4l2_control *vc){ return ov9640_control(vc, 1);}static intov9640_get_control(struct v4l2_control *vc){ return ov9640_control(vc, 0);}static intov9640_restore_current_controls(void){ struct v4l2_control vc; int i, rc=0; for (i=0; i<NUM_CONTROLS; i++) { vc.id = control[i].qc.id; vc.value = control[i].current_value; if ((rc = ov9640_set_control(&vc))) break; } return rc;}static intov9640_save_current_controls(void){ struct v4l2_control vc; int i, rc=0; for (i=0; i<NUM_CONTROLS; i++) { vc.id = control[i].qc.id; if ((rc = ov9640_get_control(&vc))) break; } return rc;}struct fract { unsigned long numerator; unsigned long denominator;}; /* Calculate the internal clock divisor (value of the CLKRC register) of the * OV9640 given the image size, the frequency (in Hz) of its XCLK input and a * desired frame period (in seconds). The frame period 'fper' is expressed as * a fraction. The frame period is an input/output parameter. * Returns the value of the OV9640 CLKRC register that will yield the frame * period returned in 'fper' at the specified xclk frequency. The * returned period will be as close to the requested period as possible. */static unsigned charov9640_clkrc(unsigned long xclk, struct fract *fper){ unsigned long fpm, fpm_max; /* frames per minute */ unsigned long divisor; const unsigned long divisor_max = 64; const static unsigned long clks_per_frame[] = { 200000, 400000, 200000, 400000, 400000, 800000, 3200000 }; /* QQCIF QQVGA QCIF QVGA CIF VGA SXGA *actually 199680,400000, 199680, 400000, 399360, 800000, 3200000 */ if (fper->numerator > 0) fpm = (fper->denominator*60)/fper->numerator; else fpm = 0xffffffff; fpm_max = (xclk*60)/clks_per_frame[this->imgfmt]; if (fpm_max == 0) fpm_max = 1; if (fpm > fpm_max) fpm = fpm_max; if (fpm == 0) fpm = 1; divisor = fpm_max/fpm; if (divisor > divisor_max) divisor = divisor_max; fper->numerator = divisor*60; fper->denominator = fpm_max; /* try to reduce the fraction */ while (!(fper->denominator % 5) && !(fper->numerator % 5)) { fper->numerator /= 5; fper->denominator /= 5; } while (!(fper->denominator % 3) && !(fper->numerator % 3)) { fper->numerator /= 3; fper->denominator /= 3; } while (!(fper->denominator % 2) && !(fper->numerator % 2)) { fper->numerator /= 2; fper->denominator /= 2; } if (fper->numerator < fper->denominator) { if (!(fper->denominator % fper->numerator)) { fper->denominator /= fper->numerator; fper->numerator = 1; } } else { if (!(fper->numerator % fper->denominator)) { fper->numerator /= fper->denominator; fper->denominator = 1; } } /* we set bit 7 in CLKRC to enable the digital PLL */ return (0x80 | (divisor - 1));}static inline void cvt_fp_to_fract(struct fract * fper, int fp){ fper->numerator = fp; fper->denominator = 10000000;}static inline int cvt_fract_to_fp(struct fract * fper){ return (fper->numerator * 10000000) / fper->denominator;}static int ov9640_set_fp(int fp, int xclk, int test){ struct camera_serial_bus * sbus = this->camif->sbus; struct fract fper; int retfp; u8 clkrc; cvt_fp_to_fract(&fper, fp); /* configure frame rate */ clkrc = ov9640_clkrc(xclk, &fper); retfp = cvt_fract_to_fp(&fper); if (!test) { int err = sbus->write(OV9640_CLKRC, &clkrc, 1); if (err) return err; current_frame_period = retfp; current_xclk = xclk; } return retfp;}static int ov9640_get_fp(void){ return current_frame_period;}/* * Configure the OV9640 for the current image size, pixel format, and * frame rate. Returns zero if successful, or non-zero otherwise. */static intov9640_configure(void){ int err; /* common register initialization */ err = ov_write_reglist(ov9640_common); if (err) return err; /* configure image size and pixel format */ err = ov_write_reglist(ov9640_reg_init[this->pixfmt][this->imgfmt]); if (err) return err; /* restore the current controls */ err = ov9640_restore_current_controls(); if (err) return err; /* * and finally set the internal clock to generate the * current frame rate for this image format */ err = ov9640_set_fp(current_frame_period, current_xclk, 0); if (err < 0) return err; return 0;}/* Convert a Video for Linux pixelformat to an enum pixel_format value. */static intov9640_find_format(struct v4l2_pix_format* fmt){ switch (fmt->pixelformat) { case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_UYVY: return YUV; case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_RGB565X: case V4L2_PIX_FMT_BGR24: /* will have to convert to BGR24 */ return RGB565; case V4L2_PIX_FMT_RGB555: case V4L2_PIX_FMT_RGB555X: return RGB555; } return -1;}/* * Find the best match for a requested image capture size. The best match * is chosen as the nearest match that has the same number or fewer pixels * as the requested size, or the smallest image size if the requested size * has fewer pixels than the smallest image. */static intov9640_find_size(struct v4l2_pix_format* fmt){ int isize; unsigned long pixels = fmt->width * fmt->height; for (isize = QQCIF; isize < SXGA; isize++) { if (omap_image_size[isize + 1].height * omap_image_size[isize + 1].width > pixels) { fmt->width = omap_image_size[isize].width; fmt->height = omap_image_size[isize].height; return isize; } } fmt->width = omap_image_size[SXGA].width; fmt->height = omap_image_size[SXGA].height; return SXGA;}static int ov9640_setup(struct v4l2_pix_format* fmt){ enum pixel_format pixfmt; enum image_format imgfmt; if ((pixfmt = ov9640_find_format(fmt)) < 0) return -EINVAL; imgfmt = ov9640_find_size(fmt); this->imgfmt = imgfmt; this->pixfmt = pixfmt; return ov9640_configure();}static int ov9640_open(void){ return ov9640_configure();}static int ov9640_close(void){ /* * save the current controls so they can be restored on * next open. */ return ov9640_save_current_controls();}static int ov9640_init(void){ int i; for (i=0; i<NUM_CONTROLS; i++) control[i].current_value = control[i].qc.default_value; this->imgfmt = QVGA; this->pixfmt = RGB565; return 0;}static void ov9640_cleanup(void){ /* nothing to do */}static int ov9640_detect(void){ struct camera_serial_bus * sbus; u8 midh, midl, pid, ver; int rc; this = &camera_ov9640; sbus = this->camif->sbus; sbus->set_devid(CAMERA_OV9640_DEV_ID); if ((rc = sbus->read(OV9640_MIDH, &midh, 1))) return rc; if ((rc = sbus->read(OV9640_MIDL, &midl, 1))) return rc; if ((rc = sbus->read(OV9640_PID, &pid, 1))) return rc; if ((rc = sbus->read(OV9640_VER, &ver, 1))) return rc; if ((midh != OV9640_MIDH_MAGIC) || (midl != OV9640_MIDL_MAGIC) || (pid != OV9640_PID_MAGIC)) { /* We didn't read the values we expected, so * this must not be an OV9640. */ return -ENODEV; } return 0;}struct camera camera_ov9640 = { imgfmt: QVGA, pixfmt: RGB565, detect: ov9640_detect, init: ov9640_init, cleanup: ov9640_cleanup, open: ov9640_open, close: ov9640_close, set_format: ov9640_setup, set_frame_period: ov9640_set_fp, get_frame_period: ov9640_get_fp, convert_image: ov9640_convert_image, query_control: ov9640_query_control, get_control: ov9640_get_control, set_control: ov9640_set_control, query_menu: ov9640_querymenu,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -