Sample code of section 10 in Nov 2014 issue of the Interface Magazine, published by CQ publishing in Japan. CQ出版社インターフェース誌 2014年11月号10章に掲載のサンプルコードです. LPC1768にトラ技OV7670モジュールを接続したうえで,省メモリ画像処理(色による簡易顔検出)を行う事例です.画像フレームバッファを確保できないとき,ストリーム処理で画像を加工するのがテーマです.このコードのうちカメラ制御部には,Sadaei Osakabe氏のコードを流用させていただいています.
Revision 0:d2c78848026d, committed 2014-09-24
- Comitter:
- smorioka
- Date:
- Wed Sep 24 20:48:23 2014 +0000
- Commit message:
- First release;
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TextLCD.lib Wed Sep 24 20:48:23 2014 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/simon/code/TextLCD/#308d188a2d3a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Wed Sep 24 20:48:23 2014 +0000 @@ -0,0 +1,875 @@ +/* + * Copyright (c) 2014, Sumio Morioka + * All rights reserved. + * + * This source code was originally written by Dr.Sumio Morioka for use in the Nov 2014 issue of + * "the Interface magazine", published by CQ publishing Co.Ltd in Japan (http://www.cqpub.co.jp). + * The author has no responsibility on any results caused by using this code. + * + * - Distribution date of this code: Sep 24, 2014 + * - Author: Dr.Sumio Morioka (http://www002.upp.so-net.ne.jp/morioka) + * + * + * IMPORTANT NOTICE: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mbed.h" +#include "TextLCD.h" +#include "LocalFileSystem.h" + +#include "ov7670.h" + +TextLCD lcd(p24, p26, p27, p28, p29, p30); +DigitalOut led1(LED1), led2(LED2), led3(LED3), led4(LED4); +PwmOut sv0(p21), sv1(p22), sv2(p23); + +LocalFileSystem local("webfs"); + +OV7670 camera( + p9,p10, // SDA,SCL(I2C / SCCB) + p5,p6,p7, // VSYNC,HREF,WEN(FIFO) + p20,p19,p18,p17,p16,p15,p14,p13, // D7-D0 + p8,p11,p12); // RRST,OE,RCLK + +Timer tmr; + +//#define QQVGA +#define QVGA +//#define VGA34 + +#ifdef QQVGA +#define SIZEX 160 +#define SIZEY 120 +#endif + +#ifdef QVGA +#define SIZEX 320 +#define SIZEY 240 +#endif + +#ifdef VGA34 +#define SIZEX 480 +#define SIZEY 360 +#endif + + +#define SHUTTER_THRESHOLD 3500 // # of skin color pixels + + +///////////////////////////////////////////////////////////////////////////////// + +void rgb2hsv( + unsigned char rval, + unsigned char gval, + unsigned char bval, + + unsigned char *hval, + unsigned char *sval, + unsigned char *vval +) +{ + unsigned char max, min; + int ret; + + max = (rval >= gval) ? rval : gval; + max = (bval >= max) ? bval : max; + + min = (rval <= gval) ? rval : gval; + min = (bval <= min) ? bval : min; + + /////////////////////////////////////////// + // compute H + /////////////////////////////////////////// + if (max == min) + ret = 0; // (undef) + else if (rval >= gval && rval >= bval) // max: R + ret = ((gval - bval) * 60) / (max - min); + else if (gval >= rval && gval >= bval) // max: G + ret = ((bval - rval) * 60) / (max - min) + 120; + else // max: B + ret = ((rval - gval) * 60) / (max - min) + 240; + + ret %= 360; + if (ret < 0) + ret += 360; + + *hval = (ret * 255) / 360; + + /////////////////////////////////////////// + // compute S + /////////////////////////////////////////// + if (max == 0) + ret = 0; // (undef) + else + ret = ((max - min) * 255) / max; + + *sval = ret; + + /////////////////////////////////////////// + // compute V + /////////////////////////////////////////// + *vval = max; +} + +///////////////////////////////////////////////////////////////////////////////// + +unsigned char judge_skin_color( + unsigned char hval, + unsigned char sval, + unsigned char vval +) +{ + if (hval <= 70 && sval >= 25 && sval <= 70 && vval >= 180 && vval <= 250) // <rgain,ggain,bgain> == <0x48,0x40,0x60> + return (255); + else + return (0); +} + +///////////////////////////////////////////////////////////////////////////////// + +typedef unsigned char (*kernel_func)(unsigned char *linebuf, int x, int y, int line_size, int kernel_size, void *param); // kernel operation function + +typedef struct _stream_filter +{ + // input pixel data + unsigned char d_in0; // plane 0 + unsigned char d_in1; // plane 1 + unsigned char d_in2; // plane 2 + unsigned char d_in_attr; // data attribute (see the definitions below) + + // output pixel data + unsigned char d_out0; // plane 0 + unsigned char d_out1; // plane 1 + unsigned char d_out2; // plane 2 + unsigned char d_out_attr; // data attribute (see the definitions below) + + // output data + char is_3_planes; // 0: single plane, Others: 3 planes + + //////////////////////////////////////// + // internal variables (do not touch) + //////////////////////////////////////// + char state; // internal + + int d_in_cnt; // # of total input + int d_in_x; // x-coordinate of input position on "line_buf" (not on entire screen) + int d_in_y; // y-coordinate + + int d_out_cnt; // # of total output + int d_out_x; // x-coordinate of center of kernel on "line_buf" (not on entire screen) + int d_out_y; // y-coordinate + + int line_size; // width + int kernel_size; // kernel size (MUST be odd) + + unsigned char *line_buf0; // line buffer for plane 0 + unsigned char *line_buf1; // plane 1 + unsigned char *line_buf2; // plane 2 + + kernel_func func; // pointer to a kernel operation function + void *func_param; // parameter to the above function (ex. pointer to coefficient matrix etc.) +} stream_filter; + + +#define ATTR_1ST 0 // 1st pixel data +#define ATTR_VALID 1 // valid pixel data (not 1st nor last) +#define ATTR_LAST 2 // last pixel data +#define ATTR_INVALID 3 // invalid pixel data + +#define STATE_PROCESS 0 // do not touch +#define STATE_FLUSH 1 // do not touch + +#ifdef DEBUG +FILE *fp_his; +#endif // DEBUG + + +///////////////////--> kernel func +unsigned char comb_filter(unsigned char *linebuf, int x, int y, int line_size, int kernel_size, void *matrix_void) +{ + float acc = 0.0f; + int mat_idx = 0; + + ////////////////////////////////////////////// ---> customize here + float *matrix = (float *)matrix_void; + ////////////////////////////////////////////// <--- customize here + +#ifdef DEBUG + fprintf(fp_his, "\tpixel: "); +#endif + + // scan kernel + for (int ky = y - ((kernel_size - 1) / 2); ky <= y + (kernel_size - 1) / 2; ky++) { + int ly; + // (rounding linebuf) + if (ky < 0) + ly = ky + (kernel_size + 1); + else if (ky >= kernel_size + 1) + ly = ky - (kernel_size + 1); + else + ly = ky; + + for (int kx = x - ((kernel_size - 1) / 2); kx <= x + (kernel_size - 1) / 2; kx++, mat_idx++) { + if (kx >= 0 && kx < line_size) { + float pixel; + pixel = (float)(*(linebuf + (ly * line_size) + kx)); + + ////////////////////////////////////////////// ---> customize here +#ifdef DEBUG + fprintf(fp_his, "%02x ", *(linebuf + (ly * line_size) + kx)); +#endif + acc += pixel * (*(matrix + mat_idx)); + ////////////////////////////////////////////// <--- customize here + } + } + +#ifdef DEBUG + fprintf(fp_his, ", "); +#endif + } + +#ifdef DEBUG + fprintf(fp_his, "(ret %d)\n", (unsigned char)(acc + 0.5f)); +#endif + + return ((unsigned char)(acc + 0.5f)); +} +///////////////////<-- kernel func + + +void dump_stream_filter(FILE *fp, stream_filter *flt) // for debug; dump contents of the structure data +{ + fprintf(fp, "d_in %02x ", flt->d_in0); + if (flt->d_in_attr == ATTR_1ST) fprintf(fp, "ATTR_1ST"); + else if (flt->d_in_attr == ATTR_VALID) fprintf(fp, "ATTR_VALID"); + else if (flt->d_in_attr == ATTR_LAST) fprintf(fp, "ATTR_LAST"); + else if (flt->d_in_attr == ATTR_INVALID) fprintf(fp, "ATTR_INVALID"); + else fprintf(fp, "illegal attribute"); + fprintf(fp, "\tcnt %d, x %d, y %d\n", flt->d_in_cnt, flt->d_in_x, flt->d_in_y); + + fprintf(fp, "d_out %02x ", flt->d_out0); + if (flt->d_out_attr == ATTR_1ST) fprintf(fp, "ATTR_1ST"); + else if (flt->d_out_attr == ATTR_VALID) fprintf(fp, "ATTR_VALID"); + else if (flt->d_out_attr == ATTR_LAST) fprintf(fp, "ATTR_LAST"); + else if (flt->d_out_attr == ATTR_INVALID) fprintf(fp, "ATTR_INVALID"); + else fprintf(fp, "illegal attribute"); + fprintf(fp, "\tcnt %d, x %d, y %d\n", flt->d_out_cnt, flt->d_out_x, flt->d_out_y); + + if (flt->state == STATE_PROCESS) fprintf(fp, "state: STATE_PROCESS\n"); + else fprintf(fp, "state: STATE_FLUSH\n"); + + fprintf(fp, "\n"); + for (int y = 0; y < flt->kernel_size + 1; y++) { + for (int x = 0; x < flt->line_size; x++) { + fprintf(fp, "%02x ", *(flt->line_buf0 + (y * flt->line_size) + x) ); + } + fprintf(fp, "\n"); + } + + if (flt->is_3_planes != 0) { + fprintf(fp, "\n"); + for (int y = 0; y < flt->kernel_size + 1; y++) { + for (int x = 0; x < flt->line_size; x++) { + fprintf(fp, "%02x ", *(flt->line_buf1 + (y * flt->line_size) + x) ); + } + fprintf(fp, "\n"); + } + + fprintf(fp, "\n"); + for (int y = 0; y < flt->kernel_size + 1; y++) { + for (int x = 0; x < flt->line_size; x++) { + fprintf(fp, "%02x ", *(flt->line_buf1 + (y * flt->line_size) + x) ); + } + fprintf(fp, "\n"); + } + } + + fprintf(fp, "====================================================\n"); + fflush(fp); +} + + +// reset data structure for reuse +void reset_stream_filter(stream_filter *flt) +{ + if (flt == (stream_filter *)NULL) + return; + + flt->state = STATE_PROCESS; + + flt->d_in_cnt = 0; // total # of data + flt->d_in_x = 0; // linebuf pointer + flt->d_in_y = (flt->kernel_size - 1) / 2; // linebuf pointer + + flt->d_out_cnt = 0; // total # of data + flt->d_out_x = 0; // linebuf pointer + flt->d_out_y = (flt->kernel_size - 1) / 2; // linebuf pointer + + // zero clear buffer + if (flt->line_buf0 != (unsigned char *)NULL) { + for (int i = 0; i < flt->line_size * (flt->kernel_size + 1); i++) { + *(flt->line_buf0 + i) = 0; + } + } + + if (flt->line_buf1 != (unsigned char *)NULL) { + for (int i = 0; i < flt->line_size * (flt->kernel_size + 1); i++) { + *(flt->line_buf1 + i) = 0; + } + } + + if (flt->line_buf2 != (unsigned char *)NULL) { + for (int i = 0; i < flt->line_size * (flt->kernel_size + 1); i++) { + *(flt->line_buf2 + i) = 0; + } + } +} + + +// allocate and initialize data structure +stream_filter *create_stream_filter(char is_3_planes, int line_size, int kernel_size, kernel_func func, void *func_param) +{ + stream_filter *ret; + + // allocate memory + if ((ret = (stream_filter *)malloc(sizeof (stream_filter))) == (stream_filter *)NULL) + return ((stream_filter *)NULL); + + if ((ret->line_buf0 = (unsigned char *)malloc(sizeof (unsigned char) * line_size * (kernel_size + 1))) == (unsigned char *)NULL) { + free(ret); + return ((stream_filter *)NULL); + } + + if (is_3_planes != 0) { + if ((ret->line_buf1 = (unsigned char *)malloc(sizeof (unsigned char) * line_size * (kernel_size + 1))) == (unsigned char *)NULL) { + free(ret->line_buf0); + free(ret); + return ((stream_filter *)NULL); + } + + if ((ret->line_buf2 = (unsigned char *)malloc(sizeof (unsigned char) * line_size * (kernel_size + 1))) == (unsigned char *)NULL) { + free(ret->line_buf0); + free(ret->line_buf1); + free(ret); + return ((stream_filter *)NULL); + } + } + else { + ret->line_buf1 = (unsigned char *)NULL; + ret->line_buf2 = (unsigned char *)NULL; + } + + // init internal valiables + ret->is_3_planes = is_3_planes; + ret->line_size = line_size; + ret->kernel_size = kernel_size; + + reset_stream_filter(ret); + + // init kernel operation func + ret->func = func; + ret->func_param = func_param; + + return (ret); +} + + +// process 1 pixel; Set d_in & d_in_attr before calling. The result will be set to d_out & d_out_attr. +void apply_filter(stream_filter *flt) +{ + if (flt == (stream_filter *)NULL) + return; + + if ((flt->state == STATE_PROCESS && flt->d_in_attr != ATTR_INVALID) + || (flt->state == STATE_FLUSH && flt->d_in_attr == ATTR_INVALID)) { + ///////////////////////////////////////////// + // store d_in to linebuf + ///////////////////////////////////////////// + if (flt->d_in_attr == ATTR_INVALID) { + flt->d_in0 = 0; + flt->d_in1 = 0; + flt->d_in2 = 0; + } + + *(flt->line_buf0 + (flt->d_in_y * flt->line_size) + flt->d_in_x) = flt->d_in0; + if (flt->is_3_planes != 0) { + *(flt->line_buf1 + (flt->d_in_y * flt->line_size) + flt->d_in_x) = flt->d_in1; + *(flt->line_buf2 + (flt->d_in_y * flt->line_size) + flt->d_in_x) = flt->d_in2; + } + + // update input counter + if (flt->state == STATE_PROCESS && flt->d_in_attr != ATTR_LAST) + (flt->d_in_cnt)++; + + // update input pointer + (flt->d_in_x)++; + if (flt->d_in_x >= flt->line_size) { + flt->d_in_x = 0; + (flt->d_in_y)++; + if (flt->d_in_y >= flt->kernel_size + 1) { + flt->d_in_y = 0; + } + } + + ///////////////////////////////////////////// + // calc output (NOTE: do after updating input counter) + ///////////////////////////////////////////// + if ((flt->state == STATE_PROCESS && flt->d_in_cnt > flt->line_size * (flt->kernel_size + 1) / 2) + || (flt->state == STATE_FLUSH && flt->d_in_cnt >= flt->d_out_cnt)) { // normal operation + + // generate output (call kernel_operation func) + flt->d_out0 = (flt->func)(flt->line_buf0, flt->d_out_x, flt->d_out_y, flt->line_size, flt->kernel_size, flt->func_param); + if (flt->is_3_planes != 0) { + flt->d_out1 = (flt->func)(flt->line_buf1, flt->d_out_x, flt->d_out_y, flt->line_size, flt->kernel_size, flt->func_param); + flt->d_out2 = (flt->func)(flt->line_buf2, flt->d_out_x, flt->d_out_y, flt->line_size, flt->kernel_size, flt->func_param); + } + + if (flt->d_out_cnt == 0) + flt->d_out_attr = ATTR_1ST; + else if (flt->d_out_cnt == flt->d_in_cnt) + flt->d_out_attr = ATTR_LAST; + else + flt->d_out_attr = ATTR_VALID; + + // update output counter + (flt->d_out_cnt)++; + + // update output pointer + (flt->d_out_x)++; + if (flt->d_out_x >= flt->line_size) { + flt->d_out_x = 0; + (flt->d_out_y)++; + if (flt->d_out_y >= flt->kernel_size + 1) { + flt->d_out_y = 0; + } + } + } + else { // initial operation (still filling buffer) or completion of data output + // no output + flt->d_out0 = 0; + flt->d_out1 = 0; + flt->d_out2 = 0; + flt->d_out_attr = ATTR_INVALID; + } + + ///////////////////////////////////////////// + // change state + ///////////////////////////////////////////// + if (flt->state == STATE_PROCESS && flt->d_in_attr == ATTR_LAST) { + flt->state = STATE_FLUSH; + } + } +} + + +// release data structure +void release_stream_filter(stream_filter *flt) +{ + if (flt == (stream_filter *)NULL) + return; + if (flt->line_buf0 != (unsigned char *)NULL) + free(flt->line_buf0); + free(flt); +} + + +///////////////////////////////////////////////////////////////////////////////// + + +//void cam_cap(void); +int cam_cap(char, stream_filter *); + + +int memfree(void) +{ + int ret = 1; + while (1) { + char *p = (char *)malloc(ret); + if (p == NULL) + break; + free(p); + ret++; + } + return (ret - 1); +} + + +int main() +{ + led1 = 0; + led2 = 0; + led3 = 0; + led4 = 0; + + sv0.period_us(20000); // 20ms + sv0.pulsewidth_us(5000); // 5ms + + sv1.period_us(20000); // 20ms + sv1.pulsewidth_us(10000); // 10ms + + sv2.period_us(20000); // 20ms + sv2.pulsewidth_us(15000); // 15ms + + //////////////////////////////////////////////////////////////////////////// + camera.WriteReg(0x12, 0x80); // com7; reset + wait_ms(200); + + camera.InitDefaultReg(); + + // negate vsync + camera.WriteReg(0x15, 0x02); // com10; negative vsync + +#ifdef QQVGA + camera.InitQQVGA(); +#endif +#ifdef QVGA + camera.InitQVGA(); +#endif +#ifdef VGA34 + camera.InitVGA_3_4(); +#endif + + // data format + camera.WriteReg(0x12, 0x04 + 0); // com7 RGB (bit1...test pattern) + camera.WriteReg(0x40, 0xD0); // com15 RGB565 + camera.WriteReg(0x8c, 0x00); // RGB444 + + // turn off AWB + unsigned char tmp = camera.ReadReg(0x13); // COM8 + camera.WriteReg(0x13, tmp & 0xFD); // COM8[1] = 0 + camera.WriteReg(0x02, 0x48); // R gain + camera.WriteReg(0x6A, 0x40); // G gain + camera.WriteReg(0x01, 0x60); // B gain + + wait_ms(300); + + // discard some first frames + for (int i = 0; i < 10; i++) { + camera.CaptureNext(); // sample start! + while(camera.CaptureDone() == false) + ; + } + + ////////////////////////////////////////////////// + int blur_kernel_size = 7; + + float blur_matrix[] = { + // Average filter + // Change here in order to use a different filter + 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, + 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, + 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, + 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, + 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, + 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, + 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f + }; + + int prev_mem = memfree(); + + stream_filter *average_flt; + average_flt = create_stream_filter(0, SIZEX, blur_kernel_size, comb_filter, (void *)blur_matrix); // 0: 1 plane + +// tmr.start(); // timer +// cam_cap(0, average_flt); +// tmr.stop(); // timer + + int cur_mem = memfree(); + +// lcd.locate(0, 0); +// lcd.printf("%dms", tmr.read_ms()); + +// lcd.locate(0, 1); +// lcd.printf("m %d, %d", prev_mem, cur_mem); + +//char shot_flag = 0; + + ////////////////////////////////////////////////// + while (1) { +// int rgain, ggain, bgain; + int skin_pixel_num; + + led1 = 1; + reset_stream_filter(average_flt); + + tmr.reset(); + tmr.start(); + skin_pixel_num = cam_cap(0, average_flt); + tmr.stop(); + + if (skin_pixel_num >= SHUTTER_THRESHOLD) { // threshold + cam_cap(1, average_flt); // shot + + lcd.locate(0, 0); + lcd.printf("CAPTURED "); + lcd.locate(0, 1); + lcd.printf("val %d ", skin_pixel_num); + + while (1) { + wait(1); + } + } +// cur_mem = memfree(); + +// rgain = camera.ReadReg(0x02); +// ggain = camera.ReadReg(0x6A); +// bgain = camera.ReadReg(0x01); + + lcd.locate(0, 0); + lcd.printf("%dms ", tmr.read_ms()); + lcd.locate(0, 1); + lcd.printf("val %d ", skin_pixel_num); +// lcd.printf("%dms, M%d ", tmr.read_ms(), cur_mem); +// lcd.printf("R%02x G%02x B%02x", rgain, ggain, bgain); + +// wait_ms(100); + } + +} + + +void write_bmp_header(FILE *fp_bmp) +{ + ///////////////////////// + // file header + ///////////////////////// + fprintf(fp_bmp, "BM"); + int val = 14 + 40 + SIZEX * SIZEY * 3; // file size + fprintf(fp_bmp, "%c%c%c%c", val % 0x100, val / 0x100, val / 0x10000, val / 0x1000000); + fprintf(fp_bmp, "%c%c%c%c%c%c%c%c", 0, 0, 0, 0, 0x36, 0, 0, 0); + + ///////////////////////// + // information header + ///////////////////////// + fprintf(fp_bmp, "%c%c%c%c", 0x28, 0, 0, 0); // header size + fprintf(fp_bmp, "%c%c%c%c", SIZEX % 0x100, SIZEX / 0x100, SIZEX / 0x10000, SIZEX / 0x1000000); + fprintf(fp_bmp, "%c%c%c%c", SIZEY % 0x100, SIZEY / 0x100, SIZEY / 0x10000, SIZEY / 0x1000000); + fprintf(fp_bmp, "%c%c", 1, 0); // # of plane + fprintf(fp_bmp, "%c%c", 24, 0); // bit count + fprintf(fp_bmp, "%c%c%c%c", 0, 0, 0, 0); // compression + val = SIZEX * SIZEY * 3; // data size + fprintf(fp_bmp, "%c%c%c%c", val % 0x100, val / 0x100, val / 0x10000, val / 0x1000000); + fprintf(fp_bmp, "%c%c%c%c", 0, 0, 0, 0); + fprintf(fp_bmp, "%c%c%c%c", 0, 0, 0, 0); + fprintf(fp_bmp, "%c%c%c%c", 0, 0, 0, 0); + fprintf(fp_bmp, "%c%c%c%c", 0, 0, 0, 0); +} + + +void write_bmp_data(FILE *fp_bmp, unsigned char b, unsigned char g, unsigned char r) +{ + fprintf(fp_bmp, "%c%c%c", b, g, r); +} + + +//void cam_cap(Arguments* input, Reply* output) +int cam_cap(char file_flag, stream_filter *average_flt) +{ + FILE *fp_bmp; + unsigned int d1, d2; + unsigned char sort[3]; + + int dx = 0; + int dy = 0; + + unsigned int skin_pixel_num = 0; + unsigned int skin_x = 0; + unsigned int skin_y = 0; + + + //////////////////////////////////////////////////////////////////// + led2 = 0; + led3 = 0; + led4 = 0; + + if (file_flag != 0) { + fp_bmp = fopen("/webfs/cam.bmp", "wb"); + write_bmp_header(fp_bmp); + } + + camera.CaptureNext(); // sample start! + + while(camera.CaptureDone() == false) + ; + + camera.ReadStart(); // reset pointer + + led2 = 1; + + ///////////////////////////////////////////// + // main loop + ///////////////////////////////////////////// + for (int y = 0; y < SIZEY; y++) { + for (int x = 0; x < SIZEX; x++) { + d1 = camera.ReadOneByte() ; // upper nibble is XXX , lower nibble is B + d2 = camera.ReadOneByte() ; // upper nibble is G , lower nibble is R + + ///////////////////////////////////////////// + // RGB565 + ///////////////////////////////////////////// + sort[0] = ((d1 & 0xF8) >> 3) << 3; // R + sort[1] = ( ((d1 & 0x07) << 3) + ((d2 & 0xE0) >> 5) ) << 2; // G + sort[2] = (d2 & 0x1F) << 3; // B + + ////////////////////////////////////////////////////////////////////////// + // 1. get input + ////////////////////////////////////////////////////////////////////////// + unsigned char b0 = sort[2]; + unsigned char g0 = sort[1]; + unsigned char r0 = sort[0]; + + if (file_flag != 0) { + write_bmp_data(fp_bmp, sort[2], sort[1], sort[0]); // B,G,R + } + else { + ////////////////////////////////////////////////////////////////////////// + // 2. RGB2HSV + ////////////////////////////////////////////////////////////////////////// + unsigned char h1, s1, v1; + rgb2hsv(r0, g0, b0, &h1, &s1, &v1); + + ////////////////////////////////////////////////////////////////////////// + // 3. judge + ////////////////////////////////////////////////////////////////////////// + unsigned char val2 = judge_skin_color(h1, s1, v1); + + ////////////////////////////////////////////////////////////////////////// + // 4. blur (average) + ////////////////////////////////////////////////////////////////////////// + average_flt->d_in0 = val2; // (1 plane mode; use d_in0 only) + + if (y == 0 && x == 0) + average_flt->d_in_attr = ATTR_1ST; + else if (y == SIZEY - 1 && x == SIZEX - 1) + average_flt->d_in_attr = ATTR_LAST; + else + average_flt->d_in_attr = ATTR_VALID; + + // apply filter + apply_filter(average_flt); + + ////////////////////////////////////////////////////////////////////////// + // 5. limit + ////////////////////////////////////////////////////////////////////////// + unsigned char val3 = average_flt->d_out0; + + if (val3 < 220) + val3 = 0; + else { + skin_pixel_num++; + skin_x += dx; + skin_y += dy; + } + + ////////////////////////////////////////////////////////////////////////// + // 6. put output + ////////////////////////////////////////////////////////////////////////// + if (average_flt->d_out_attr != ATTR_INVALID) { + sort[2] = val3 & b0; + sort[1] = val3 & g0; + sort[0] = val3 & r0; + + dx++; + if (dx == SIZEX) { + dx = 0; + dy++; + } + } + } // file_flag + + } + } + + led3 = 1; + + if (file_flag != 0) { + ///////////////////////////////////////////// + // flush filter + ///////////////////////////////////////////// + average_flt->d_in_attr = ATTR_INVALID; + + while (1) { + apply_filter(average_flt); + + if (average_flt->d_out_attr == ATTR_INVALID) + break; + + ////////////////////////////////////////////////////////////////////////// + // 5. limit + ////////////////////////////////////////////////////////////////////////// + unsigned char val3 = average_flt->d_out0; + + if (val3 < 220) + val3 = 0; + else { + skin_pixel_num++; + skin_x += dx; + skin_y += dy; + } + + ////////////////////////////////////////////////////////////////////////// + // 6. put output + ////////////////////////////////////////////////////////////////////////// + sort[2] = val3; + sort[1] = val3; + sort[0] = val3; + + dx++; + if (dx == SIZEX) { + dx = 0; + dy++; + } + } + } + + led4 = 1; + + ///////////////////////////////////////////// + // end + ///////////////////////////////////////////// + camera.ReadStop(); + +// release_stream_filter(average_flt); + + if (skin_pixel_num != 0) { + skin_x /= skin_pixel_num; + skin_y /= skin_pixel_num; + } + else { + skin_x = SIZEX / 2; + skin_y = SIZEY / 2; + } + + if (file_flag != 0) { + fclose(fp_bmp); + } + +// led2 = 0; +// led3 = 0; +// led4 = 0; + + return (skin_pixel_num); +} + +// end of file \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Wed Sep 24 20:48:23 2014 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/8a40adfe8776 \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ov7670.h Wed Sep 24 20:48:23 2014 +0000 @@ -0,0 +1,583 @@ +// This code was written by Mr.Sadaei Osakabe. +// Original code is located at +// https://mbed.org/users/diasea/code/OV7670_with_AL422B_Color_Size_test/ + +#include "mbed.h" +#include "ov7670reg.h" + +#define OV7670_WRITE (0x42) +#define OV7670_READ (0x43) +#define OV7670_WRITEWAIT (20) +#define OV7670_NOACK (0) +#define OV7670_REGMAX (201) +#define OV7670_I2CFREQ (50000) + +// +// OV7670 + FIFO AL422B camera board test +// +class OV7670 +{ +public: + I2C camera; + InterruptIn vsync,href; + DigitalOut wen; + BusIn data; + DigitalOut rrst,oe,rclk; + volatile int LineCounter; + volatile int LastLines; + volatile bool CaptureReq; + volatile bool Busy; + volatile bool Done; + + OV7670( + PinName sda,// Camera I2C port + PinName scl,// Camera I2C port + PinName vs, // VSYNC + PinName hr, // HREF + PinName we, // WEN + PinName d7, // D7 + PinName d6, // D6 + PinName d5, // D5 + PinName d4, // D4 + PinName d3, // D3 + PinName d2, // D2 + PinName d1, // D1 + PinName d0, // D0 + PinName rt, // /RRST + PinName o, // /OE + PinName rc // RCLK + ) : camera(sda,scl),vsync(vs),href(hr),wen(we),data(d0,d1,d2,d3,d4,d5,d6,d7),rrst(rt),oe(o),rclk(rc) + { + camera.stop(); + camera.frequency(OV7670_I2CFREQ); + vsync.fall(this,&OV7670::VsyncHandler); + href.rise(this,&OV7670::HrefHandler); + CaptureReq = false; + Busy = false; + Done = false; + LineCounter = 0; + rrst = 1; + oe = 1; + rclk = 1; + wen = 0; + } + + // capture request + void CaptureNext(void) + { + CaptureReq = true; + Busy = true; + } + + // capture done? (with clear) + bool CaptureDone(void) + { + bool result; + if (Busy) { + result = false; + } else { + result = Done; + Done = false; + } + return result; + } + + // write to camera + void WriteReg(int addr,int data) + { + // WRITE 0x42,ADDR,DATA + camera.start(); + camera.write(OV7670_WRITE); + wait_us(OV7670_WRITEWAIT); + camera.write(addr); + wait_us(OV7670_WRITEWAIT); + camera.write(data); + camera.stop(); + } + + // read from camera + int ReadReg(int addr) + { + int data; + + // WRITE 0x42,ADDR + camera.start(); + camera.write(OV7670_WRITE); + wait_us(OV7670_WRITEWAIT); + camera.write(addr); + camera.stop(); + wait_us(OV7670_WRITEWAIT); + + // WRITE 0x43,READ + camera.start(); + camera.write(OV7670_READ); + wait_us(OV7670_WRITEWAIT); + data = camera.read(OV7670_NOACK); + camera.stop(); + + return data; + } + + // print register + void PrintRegister(void) { + printf("AD : +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F"); + for (int i=0;i<OV7670_REGMAX;i++) { + int data; + data = ReadReg(i); // READ REG + if ((i & 0x0F) == 0) { + printf("\r\n%02X : ",i); + } + printf("%02X ",data); + } + printf("\r\n"); + } + + void Reset(void) { + WriteReg(REG_COM7,COM7_RESET); // RESET CAMERA + wait_ms(200); + } + + void InitForFIFOWriteReset(void) { + WriteReg(REG_COM10, COM10_VS_NEG); + } + + void InitSetColorbar(void) { + int reg_com7 = ReadReg(REG_COM7); + // color bar + WriteReg(REG_COM17, reg_com7|COM17_CBAR); + } + + void InitDefaultReg(void) { + // Gamma curve values + WriteReg(0x7a, 0x20); + WriteReg(0x7b, 0x10); + WriteReg(0x7c, 0x1e); + WriteReg(0x7d, 0x35); + WriteReg(0x7e, 0x5a); + WriteReg(0x7f, 0x69); + WriteReg(0x80, 0x76); + WriteReg(0x81, 0x80); + WriteReg(0x82, 0x88); + WriteReg(0x83, 0x8f); + WriteReg(0x84, 0x96); + WriteReg(0x85, 0xa3); + WriteReg(0x86, 0xaf); + WriteReg(0x87, 0xc4); + WriteReg(0x88, 0xd7); + WriteReg(0x89, 0xe8); + + // AGC and AEC parameters. Note we start by disabling those features, + //then turn them only after tweaking the values. + WriteReg(REG_COM8, COM8_FASTAEC | COM8_AECSTEP | COM8_BFILT); + WriteReg(REG_GAIN, 0); + WriteReg(REG_AECH, 0); + WriteReg(REG_COM4, 0x40); + // magic reserved bit + WriteReg(REG_COM9, 0x18); + // 4x gain + magic rsvd bit + WriteReg(REG_BD50MAX, 0x05); + WriteReg(REG_BD60MAX, 0x07); + WriteReg(REG_AEW, 0x95); + WriteReg(REG_AEB, 0x33); + WriteReg(REG_VPT, 0xe3); + WriteReg(REG_HAECC1, 0x78); + WriteReg(REG_HAECC2, 0x68); + WriteReg(0xa1, 0x03); + // magic + WriteReg(REG_HAECC3, 0xd8); + WriteReg(REG_HAECC4, 0xd8); + WriteReg(REG_HAECC5, 0xf0); + WriteReg(REG_HAECC6, 0x90); + WriteReg(REG_HAECC7, 0x94); + WriteReg(REG_COM8, COM8_FASTAEC|COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC); + + // Almost all of these are magic "reserved" values. + WriteReg(REG_COM5, 0x61); + WriteReg(REG_COM6, 0x4b); + WriteReg(0x16, 0x02); + WriteReg(REG_MVFP, 0x07); + WriteReg(0x21, 0x02); + WriteReg(0x22, 0x91); + WriteReg(0x29, 0x07); + WriteReg(0x33, 0x0b); + WriteReg(0x35, 0x0b); + WriteReg(0x37, 0x1d); + WriteReg(0x38, 0x71); + WriteReg(0x39, 0x2a); + WriteReg(REG_COM12, 0x78); + WriteReg(0x4d, 0x40); + WriteReg(0x4e, 0x20); + WriteReg(REG_GFIX, 0); + WriteReg(0x6b, 0x0a); + WriteReg(0x74, 0x10); + WriteReg(0x8d, 0x4f); + WriteReg(0x8e, 0); + WriteReg(0x8f, 0); + WriteReg(0x90, 0); + WriteReg(0x91, 0); + WriteReg(0x96, 0); + WriteReg(0x9a, 0); + WriteReg(0xb0, 0x84); + WriteReg(0xb1, 0x0c); + WriteReg(0xb2, 0x0e); + WriteReg(0xb3, 0x82); + WriteReg(0xb8, 0x0a); + + // More reserved magic, some of which tweaks white balance + WriteReg(0x43, 0x0a); + WriteReg(0x44, 0xf0); + WriteReg(0x45, 0x34); + WriteReg(0x46, 0x58); + WriteReg(0x47, 0x28); + WriteReg(0x48, 0x3a); + WriteReg(0x59, 0x88); + WriteReg(0x5a, 0x88); + WriteReg(0x5b, 0x44); + WriteReg(0x5c, 0x67); + WriteReg(0x5d, 0x49); + WriteReg(0x5e, 0x0e); + WriteReg(0x6c, 0x0a); + WriteReg(0x6d, 0x55); + WriteReg(0x6e, 0x11); + WriteReg(0x6f, 0x9f); + // "9e for advance AWB" + WriteReg(0x6a, 0x40); + WriteReg(REG_BLUE, 0x40); + WriteReg(REG_RED, 0x60); + WriteReg(REG_COM8, COM8_FASTAEC|COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC|COM8_AWB); + + // Matrix coefficients + WriteReg(0x4f, 0x80); + WriteReg(0x50, 0x80); + WriteReg(0x51, 0); + WriteReg(0x52, 0x22); + WriteReg(0x53, 0x5e); + WriteReg(0x54, 0x80); + WriteReg(0x58, 0x9e); + + WriteReg(REG_COM16, COM16_AWBGAIN); + WriteReg(REG_EDGE, 0); + WriteReg(0x75, 0x05); + WriteReg(0x76, 0xe1); + WriteReg(0x4c, 0); + WriteReg(0x77, 0x01); + WriteReg(0x4b, 0x09); + WriteReg(0xc9, 0x60); + WriteReg(REG_COM16, 0x38); + WriteReg(0x56, 0x40); + + WriteReg(0x34, 0x11); + WriteReg(REG_COM11, COM11_EXP|COM11_HZAUTO_ON); + WriteReg(0xa4, 0x88); + WriteReg(0x96, 0); + WriteReg(0x97, 0x30); + WriteReg(0x98, 0x20); + WriteReg(0x99, 0x30); + WriteReg(0x9a, 0x84); + WriteReg(0x9b, 0x29); + WriteReg(0x9c, 0x03); + WriteReg(0x9d, 0x4c); + WriteReg(0x9e, 0x3f); + WriteReg(0x78, 0x04); + + // Extra-weird stuff. Some sort of multiplexor register + WriteReg(0x79, 0x01); + WriteReg(0xc8, 0xf0); + WriteReg(0x79, 0x0f); + WriteReg(0xc8, 0x00); + WriteReg(0x79, 0x10); + WriteReg(0xc8, 0x7e); + WriteReg(0x79, 0x0a); + WriteReg(0xc8, 0x80); + WriteReg(0x79, 0x0b); + WriteReg(0xc8, 0x01); + WriteReg(0x79, 0x0c); + WriteReg(0xc8, 0x0f); + WriteReg(0x79, 0x0d); + WriteReg(0xc8, 0x20); + WriteReg(0x79, 0x09); + WriteReg(0xc8, 0x80); + WriteReg(0x79, 0x02); + WriteReg(0xc8, 0xc0); + WriteReg(0x79, 0x03); + WriteReg(0xc8, 0x40); + WriteReg(0x79, 0x05); + WriteReg(0xc8, 0x30); + WriteReg(0x79, 0x26); + } + + void InitRGB444(void){ + int reg_com7 = ReadReg(REG_COM7); + + WriteReg(REG_COM7, reg_com7|COM7_RGB); + WriteReg(REG_RGB444, RGB444_ENABLE|RGB444_XBGR); + WriteReg(REG_COM15, COM15_R01FE|COM15_RGB444); + + WriteReg(REG_COM1, 0x40); // Magic reserved bit + WriteReg(REG_COM9, 0x38); // 16x gain ceiling; 0x8 is reserved bit + WriteReg(0x4f, 0xb3); // "matrix coefficient 1" + WriteReg(0x50, 0xb3); // "matrix coefficient 2" + WriteReg(0x51, 0x00); // vb + WriteReg(0x52, 0x3d); // "matrix coefficient 4" + WriteReg(0x53, 0xa7); // "matrix coefficient 5" + WriteReg(0x54, 0xe4); // "matrix coefficient 6" + WriteReg(REG_COM13, COM13_GAMMA|COM13_UVSAT|0x2); // Magic rsvd bit + + WriteReg(REG_TSLB, 0x04); + } + + void InitRGB555(void){ + int reg_com7 = ReadReg(REG_COM7); + + WriteReg(REG_COM7, reg_com7|COM7_RGB); + WriteReg(REG_RGB444, RGB444_DISABLE); + WriteReg(REG_COM15, COM15_RGB555|COM15_R00FF); + + WriteReg(REG_TSLB, 0x04); + + WriteReg(REG_COM1, 0x00); + WriteReg(REG_COM9, 0x38); // 16x gain ceiling; 0x8 is reserved bit + WriteReg(0x4f, 0xb3); // "matrix coefficient 1" + WriteReg(0x50, 0xb3); // "matrix coefficient 2" + WriteReg(0x51, 0x00); // vb + WriteReg(0x52, 0x3d); // "matrix coefficient 4" + WriteReg(0x53, 0xa7); // "matrix coefficient 5" + WriteReg(0x54, 0xe4); // "matrix coefficient 6" + WriteReg(REG_COM13, COM13_GAMMA|COM13_UVSAT); + } + + void InitRGB565(void){ + int reg_com7 = ReadReg(REG_COM7); + + WriteReg(REG_COM7, reg_com7|COM7_RGB); + WriteReg(REG_RGB444, RGB444_DISABLE); + WriteReg(REG_COM15, COM15_R00FF|COM15_RGB565); + + WriteReg(REG_TSLB, 0x04); + + WriteReg(REG_COM1, 0x00); + WriteReg(REG_COM9, 0x38); // 16x gain ceiling; 0x8 is reserved bit + WriteReg(0x4f, 0xb3); // "matrix coefficient 1" + WriteReg(0x50, 0xb3); // "matrix coefficient 2" + WriteReg(0x51, 0x00); // vb + WriteReg(0x52, 0x3d); // "matrix coefficient 4" + WriteReg(0x53, 0xa7); // "matrix coefficient 5" + WriteReg(0x54, 0xe4); // "matrix coefficient 6" + WriteReg(REG_COM13, COM13_GAMMA|COM13_UVSAT); + } + + void InitYUV(void){ + int reg_com7 = ReadReg(REG_COM7); + + WriteReg(REG_COM7, reg_com7|COM7_YUV); + WriteReg(REG_RGB444, RGB444_DISABLE); + WriteReg(REG_COM15, COM15_R00FF); + + WriteReg(REG_TSLB, 0x04); +// WriteReg(REG_TSLB, 0x14); +// WriteReg(REG_MANU, 0x00); +// WriteReg(REG_MANV, 0x00); + + WriteReg(REG_COM1, 0x00); + WriteReg(REG_COM9, 0x18); // 4x gain ceiling; 0x8 is reserved bit + WriteReg(0x4f, 0x80); // "matrix coefficient 1" + WriteReg(0x50, 0x80); // "matrix coefficient 2" + WriteReg(0x51, 0x00); // vb + WriteReg(0x52, 0x22); // "matrix coefficient 4" + WriteReg(0x53, 0x5e); // "matrix coefficient 5" + WriteReg(0x54, 0x80); // "matrix coefficient 6" + WriteReg(REG_COM13, COM13_GAMMA|COM13_UVSAT|COM13_UVSWAP); + } + + void InitBayerRGB(void){ + int reg_com7 = ReadReg(REG_COM7); + + // odd line BGBG... even line GRGR... + WriteReg(REG_COM7, reg_com7|COM7_BAYER); + // odd line GBGB... even line RGRG... + //WriteReg(REG_COM7, reg_com7|COM7_PBAYER); + + WriteReg(REG_RGB444, RGB444_DISABLE); + WriteReg(REG_COM15, COM15_R00FF); + + WriteReg(REG_COM13, 0x08); /* No gamma, magic rsvd bit */ + WriteReg(REG_COM16, 0x3d); /* Edge enhancement, denoise */ + WriteReg(REG_REG76, 0xe1); /* Pix correction, magic rsvd */ + + WriteReg(REG_TSLB, 0x04); + } + + void InitVGA(void) { + // VGA + int reg_com7 = ReadReg(REG_COM7); + + WriteReg(REG_COM7,reg_com7|COM7_VGA); + + WriteReg(REG_HSTART,HSTART_VGA); + WriteReg(REG_HSTOP,HSTOP_VGA); + WriteReg(REG_HREF,HREF_VGA); + WriteReg(REG_VSTART,VSTART_VGA); + WriteReg(REG_VSTOP,VSTOP_VGA); + WriteReg(REG_VREF,VREF_VGA); + WriteReg(REG_COM3, COM3_VGA); + WriteReg(REG_COM14, COM14_VGA); + WriteReg(REG_SCALING_XSC, SCALING_XSC_VGA); + WriteReg(REG_SCALING_YSC, SCALING_YSC_VGA); + WriteReg(REG_SCALING_DCWCTR, SCALING_DCWCTR_VGA); + WriteReg(REG_SCALING_PCLK_DIV, SCALING_PCLK_DIV_VGA); + WriteReg(REG_SCALING_PCLK_DELAY, SCALING_PCLK_DELAY_VGA); + } + + void InitFIFO_2bytes_color_nealy_limit_size(void) { + // nealy FIFO limit 544x360 + int reg_com7 = ReadReg(REG_COM7); + + WriteReg(REG_COM7,reg_com7|COM7_VGA); + + WriteReg(REG_HSTART,HSTART_VGA); + WriteReg(REG_HSTOP,HSTOP_VGA); + WriteReg(REG_HREF,HREF_VGA); + WriteReg(REG_VSTART,VSTART_VGA); + WriteReg(REG_VSTOP,VSTOP_VGA); + WriteReg(REG_VREF,VREF_VGA); + WriteReg(REG_COM3, COM3_VGA); + WriteReg(REG_COM14, COM14_VGA); + WriteReg(REG_SCALING_XSC, SCALING_XSC_VGA); + WriteReg(REG_SCALING_YSC, SCALING_YSC_VGA); + WriteReg(REG_SCALING_DCWCTR, SCALING_DCWCTR_VGA); + WriteReg(REG_SCALING_PCLK_DIV, SCALING_PCLK_DIV_VGA); + WriteReg(REG_SCALING_PCLK_DELAY, SCALING_PCLK_DELAY_VGA); + + WriteReg(REG_HSTART, 0x17); + WriteReg(REG_HSTOP, 0x5b); + WriteReg(REG_VSTART, 0x12); + WriteReg(REG_VSTOP, 0x6c); + } + + void InitVGA_3_4(void) { + // VGA 3/4 -> 480x360 + int reg_com7 = ReadReg(REG_COM7); + + WriteReg(REG_COM7,reg_com7|COM7_VGA); + + WriteReg(REG_HSTART,HSTART_VGA); + WriteReg(REG_HSTOP,HSTOP_VGA); + WriteReg(REG_HREF,HREF_VGA); + WriteReg(REG_VSTART,VSTART_VGA); + WriteReg(REG_VSTOP,VSTOP_VGA); + WriteReg(REG_VREF,VREF_VGA); + WriteReg(REG_COM3, COM3_VGA); + WriteReg(REG_COM14, COM14_VGA); + WriteReg(REG_SCALING_XSC, SCALING_XSC_VGA); + WriteReg(REG_SCALING_YSC, SCALING_YSC_VGA); + WriteReg(REG_SCALING_DCWCTR, SCALING_DCWCTR_VGA); + WriteReg(REG_SCALING_PCLK_DIV, SCALING_PCLK_DIV_VGA); + WriteReg(REG_SCALING_PCLK_DELAY, SCALING_PCLK_DELAY_VGA); + + WriteReg(REG_HSTART, 0x1b); + WriteReg(REG_HSTOP, 0x57); + WriteReg(REG_VSTART, 0x12); + WriteReg(REG_VSTOP, 0x6c); + } + + void InitQVGA(void) { + // QQVGA + int reg_com7 = ReadReg(REG_COM7); + + WriteReg(REG_COM7,reg_com7|COM7_QVGA); + + WriteReg(REG_HSTART,HSTART_QVGA); + WriteReg(REG_HSTOP,HSTOP_QVGA); + WriteReg(REG_HREF,HREF_QVGA); + WriteReg(REG_VSTART,VSTART_QVGA); + WriteReg(REG_VSTOP,VSTOP_QVGA); + WriteReg(REG_VREF,VREF_QVGA); + WriteReg(REG_COM3, COM3_QVGA); + WriteReg(REG_COM14, COM14_QVGA); + WriteReg(REG_SCALING_XSC, SCALING_XSC_QVGA); + WriteReg(REG_SCALING_YSC, SCALING_YSC_QVGA); + WriteReg(REG_SCALING_DCWCTR, SCALING_DCWCTR_QVGA); + WriteReg(REG_SCALING_PCLK_DIV, SCALING_PCLK_DIV_QVGA); + WriteReg(REG_SCALING_PCLK_DELAY, SCALING_PCLK_DELAY_QVGA); + } + + void InitQQVGA(void) { + // QQVGA + int reg_com7 = ReadReg(REG_COM7); + + WriteReg(REG_COM7,reg_com7|COM7_QQVGA); + + WriteReg(REG_HSTART,HSTART_QQVGA); + WriteReg(REG_HSTOP,HSTOP_QQVGA); + WriteReg(REG_HREF,HREF_QQVGA); + WriteReg(REG_VSTART,VSTART_QQVGA); + WriteReg(REG_VSTOP,VSTOP_QQVGA); + WriteReg(REG_VREF,VREF_QQVGA); + WriteReg(REG_COM3, COM3_QQVGA); + WriteReg(REG_COM14, COM14_QQVGA); + WriteReg(REG_SCALING_XSC, SCALING_XSC_QQVGA); + WriteReg(REG_SCALING_YSC, SCALING_YSC_QQVGA); + WriteReg(REG_SCALING_DCWCTR, SCALING_DCWCTR_QQVGA); + WriteReg(REG_SCALING_PCLK_DIV, SCALING_PCLK_DIV_QQVGA); + WriteReg(REG_SCALING_PCLK_DELAY, SCALING_PCLK_DELAY_QQVGA); + } + + // vsync handler + void VsyncHandler(void) + { + // Capture Enable + if (CaptureReq) { + wen = 1; + Done = false; + CaptureReq = false; + } else { + wen = 0; + if (Busy) { + Busy = false; + Done = true; + } + } + + // Hline Counter + LastLines = LineCounter; + LineCounter = 0; + } + + // href handler + void HrefHandler(void) + { + LineCounter++; + } + + // Data Read + int ReadOneByte(void) + { + int result; + rclk = 1; +// wait_us(1); + result = data; + rclk = 0; + return result; + } + + // Data Start + void ReadStart(void) + { + rrst = 0; + oe = 0; + wait_us(1); + rclk = 0; + wait_us(1); + rclk = 1; + wait_us(1); + rrst = 1; + } + + // Data Stop + void ReadStop(void) + { + oe = 1; + ReadOneByte(); + rclk = 1; + } +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ov7670reg.h Wed Sep 24 20:48:23 2014 +0000 @@ -0,0 +1,259 @@ +// This code was written by Mr.Sadaei Osakabe. +// Original code is located at +// https://mbed.org/users/diasea/code/OV7670_with_AL422B_Color_Size_test/ + +// size register +#define REG_COM7 0x12 /* Control 7 */ +#define REG_HSTART 0x17 /* Horiz start high bits */ +#define REG_HSTOP 0x18 /* Horiz stop high bits */ +#define REG_HREF 0x32 /* HREF pieces */ +#define REG_VSTART 0x19 /* Vert start high bits */ +#define REG_VSTOP 0x1a /* Vert stop high bits */ +#define REG_VREF 0x03 /* Pieces of GAIN, VSTART, VSTOP */ +#define REG_COM3 0x0c /* Control 3 */ +#define REG_COM14 0x3e /* Control 14 */ +#define REG_SCALING_XSC 0x70 +#define REG_SCALING_YSC 0x71 +#define REG_SCALING_DCWCTR 0x72 +#define REG_SCALING_PCLK_DIV 0x73 +#define REG_SCALING_PCLK_DELAY 0xa2 + +// VGA setting +#define COM7_VGA 0x00 +#define HSTART_VGA 0x13 +#define HSTOP_VGA 0x01 +#define HREF_VGA 0x36 //0xb6 0x36 +#define VSTART_VGA 0x02 +#define VSTOP_VGA 0x7a +#define VREF_VGA 0x0a +#define COM3_VGA 0x00 +#define COM14_VGA 0x00 +#define SCALING_XSC_VGA 0x3a +#define SCALING_YSC_VGA 0x35 +#define SCALING_DCWCTR_VGA 0x11 +#define SCALING_PCLK_DIV_VGA 0xf0 +#define SCALING_PCLK_DELAY_VGA 0x02 + +// QVGA setting +#define COM7_QVGA 0x00 +#define HSTART_QVGA 0x16 +#define HSTOP_QVGA 0x04 +#define HREF_QVGA 0x00 +#define VSTART_QVGA 0x02 +#define VSTOP_QVGA 0x7a +#define VREF_QVGA 0x0a +#define COM3_QVGA 0x04 +#define COM14_QVGA 0x19 +#define SCALING_XSC_QVGA 0x3a +#define SCALING_YSC_QVGA 0x35 +#define SCALING_DCWCTR_QVGA 0x11 +#define SCALING_PCLK_DIV_QVGA 0xf1 +#define SCALING_PCLK_DELAY_QVGA 0x02 + +// QQVGA setting +#define COM7_QQVGA 0x00 +#define HSTART_QQVGA 0x16 +#define HSTOP_QQVGA 0x04 +#define HREF_QQVGA 0xa4 //0x24? 0xa4? +#define VSTART_QQVGA 0x02 +#define VSTOP_QQVGA 0x7a +#define VREF_QQVGA 0x0a +#define COM3_QQVGA 0x04 +#define COM14_QQVGA 0x1a +#define SCALING_XSC_QQVGA 0x3a +#define SCALING_YSC_QQVGA 0x35 +#define SCALING_DCWCTR_QQVGA 0x22 +#define SCALING_PCLK_DIV_QQVGA 0xf2 +#define SCALING_PCLK_DELAY_QQVGA 0x02 + +// CIF setting no tested linux src 2.6.29-rc5 ov7670_soc.c +#define COM7_CIF 0x00 +#define HSTART_CIF 0x15 +#define HSTOP_CIF 0x0b +#define HREF_CIF 0xb6 +#define VSTART_CIF 0x03 +#define VSTOP_CIF 0x7b +#define VREF_CIF 0x02 +#define COM3_CIF 0x08 +#define COM14_CIF 0x11 +#define SCALING_XSC_CIF 0x3a +#define SCALING_YSC_CIF 0x35 +#define SCALING_DCWCTR_CIF 0x11 +#define SCALING_PCLK_DIV_CIF 0xf1 +#define SCALING_PCLK_DELAY_CIF 0x02 + +// QCIF setting no tested no tested linux src 2.6.29-rc5 ov7670_soc.c +#define COM7_QCIF 0x00 +#define HSTART_QCIF 0x39 +#define HSTOP_QCIF 0x03 +#define HREF_QCIF 0x80 +#define VSTART_QCIF 0x03 +#define VSTOP_QCIF 0x7b +#define VREF_QCIF 0x02 +#define COM3_QCIF 0x0c +#define COM14_QCIF 0x11 +#define SCALING_XSC_QCIF 0x3a +#define SCALING_YSC_QCIF 0x35 +#define SCALING_DCWCTR_QCIF 0x11 +#define SCALING_PCLK_DIV_QCIF 0xf1 +#define SCALING_PCLK_DELAY_QCIF 0x52 + +// YUV +#define REG_COM13 0x3d /* Control 13 */ +#define REG_TSLB 0x3a /* lots of stuff */ + +#define COM7_YUV 0x00 /* YUV */ +#define COM13_UV 0x00 /* U before V - w/TSLB */ +#define COM13_UVSWAP 0x01 /* V before U - w/TSLB */ +#define TSLB_VLAST 0x00 /* YUYV - see com13 */ +#define TSLB_ULAST 0x00 /* YVYU - see com13 */ +#define TSLB_YLAST 0x08 /* UYVY or VYUY - see com13 */ + +// RGB +#define COM7_RGB 0x04 /* bits 0 and 2 - RGB format */ + +// RGB444 +#define REG_RGB444 0x8c /* RGB 444 control */ +#define REG_COM15 0x40 /* Control 15 */ + +#define RGB444_ENABLE 0x02 /* Turn on RGB444, overrides 5x5 */ +#define RGB444_XBGR 0x00 +#define RGB444_BGRX 0x01 /* Empty nibble at end */ +#define COM15_RGB444 0x10 /* RGB444 output */ + +// RGB555 +#define RGB444_DISABLE 0x00 /* Turn off RGB444, overrides 5x5 */ +#define COM15_RGB555 0x30 /* RGB555 output */ + +// RGB565 +#define COM15_RGB565 0x10 /* RGB565 output */ + +// Bayer RGB +#define COM7_BAYER 0x01 /* Bayer format */ +#define COM7_PBAYER 0x05 /* "Processed bayer" */ + + +// data format +#define COM15_R10F0 0x00 /* Data range 10 to F0 */ +#define COM15_R01FE 0x80 /* 01 to FE */ +#define COM15_R00FF 0xc0 /* 00 to FF */ + +// Night mode, flicker, banding / +#define REG_COM11 0x3b /* Control 11 */ +#define COM11_NIGHT 0x80 /* NIght mode enable */ +#define COM11_NIGHT_MIN_RATE_1_1 0x00 /* Normal mode same */ +#define COM11_NIGHT_MIN_RATE_1_2 0x20 /* Normal mode 1/2 */ +#define COM11_NIGHT_MIN_RATE_1_4 0x40 /* Normal mode 1/4 */ +#define COM11_NIGHT_MIN_RATE_1_8 0x60 /* Normal mode 1/5 */ +#define COM11_HZAUTO_ON 0x10 /* Auto detect 50/60 Hz on */ +#define COM11_HZAUTO_OFF 0x00 /* Auto detect 50/60 Hz off */ +#define COM11_60HZ 0x00 /* Manual 60Hz select */ +#define COM11_50HZ 0x08 /* Manual 50Hz select */ +#define COM11_EXP 0x02 + +#define REG_MTX1 0x4f +#define REG_MTX2 0x50 +#define REG_MTX3 0x51 +#define REG_MTX4 0x52 +#define REG_MTX5 0x53 +#define REG_MTX6 0x54 +#define REG_BRIGHT 0x55 /* Brightness */ +#define REG_CONTRAS 0x56 /* Contrast control */ +#define REG_CONTRAS_CENTER 0x57 +#define REG_MTXS 0x58 +#define REG_MANU 0x67 +#define REG_MANV 0x68 +#define REG_GFIX 0x69 /* Fix gain control */ +#define REG_GGAIN 0x6a +#define REG_DBLV 0x6b + +#define REG_COM9 0x14 // Control 9 - gain ceiling +#define COM9_AGC_2X 0x00 +#define COM9_AGC_4X 0x10 +#define COM9_AGC_8X 0x20 +#define COM9_AGC_16X 0x30 +#define COM9_AGC_32X 0x40 +#define COM9_AGC_64X 0x50 +#define COM9_AGC_128X 0x60 +#define COM9_AGC_MASK 0x70 +#define COM9_FREEZE 0x01 +#define COM13_GAMMA 0x80 /* Gamma enable */ +#define COM13_UVSAT 0x40 /* UV saturation auto adjustment */ +#define REG_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */ +#define REG_BLUE 0x01 /* blue gain */ +#define REG_RED 0x02 /* red gain */ +#define REG_COM1 0x04 /* Control 1 */ +#define COM1_CCIR656 0x40 /* CCIR656 enable */ +#define REG_BAVE 0x05 /* U/B Average level */ +#define REG_GbAVE 0x06 /* Y/Gb Average level */ +#define REG_AECHH 0x07 /* AEC MS 5 bits */ +#define REG_RAVE 0x08 /* V/R Average level */ +#define REG_COM2 0x09 /* Control 2 */ +#define COM2_SSLEEP 0x10 /* Soft sleep mode */ +#define REG_PID 0x0a /* Product ID MSB */ +#define REG_VER 0x0b /* Product ID LSB */ +#define COM3_SWAP 0x40 /* Byte swap */ +#define COM3_SCALEEN 0x08 /* Enable scaling */ +#define COM3_DCWEN 0x04 /* Enable downsamp/crop/window */ +#define REG_COM4 0x0d /* Control 4 */ +#define REG_COM5 0x0e /* All "reserved" */ +#define REG_COM6 0x0f /* Control 6 */ +#define REG_AECH 0x10 /* More bits of AEC value */ +#define REG_CLKRC 0x11 /* Clocl control */ +#define CLK_EXT 0x40 /* Use external clock directly */ +#define CLK_SCALE 0x3f /* Mask for internal clock scale */ +#define COM7_RESET 0x80 /* Register reset */ +#define COM7_FMT_MASK 0x38 +#define COM7_FMT_VGA 0x00 +#define COM7_FMT_CIF 0x20 /* CIF format */ +#define COM7_FMT_QVGA 0x10 /* QVGA format */ +#define COM7_FMT_QCIF 0x08 /* QCIF format */ +#define REG_COM8 0x13 /* Control 8 */ +#define COM8_FASTAEC 0x80 /* Enable fast AGC/AEC */ +#define COM8_AECSTEP 0x40 /* Unlimited AEC step size */ +#define COM8_BFILT 0x20 /* Band filter enable */ +#define COM8_AGC 0x04 /* Auto gain enable */ +#define COM8_AWB 0x02 /* White balance enable */ +#define COM8_AEC 0x01 /* Auto exposure enable */ +#define REG_COM9 0x14 /* Control 9 - gain ceiling */ +#define REG_COM10 0x15 /* Control 10 */ +#define COM10_HSYNC 0x40 /* HSYNC instead of HREF */ +#define COM10_PCLK_HB 0x20 /* Suppress PCLK on horiz blank */ +#define COM10_HREF_REV 0x08 /* Reverse HREF */ +#define COM10_VS_LEAD 0x04 /* VSYNC on clock leading edge */ +#define COM10_VS_NEG 0x02 /* VSYNC negative */ +#define COM10_HS_NEG 0x01 /* HSYNC negative */ +#define REG_PSHFT 0x1b /* Pixel delay after HREF */ +#define REG_MIDH 0x1c /* Manuf. ID high */ +#define REG_MIDL 0x1d /* Manuf. ID low */ +#define REG_MVFP 0x1e /* Mirror / vflip */ +#define MVFP_MIRROR 0x20 /* Mirror image */ +#define MVFP_FLIP 0x10 /* Vertical flip */ +#define REG_AEW 0x24 /* AGC upper limit */ +#define REG_AEB 0x25 /* AGC lower limit */ +#define REG_VPT 0x26 /* AGC/AEC fast mode op region */ +#define REG_HSYST 0x30 /* HSYNC rising edge delay */ +#define REG_HSYEN 0x31 /* HSYNC falling edge delay */ +#define REG_COM12 0x3c /* Control 12 */ +#define COM12_HREF 0x80 /* HREF always */ +#define COM14_DCWEN 0x10 /* DCW/PCLK-scale enable */ +#define REG_EDGE 0x3f /* Edge enhancement factor */ +#define REG_COM16 0x41 /* Control 16 */ +#define COM16_AWBGAIN 0x08 /* AWB gain enable */ +#define REG_COM17 0x42 /* Control 17 */ +#define COM17_AECWIN 0xc0 /* AEC window - must match COM4 */ +#define COM17_CBAR 0x08 /* DSP Color bar */ +#define REG_CMATRIX_BASE 0x4f +#define CMATRIX_LEN 6 +#define REG_REG76 0x76 /* OV's name */ +#define R76_BLKPCOR 0x80 /* Black pixel correction enable */ +#define R76_WHTPCOR 0x40 /* White pixel correction enable */ +#define REG_HAECC1 0x9f /* Hist AEC/AGC control 1 */ +#define REG_HAECC2 0xa0 /* Hist AEC/AGC control 2 */ +#define REG_BD50MAX 0xa5 /* 50hz banding step limit */ +#define REG_HAECC3 0xa6 /* Hist AEC/AGC control 3 */ +#define REG_HAECC4 0xa7 /* Hist AEC/AGC control 4 */ +#define REG_HAECC5 0xa8 /* Hist AEC/AGC control 5 */ +#define REG_HAECC6 0xa9 /* Hist AEC/AGC control 6 */ +#define REG_HAECC7 0xaa /* Hist AEC/AGC control 7 */ +#define REG_BD60MAX 0xab /* 60hz banding step limit */ \ No newline at end of file