Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
camera.cpp@0:78595d38d985, 2014-05-23 (annotated)
- Committer:
- ollyhicks
- Date:
- Fri May 23 20:48:07 2014 +0000
- Revision:
- 0:78595d38d985
Sort of working (terrible image)
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
ollyhicks | 0:78595d38d985 | 1 | #include "camera.h" |
ollyhicks | 0:78595d38d985 | 2 | |
ollyhicks | 0:78595d38d985 | 3 | /* |
ollyhicks | 0:78595d38d985 | 4 | * Links |
ollyhicks | 0:78595d38d985 | 5 | * https://gist.github.com/franciscospaeth/8503747 |
ollyhicks | 0:78595d38d985 | 6 | * http://embeddedprogrammer.blogspot.co.uk/2012/07/hacking-ov7670-camera-module-sccb-cheat.html |
ollyhicks | 0:78595d38d985 | 7 | * http://www.voti.nl/docs/OV7670.pdf |
ollyhicks | 0:78595d38d985 | 8 | */ |
ollyhicks | 0:78595d38d985 | 9 | |
ollyhicks | 0:78595d38d985 | 10 | BusIn data_p(p17,p18,p15,p16,p13,p14,p11,p12); |
ollyhicks | 0:78595d38d985 | 11 | |
ollyhicks | 0:78595d38d985 | 12 | PwmOut xclock_p(p21); |
ollyhicks | 0:78595d38d985 | 13 | DigitalIn pclock_p(p8); |
ollyhicks | 0:78595d38d985 | 14 | DigitalIn href_p(p5); |
ollyhicks | 0:78595d38d985 | 15 | DigitalIn vsync_p(p6); |
ollyhicks | 0:78595d38d985 | 16 | |
ollyhicks | 0:78595d38d985 | 17 | DigitalOut pwdn_p(p19); |
ollyhicks | 0:78595d38d985 | 18 | DigitalOut reset_p(p20); |
ollyhicks | 0:78595d38d985 | 19 | |
ollyhicks | 0:78595d38d985 | 20 | I2C i2c(p9, p10); //sda,scl |
ollyhicks | 0:78595d38d985 | 21 | |
ollyhicks | 0:78595d38d985 | 22 | void camera_setup() { |
ollyhicks | 0:78595d38d985 | 23 | pwdn_p.write(0); |
ollyhicks | 0:78595d38d985 | 24 | reset_p.write(1); // The reset pin must be HIGH! (3v3) |
ollyhicks | 0:78595d38d985 | 25 | |
ollyhicks | 0:78595d38d985 | 26 | /* |
ollyhicks | 0:78595d38d985 | 27 | * Make camera xclk using PWM |
ollyhicks | 0:78595d38d985 | 28 | * |
ollyhicks | 0:78595d38d985 | 29 | * Note the this is 1Mhz, the datasheet specifies a minimum of 26Mhz. |
ollyhicks | 0:78595d38d985 | 30 | * Reports online state that 10Mhz works, but if you're having issues |
ollyhicks | 0:78595d38d985 | 31 | * try 26Mhz as we don't understand the side affects. |
ollyhicks | 0:78595d38d985 | 32 | */ |
ollyhicks | 0:78595d38d985 | 33 | xclock_p.period(CAMERA_CLK_PERIOD); |
ollyhicks | 0:78595d38d985 | 34 | xclock_p = 0.5; |
ollyhicks | 0:78595d38d985 | 35 | |
ollyhicks | 0:78595d38d985 | 36 | // i2c |
ollyhicks | 0:78595d38d985 | 37 | i2c.stop() ; |
ollyhicks | 0:78595d38d985 | 38 | i2c.frequency(CAMERA_I2C_FREQ); // must be slow |
ollyhicks | 0:78595d38d985 | 39 | wait(0.1); |
ollyhicks | 0:78595d38d985 | 40 | |
ollyhicks | 0:78595d38d985 | 41 | /* |
ollyhicks | 0:78595d38d985 | 42 | * Set to QCIF (176 x 144) |
ollyhicks | 0:78595d38d985 | 43 | * Note that CAMERA_W and CAMERA_H must also be changed so |
ollyhicks | 0:78595d38d985 | 44 | * that the buffers are the correct length |
ollyhicks | 0:78595d38d985 | 45 | */ |
ollyhicks | 0:78595d38d985 | 46 | camera_set_output_format(CAMERA_I2C_OF_QCIF); |
ollyhicks | 0:78595d38d985 | 47 | |
ollyhicks | 0:78595d38d985 | 48 | /* |
ollyhicks | 0:78595d38d985 | 49 | * Set PCLK frequency slow enough for us to read and save the data (larger = slower) |
ollyhicks | 0:78595d38d985 | 50 | * Maximum 65 = (2^6 - 1) see datasheet for CLKRC |
ollyhicks | 0:78595d38d985 | 51 | */ |
ollyhicks | 0:78595d38d985 | 52 | camera_set_freq_scaler(32); |
ollyhicks | 0:78595d38d985 | 53 | } |
ollyhicks | 0:78595d38d985 | 54 | |
ollyhicks | 0:78595d38d985 | 55 | void camera_set_freq_scaler(int prescaler) { |
ollyhicks | 0:78595d38d985 | 56 | camera_i2c_write(CAMERA_I2C_REG_CLKRC, prescaler); |
ollyhicks | 0:78595d38d985 | 57 | } |
ollyhicks | 0:78595d38d985 | 58 | |
ollyhicks | 0:78595d38d985 | 59 | void camera_set_output_format(int output_format) { |
ollyhicks | 0:78595d38d985 | 60 | camera_i2c_write(CAMERA_I2C_REG_COM3, 0x08); // enable scaling |
ollyhicks | 0:78595d38d985 | 61 | camera_i2c_write(CAMERA_I2C_REG_COM7, output_format); |
ollyhicks | 0:78595d38d985 | 62 | } |
ollyhicks | 0:78595d38d985 | 63 | |
ollyhicks | 0:78595d38d985 | 64 | /** |
ollyhicks | 0:78595d38d985 | 65 | * Grab a single frame from the camera and save to the file |
ollyhicks | 0:78595d38d985 | 66 | */ |
ollyhicks | 0:78595d38d985 | 67 | void camera_grab(FILE *fp) { |
ollyhicks | 0:78595d38d985 | 68 | char href, vsync; |
ollyhicks | 0:78595d38d985 | 69 | |
ollyhicks | 0:78595d38d985 | 70 | int x = 0; // col |
ollyhicks | 0:78595d38d985 | 71 | int y = 0; // row |
ollyhicks | 0:78595d38d985 | 72 | long n = 0; // px number |
ollyhicks | 0:78595d38d985 | 73 | |
ollyhicks | 0:78595d38d985 | 74 | // Write one row of pixels to the file at a time, so store the row in a buffer |
ollyhicks | 0:78595d38d985 | 75 | char row_buffer[CAMERA_W * CAMERA_BPX]; |
ollyhicks | 0:78595d38d985 | 76 | |
ollyhicks | 0:78595d38d985 | 77 | // http://3.bp.blogspot.com/-cjOYTMj4C4M/UA2kV-db8GI/AAAAAAAAAPs/rtCGSIGjOHo/s1600/vga.png |
ollyhicks | 0:78595d38d985 | 78 | |
ollyhicks | 0:78595d38d985 | 79 | // Wait until the end of the previous frame |
ollyhicks | 0:78595d38d985 | 80 | wait_negedge(vsync_p); |
ollyhicks | 0:78595d38d985 | 81 | |
ollyhicks | 0:78595d38d985 | 82 | // Start of the frame |
ollyhicks | 0:78595d38d985 | 83 | while(1) { |
ollyhicks | 0:78595d38d985 | 84 | // Each row |
ollyhicks | 0:78595d38d985 | 85 | |
ollyhicks | 0:78595d38d985 | 86 | // Wait until the start of a row or the end of a frame |
ollyhicks | 0:78595d38d985 | 87 | do { |
ollyhicks | 0:78595d38d985 | 88 | href = href_p.read(); |
ollyhicks | 0:78595d38d985 | 89 | vsync = vsync_p.read(); |
ollyhicks | 0:78595d38d985 | 90 | } while(href == 0 && vsync == 0); |
ollyhicks | 0:78595d38d985 | 91 | |
ollyhicks | 0:78595d38d985 | 92 | // Vsync high, thus the end of the frame |
ollyhicks | 0:78595d38d985 | 93 | if(vsync == 1){ |
ollyhicks | 0:78595d38d985 | 94 | // Print the current x, y and n |
ollyhicks | 0:78595d38d985 | 95 | // These indicate how many pixels where actually captured |
ollyhicks | 0:78595d38d985 | 96 | printf("y: %d\r\n", y); |
ollyhicks | 0:78595d38d985 | 97 | printf("x: %d\r\n", x); |
ollyhicks | 0:78595d38d985 | 98 | printf("n: %ld\r\n", n); |
ollyhicks | 0:78595d38d985 | 99 | return; // is the end of a frame |
ollyhicks | 0:78595d38d985 | 100 | } |
ollyhicks | 0:78595d38d985 | 101 | // else carry on (href = 1) |
ollyhicks | 0:78595d38d985 | 102 | |
ollyhicks | 0:78595d38d985 | 103 | x = 0; |
ollyhicks | 0:78595d38d985 | 104 | |
ollyhicks | 0:78595d38d985 | 105 | /* |
ollyhicks | 0:78595d38d985 | 106 | * Note we must sample at the rising edge of the PCLK, |
ollyhicks | 0:78595d38d985 | 107 | * but we must also read the href to check that the frame |
ollyhicks | 0:78595d38d985 | 108 | * has not ended. |
ollyhicks | 0:78595d38d985 | 109 | * http://2.bp.blogspot.com/-K-OIuy-inUU/UA2gp3SYgYI/AAAAAAAAAPg/Gure3RWI8G4/s1600/href.png |
ollyhicks | 0:78595d38d985 | 110 | */ |
ollyhicks | 0:78595d38d985 | 111 | |
ollyhicks | 0:78595d38d985 | 112 | wait_posedge(pclock_p); |
ollyhicks | 0:78595d38d985 | 113 | |
ollyhicks | 0:78595d38d985 | 114 | while(href_p.read() == 1) { |
ollyhicks | 0:78595d38d985 | 115 | // Each column |
ollyhicks | 0:78595d38d985 | 116 | |
ollyhicks | 0:78595d38d985 | 117 | // sample at the rising edge of the PCLK signal |
ollyhicks | 0:78595d38d985 | 118 | |
ollyhicks | 0:78595d38d985 | 119 | row_buffer[x] = data_p.read(); |
ollyhicks | 0:78595d38d985 | 120 | |
ollyhicks | 0:78595d38d985 | 121 | n++; |
ollyhicks | 0:78595d38d985 | 122 | x++; |
ollyhicks | 0:78595d38d985 | 123 | |
ollyhicks | 0:78595d38d985 | 124 | // Wait until next rising edge so that when the href read is done it has changed |
ollyhicks | 0:78595d38d985 | 125 | wait_posedge(pclock_p); |
ollyhicks | 0:78595d38d985 | 126 | } |
ollyhicks | 0:78595d38d985 | 127 | |
ollyhicks | 0:78595d38d985 | 128 | // Write row buffer to the flash |
ollyhicks | 0:78595d38d985 | 129 | fwrite(row_buffer, sizeof(char), sizeof(row_buffer), fp); |
ollyhicks | 0:78595d38d985 | 130 | |
ollyhicks | 0:78595d38d985 | 131 | |
ollyhicks | 0:78595d38d985 | 132 | y++; |
ollyhicks | 0:78595d38d985 | 133 | } |
ollyhicks | 0:78595d38d985 | 134 | |
ollyhicks | 0:78595d38d985 | 135 | } |
ollyhicks | 0:78595d38d985 | 136 | |
ollyhicks | 0:78595d38d985 | 137 | int camera_i2c_read(int addr) { |
ollyhicks | 0:78595d38d985 | 138 | int data=0; |
ollyhicks | 0:78595d38d985 | 139 | |
ollyhicks | 0:78595d38d985 | 140 | // Address |
ollyhicks | 0:78595d38d985 | 141 | i2c.start(); |
ollyhicks | 0:78595d38d985 | 142 | i2c.write(CAMERA_I2C_WRITE_ADDR); |
ollyhicks | 0:78595d38d985 | 143 | i2c.write(addr); |
ollyhicks | 0:78595d38d985 | 144 | |
ollyhicks | 0:78595d38d985 | 145 | // Not sure why we must stop the i2c bus? |
ollyhicks | 0:78595d38d985 | 146 | i2c.stop(); |
ollyhicks | 0:78595d38d985 | 147 | |
ollyhicks | 0:78595d38d985 | 148 | wait_us(50); |
ollyhicks | 0:78595d38d985 | 149 | |
ollyhicks | 0:78595d38d985 | 150 | // Data |
ollyhicks | 0:78595d38d985 | 151 | i2c.start(); |
ollyhicks | 0:78595d38d985 | 152 | i2c.write(CAMERA_I2C_READ_ADDR); |
ollyhicks | 0:78595d38d985 | 153 | data = i2c.read(CAMERA_I2C_NOACK) ; |
ollyhicks | 0:78595d38d985 | 154 | i2c.stop(); |
ollyhicks | 0:78595d38d985 | 155 | |
ollyhicks | 0:78595d38d985 | 156 | wait_us(50); |
ollyhicks | 0:78595d38d985 | 157 | return data; |
ollyhicks | 0:78595d38d985 | 158 | } |
ollyhicks | 0:78595d38d985 | 159 | |
ollyhicks | 0:78595d38d985 | 160 | void camera_i2c_write(int addr, int val) { |
ollyhicks | 0:78595d38d985 | 161 | i2c.start(); |
ollyhicks | 0:78595d38d985 | 162 | |
ollyhicks | 0:78595d38d985 | 163 | i2c.write(CAMERA_I2C_WRITE_ADDR); |
ollyhicks | 0:78595d38d985 | 164 | i2c.write(addr); |
ollyhicks | 0:78595d38d985 | 165 | |
ollyhicks | 0:78595d38d985 | 166 | i2c.write(val); |
ollyhicks | 0:78595d38d985 | 167 | |
ollyhicks | 0:78595d38d985 | 168 | i2c.stop(); |
ollyhicks | 0:78595d38d985 | 169 | |
ollyhicks | 0:78595d38d985 | 170 | wait_us(50); |
ollyhicks | 0:78595d38d985 | 171 | } |
ollyhicks | 0:78595d38d985 | 172 | |
ollyhicks | 0:78595d38d985 | 173 | void wait_posedge(DigitalIn pin) { |
ollyhicks | 0:78595d38d985 | 174 | while(pin.read() == 1) {}; |
ollyhicks | 0:78595d38d985 | 175 | while(pin.read() == 0) {}; |
ollyhicks | 0:78595d38d985 | 176 | } |
ollyhicks | 0:78595d38d985 | 177 | |
ollyhicks | 0:78595d38d985 | 178 | void wait_negedge(DigitalIn pin) { |
ollyhicks | 0:78595d38d985 | 179 | while(pin.read() == 0) {}; |
ollyhicks | 0:78595d38d985 | 180 | while(pin.read() == 1) {}; |
ollyhicks | 0:78595d38d985 | 181 | } |