📄 camera_ov9640.c
字号:
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_default_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].qc.default_value; if ((rc = ov9640_set_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 inline 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_default_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; for (isize = QQCIF; isize < SXGA; isize++) { if ((mx2ads_image_size[isize].height >= fmt->height) && (mx2ads_image_size[isize].width >= fmt->width)) { fmt->width = mx2ads_image_size[isize].width; fmt->height = mx2ads_image_size[isize].height; return isize; } } fmt->width = mx2ads_image_size[SXGA].width; fmt->height = mx2ads_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; /* configure image size and pixel format */ return ov_write_reglist(ov9640_reg_init[this->pixfmt][this->imgfmt]);}static int ov9640_open(void){ uint16_t reg_val; /* * Make standby low (disable standby) */ CSI_REG_READ(EXP_IO, reg_val); reg_val &= ~EXP_IO_CSI_CTL0; CSI_REG_WRITE(EXP_IO, reg_val); udelay(20); return 0;}static int ov9640_close(void){ uint16_t reg_val; /* * Make standby high (enable standby) */ CSI_REG_READ(EXP_IO, reg_val); reg_val |= EXP_IO_CSI_CTL0; CSI_REG_WRITE(EXP_IO, reg_val); udelay(20); return 0;}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; ov9640_configure(); ov9640_close(); return 0;}static void ov9640_cleanup(void){ ov9640_close(); this->camif->sbus->cleanup();}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); /* * Special MDS register (controls CNTL and LEDs) */ uint16_t reg_val; CSI_REG_READ(EXP_IO, reg_val); /* * Make standby low (disable standby) */ reg_val &= ~EXP_IO_CSI_CTL0; CSI_REG_WRITE(EXP_IO, reg_val); udelay(20); /* * Make reset high (reset sensor) */ reg_val |= EXP_IO_CSI_CTL1; CSI_REG_WRITE(EXP_IO, reg_val); udelay(200); /* * Make reset low */ reg_val &= ~EXP_IO_CSI_CTL1; CSI_REG_WRITE(EXP_IO, reg_val); mdelay(15); if ((rc = sbus->init()) < 0) { ov9640_cleanup(); return rc; } if ((rc = sbus->read(OV9640_MIDH, &midh, 1))) { ov9640_cleanup(); return rc; } if ((rc = sbus->read(OV9640_MIDL, &midl, 1))) { ov9640_cleanup(); return rc; } if ((rc = sbus->read(OV9640_PID, &pid, 1))) { ov9640_cleanup(); return rc; } if ((rc = sbus->read(OV9640_VER, &ver, 1))) { ov9640_cleanup(); 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. */ ov9640_cleanup(); 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, 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 + -