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.
Dependents: CameraOV528-Example
CameraOV528.cpp
00001 /* Copyright (c) 2016 ARM Limited 00002 * 00003 * Licensed under the Apache License, Version 2.0 (the "License"); 00004 * you may not use this file except in compliance with the License. 00005 * You may obtain a copy of the License at 00006 * 00007 * http://www.apache.org/licenses/LICENSE-2.0 00008 * 00009 * Unless required by applicable law or agreed to in writing, software 00010 * distributed under the License is distributed on an "AS IS" BASIS, 00011 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00012 * See the License for the specific language governing permissions and 00013 * limitations under the License. 00014 */ 00015 00016 /* 00017 * Originally Based on the (Grove_Serial_Camera_Kit) - https://github.com/Seeed-Studio/Grove_Serial_Camera_Kit 00018 */ 00019 00020 #include<stdint.h> 00021 #include<stdlib.h> 00022 #include<string.h> 00023 00024 #include "CameraOV528.h" 00025 00026 #define camera_printf(...) 00027 00028 #define PIC_CLOCK_HZ 14745600 00029 #define BOOT_BAUD 9600 00030 00031 #define COMMAND_LENGTH 6 00032 #define PIC_PAYLOAD_DATA_BEGIN 4 00033 #define PIC_PAYLOAD_OVERHEAD 6 00034 #define READ_WAKE_POS_INVALID 0xFFFFFFFF 00035 00036 #define DEFAULT_BAUD 115200 00037 00038 enum CameraCommand { 00039 INITIAL = 0x01, 00040 GET_PICTURE = 0x04, 00041 SNAPSHOT = 0x05, 00042 SET_PACKAGE_SIZE = 0x06, 00043 SET_BAUD_RATE = 0x07, 00044 RESET = 0x08, 00045 POWER_DOWN = 0x09, 00046 DATA = 0x0A, 00047 SYNC = 0x0D, 00048 ACK = 0x0E, 00049 NAK = 0x0F 00050 }; 00051 00052 enum GetSetting { 00053 GET_SNAPSHOT = 1, 00054 GET_PREVIEW_PICTURE = 2, 00055 GET_JPEG_PREVIEW_PICTURE = 3, 00056 }; 00057 00058 typedef struct { 00059 uint8_t header; 00060 uint8_t command; 00061 uint8_t param[4]; 00062 } camera_command_t; 00063 00064 CameraOV528::Resolution supported_resolutions[] = { 00065 // CameraOV528::RES_80x60, //Does not work 00066 CameraOV528::RES_160x120, 00067 CameraOV528::RES_320x240, 00068 CameraOV528::RES_640x480, 00069 }; 00070 00071 CameraOV528::Format supported_formats[] = { 00072 // CameraOV528::FMT_2_BIT_GRAY_SCALE, //Does not work 00073 // CameraOV528::FMT_4_BIT_GRAY_SCALE, 00074 // CameraOV528::FMT_8_BIT_GRAY_SCALE, 00075 // CameraOV528::FMT_2_BIT_COLOR, 00076 // CameraOV528::FMT_16_BIT, 00077 CameraOV528::FMT_JPEG, 00078 }; 00079 00080 static uint32_t divide_round_up(uint32_t dividen, uint32_t divisor); 00081 static uint32_t min(uint32_t value1, uint32_t value2); 00082 static uint32_t queue_used(uint32_t head, uint32_t tail, uint32_t size); 00083 00084 CameraOV528::CameraOV528(PinName rx, PinName tx) : _serial(rx, tx), _read_sem(0) 00085 { 00086 _init_done = false; 00087 _resolution = RES_640x480; 00088 _format = FMT_JPEG; 00089 _baud = DEFAULT_BAUD; 00090 00091 _dev_resolution = _resolution; 00092 _dev_format = _format; 00093 _dev_baud = _baud; 00094 00095 picture_length = 0; 00096 picture_data_id = 0; 00097 picture_data_id_count = 0; 00098 memset(picture_buffer, 0, sizeof(picture_buffer)); 00099 picture_buffer_size_limit = sizeof(picture_buffer); 00100 picture_buffer_pos = 0; 00101 picture_buffer_size = 0; 00102 00103 memset(_read_buf, 0, sizeof(_read_buf)); 00104 _read_buf_head = 0; 00105 _read_buf_tail = 0; 00106 _read_wake_pos = READ_WAKE_POS_INVALID; 00107 this->log_func = debug; 00108 } 00109 00110 CameraOV528::~CameraOV528() 00111 { 00112 powerdown(); 00113 } 00114 00115 void CameraOV528::attach_debug_function(void (*func)(const char* fmt, ...)) 00116 { 00117 this->log_func = func; 00118 } 00119 00120 int CameraOV528::camera_error(const char* message) 00121 { 00122 log_func("%s\r\n",message); 00123 return -1; 00124 } 00125 00126 int CameraOV528::powerup() 00127 { 00128 if (_init_done) { 00129 return 0; 00130 } 00131 00132 _serial.attach(this, &CameraOV528::_rx_irq, SerialBase::RxIrq); 00133 00134 // Attempt to connect at the desired baud 00135 _serial.baud(_baud); 00136 bool success = _init_sequence(); 00137 00138 // If unsuccessful try with boot baud 00139 if (!success) { 00140 _serial.baud(BOOT_BAUD); 00141 success = _init_sequence(); 00142 } 00143 00144 if (!success) { 00145 return camera_error("Unable to communicate with camera"); 00146 } 00147 00148 // Acknowledge the SYNC read in _init_sequence with an ACK 00149 _send_ack(SYNC, 0, 0, 0); 00150 camera_printf("\nCamera initialization done.\r\n"); 00151 00152 _set_baud(_baud); 00153 00154 _set_fmt_and_res(_format, _resolution); 00155 _set_package_size(picture_buffer_size_limit); 00156 00157 _init_done = false; 00158 return 0; 00159 } 00160 00161 int CameraOV528::powerup(uint32_t baud) 00162 { 00163 _baud = baud; 00164 return powerup(); 00165 } 00166 00167 int CameraOV528::powerdown() 00168 { 00169 if (!_init_done) { 00170 return 0; 00171 } 00172 00173 if (!_send_cmd(POWER_DOWN, 0)) { 00174 return camera_error("Powerdown failed"); 00175 } 00176 00177 // Reset picture transfer variables 00178 picture_length = 0; 00179 picture_data_id = 0; 00180 picture_data_id_count = 0; 00181 memset(picture_buffer, 0, sizeof(picture_buffer)); 00182 picture_buffer_size_limit = sizeof(picture_buffer); 00183 picture_buffer_pos = 0; 00184 picture_buffer_size = 0; 00185 00186 _serial.attach(NULL, SerialBase::RxIrq); 00187 _flush_rx(); 00188 00189 _init_done = false; 00190 return 0; 00191 } 00192 00193 int CameraOV528::take_picture(void) 00194 { 00195 // Ensure driver is powered up 00196 powerup(); 00197 00198 // Update settings if any have changed 00199 if ((_dev_format != _format) || (_dev_resolution != _resolution)) { 00200 _set_fmt_and_res(_format, _resolution); 00201 _dev_format = _format; 00202 _dev_resolution = _resolution; 00203 } 00204 00205 // Take snapshot 00206 camera_printf("Taking snapshot\r\n"); 00207 if (!_send_cmd(SNAPSHOT, 0)) { 00208 return camera_error("Take snapshot failed"); 00209 } 00210 00211 // Start picture transfer 00212 camera_printf("Starting transfer\r\n"); 00213 const GetSetting request = GET_JPEG_PREVIEW_PICTURE; 00214 if (!_send_cmd(GET_PICTURE, request)) { 00215 return camera_error("Get picture command failed"); 00216 } 00217 camera_command_t resp = {0}; 00218 uint32_t size_read = _read((uint8_t*)&resp, COMMAND_LENGTH, 1000); 00219 if (size_read != COMMAND_LENGTH) { 00220 return camera_error("Get picture response invalid"); 00221 } 00222 if (resp.header != 0xAA) camera_error("Get picture response invalid sync"); 00223 if (resp.command != DATA) camera_error("Get picture response invalid data"); 00224 if (resp.param[0] != request) camera_error("Get picture response invalid content"); 00225 picture_length = (resp.param[1] << 0) | 00226 (resp.param[2] << 8) | 00227 (resp.param[3] << 16); 00228 picture_data_id = 0; 00229 uint32_t payload_length = picture_buffer_size_limit - PIC_PAYLOAD_OVERHEAD; 00230 picture_data_id_count = divide_round_up(picture_length, payload_length); 00231 return 0; 00232 } 00233 00234 uint32_t CameraOV528::get_picture_size() 00235 { 00236 return picture_length; 00237 } 00238 00239 uint32_t CameraOV528::read_picture_data(uint8_t * data, uint32_t size) 00240 { 00241 uint32_t size_copied = 0; 00242 while (size_copied < size) { 00243 00244 // Copy any data in the picture buffer 00245 uint32_t size_left = size - size_copied; 00246 uint32_t copy_size = min(picture_buffer_size, size_left); 00247 memcpy(data + size_copied, picture_buffer + picture_buffer_pos, copy_size); 00248 picture_buffer_pos += copy_size; 00249 picture_buffer_size -= copy_size; 00250 size_copied += copy_size; 00251 00252 // If picture buffer is empty read more data 00253 if (0 == picture_buffer_size) { 00254 _read_picture_block(); 00255 } 00256 00257 // If there is still no more data to read then break from loop 00258 if (0 == picture_buffer_size) { 00259 break; 00260 } 00261 } 00262 00263 return size_copied; 00264 } 00265 00266 void CameraOV528::set_resolution(CameraOV528::Resolution resolution) 00267 { 00268 const uint32_t count = sizeof(supported_resolutions) / sizeof(supported_resolutions[0]); 00269 bool valid_resolution = false; 00270 for (uint32_t i = 0; i < count; i++) { 00271 if (resolution == supported_resolutions[i]) { 00272 valid_resolution = true; 00273 break; 00274 } 00275 } 00276 00277 if (!valid_resolution) { 00278 camera_error("Invalid resolution"); 00279 } 00280 00281 _resolution = resolution; 00282 00283 } 00284 00285 void CameraOV528::set_format(CameraOV528::Format format) 00286 { 00287 const uint32_t count = sizeof(supported_formats) / sizeof(supported_formats[0]); 00288 bool valid_format = false; 00289 for (uint32_t i = 0; i < count; i++) { 00290 if (format == supported_formats[i]) { 00291 valid_format = true; 00292 break; 00293 } 00294 } 00295 00296 if (!valid_format) { 00297 camera_error("Invalid format"); 00298 } 00299 00300 _format = format; 00301 } 00302 00303 void CameraOV528::_set_baud(uint32_t baud) 00304 { 00305 // Baud Rate = 14.7456MHz/(2*(2nd divider +1))/(2*(1st divider+1)) 00306 uint32_t div2 = 1; 00307 uint32_t div1 = PIC_CLOCK_HZ / _baud / (2 * (div2 + 1)) / 2 - 1; 00308 // Assert no rounding errors 00309 MBED_ASSERT(PIC_CLOCK_HZ / ( 2 * (div2 + 1) ) / ( 2 * (div1 + 1)) == _baud); 00310 if (!_send_cmd(SET_BAUD_RATE, div1, div2)) { 00311 camera_error("_set_baud failed"); 00312 } 00313 _serial.baud(_baud); 00314 } 00315 00316 void CameraOV528::_set_package_size(uint32_t size) 00317 { 00318 camera_printf("_set_package_size(%lu)\r\n", size); 00319 uint8_t size_low = (size >> 0) & 0xff; 00320 uint8_t size_high = (size >> 8) & 0xff; 00321 if (!_send_cmd(SET_PACKAGE_SIZE, 0x08, size_low, size_high, 0)) { 00322 camera_error("_set_package_size failed"); 00323 } 00324 } 00325 00326 void CameraOV528::_set_fmt_and_res(Format fmt, Resolution res) 00327 { 00328 if (!_send_cmd(INITIAL, 0x00, _format, 0x00, _resolution)) { 00329 camera_error("_set_fmt_and_res failed"); 00330 } 00331 } 00332 00333 int CameraOV528::_read_picture_block() 00334 { 00335 const uint32_t payload_length = picture_buffer_size_limit - PIC_PAYLOAD_OVERHEAD; 00336 if (picture_data_id >= picture_data_id_count) { 00337 // Transfer complete 00338 return 0; 00339 } 00340 00341 // Send an ACK to indicate that the next block id should be sent 00342 uint8_t id_low = (picture_data_id >> 0) & 0xff; 00343 uint8_t id_high = (picture_data_id >> 8) & 0xff; 00344 _send_ack(0x00, 0x00, id_low, id_high); 00345 00346 // Read image data 00347 memset(picture_buffer, 0, sizeof(picture_buffer)); 00348 uint32_t size_left = picture_length - payload_length * picture_data_id; 00349 uint32_t size_to_read = min(size_left, payload_length) + PIC_PAYLOAD_OVERHEAD; 00350 uint32_t size_read = _read(picture_buffer, size_to_read); 00351 if (size_read != size_to_read) { 00352 return camera_error("Image data protocol error"); 00353 } 00354 00355 // Validate checksum 00356 uint8_t checksum = 0; 00357 for (uint32_t i = 0; i < size_read - 2; i++) { 00358 checksum += picture_buffer[i]; 00359 } 00360 if (picture_buffer[size_read - 2] != checksum) { 00361 return camera_error("Image data checksum failure"); 00362 } 00363 00364 // Update buffer information 00365 picture_buffer_pos = PIC_PAYLOAD_DATA_BEGIN; 00366 picture_buffer_size = size_read - PIC_PAYLOAD_OVERHEAD; 00367 00368 // If this is the last packet then send the completion ACK 00369 if (picture_data_id + 1 == picture_data_id_count) { 00370 _send_ack(0x00, 0x00, 0xF0, 0xF0); 00371 } 00372 00373 // Increment position 00374 camera_printf("%lu of %lu\r\n", picture_data_id + 1, picture_data_id_count); 00375 camera_printf("size left %lu\r\n", 00376 picture_length - payload_length * picture_data_id + 00377 PIC_PAYLOAD_OVERHEAD - size_read); 00378 picture_data_id++; 00379 return 0; 00380 } 00381 00382 void CameraOV528::_send_ack(uint8_t p1, uint8_t p2, uint8_t p3, uint8_t p4) 00383 { 00384 camera_command_t cmd = {0}; 00385 cmd.header = 0xAA; 00386 cmd.command = ACK; 00387 cmd.param[0] = p1; 00388 cmd.param[1] = p2; 00389 cmd.param[2] = p3; 00390 cmd.param[3] = p4; 00391 _send((uint8_t*)&cmd, COMMAND_LENGTH); 00392 } 00393 00394 void CameraOV528::_rx_irq(void) 00395 { 00396 if(_serial.readable()) { 00397 00398 // Check for overflow 00399 if (_read_buf_head + 1 == _read_buf_tail) { 00400 camera_error("RX buffer overflow"); 00401 } 00402 00403 // Add data 00404 _read_buf[_read_buf_head] = (uint8_t)_serial.getc(); 00405 _read_buf_head = (_read_buf_head + 1) % sizeof(_read_buf); 00406 00407 // Check if thread should be woken 00408 if (_read_buf_head == _read_wake_pos) { 00409 _read_sem.release(); 00410 _read_wake_pos = READ_WAKE_POS_INVALID; 00411 } 00412 } 00413 } 00414 00415 bool CameraOV528::_send(const uint8_t *data, uint32_t size, uint32_t timeout_ms) 00416 { 00417 for (uint32_t i = 0; i < size; i++) { 00418 _serial.putc(data[i]); 00419 } 00420 return true; 00421 } 00422 00423 uint32_t CameraOV528::_read(uint8_t *data, uint32_t size, uint32_t timeout_ms) 00424 { 00425 MBED_ASSERT(size < sizeof(_read_buf)); 00426 MBED_ASSERT(0 == _read_sem.wait(0)); 00427 00428 core_util_critical_section_enter(); 00429 00430 // Atomically set wakeup condition 00431 uint32_t size_available = queue_used(_read_buf_head, _read_buf_tail, sizeof(_read_buf)); 00432 if (size_available >= size) { 00433 _read_wake_pos = READ_WAKE_POS_INVALID; 00434 } else { 00435 _read_wake_pos = (_read_buf_tail + size) % sizeof(_read_buf); 00436 } 00437 00438 core_util_critical_section_exit(); 00439 00440 // Wait until the requested number of bytes are available 00441 if (_read_wake_pos != READ_WAKE_POS_INVALID) { 00442 int32_t tokens = _read_sem.wait(timeout_ms); 00443 if (tokens <= 0) { 00444 // Timeout occurred so make sure semaphore is cleared 00445 _read_wake_pos = READ_WAKE_POS_INVALID; 00446 _read_sem.wait(0); 00447 } else { 00448 // If the semaphore was signaled then the requested number of 00449 // bytes were read 00450 MBED_ASSERT(queue_used(_read_buf_head, _read_buf_tail, sizeof(_read_buf)) >= size); 00451 } 00452 } 00453 00454 // Copy bytes 00455 size_available = queue_used(_read_buf_head, _read_buf_tail, sizeof(_read_buf)); 00456 uint32_t read_size = min(size_available, size); 00457 for (uint32_t i = 0; i < read_size; i++) { 00458 data[i] = _read_buf[_read_buf_tail]; 00459 _read_buf_tail = (_read_buf_tail + 1) % sizeof(_read_buf); 00460 } 00461 00462 return read_size; 00463 } 00464 00465 00466 void CameraOV528::_flush_rx(void) 00467 { 00468 00469 core_util_critical_section_enter(); 00470 _read_buf_head = 0; 00471 _read_buf_tail = 0; 00472 _read_wake_pos = 0; 00473 core_util_critical_section_exit(); 00474 } 00475 00476 bool CameraOV528::_send_cmd(uint8_t cmd, uint8_t p1, uint8_t p2, uint8_t p3, uint8_t p4) 00477 { 00478 _flush_rx(); 00479 00480 camera_command_t command = {0}; 00481 command.header = 0xAA; 00482 command.command = cmd; 00483 command.param[0] = p1; 00484 command.param[1] = p2; 00485 command.param[2] = p3; 00486 command.param[3] = p4; 00487 _send((uint8_t*)&command, COMMAND_LENGTH); 00488 00489 camera_command_t resp = {0}; 00490 uint32_t len = _read((uint8_t*)&resp, COMMAND_LENGTH); 00491 if (COMMAND_LENGTH != len) { 00492 camera_printf("Wrong command response length %lu\r\n", len); 00493 } 00494 if ((resp.header != 0xAA) || (resp.command != ACK) || (resp.param[0] != command.command)) { 00495 camera_printf("Invalid command: %i, %i, %i\r\n", resp.header, resp.command, resp.param[0]); 00496 return false; 00497 } 00498 return true; 00499 } 00500 00501 bool CameraOV528::_init_sequence() 00502 { 00503 camera_printf("connecting to camera..."); 00504 bool success = false; 00505 for (uint32_t i = 0; i < 4; i++) { 00506 camera_printf("."); 00507 00508 // Send SYNC command repeatedly 00509 if (!_send_cmd(SYNC, 0, 0, 0, 0)) { 00510 continue; 00511 } 00512 // Device should send back SYNC command 00513 camera_command_t resp = {0}; 00514 if (_read((uint8_t*)&resp, COMMAND_LENGTH, 500) != COMMAND_LENGTH) { 00515 continue; 00516 } 00517 if (resp.header != 0xAA) continue; 00518 if (resp.command != SYNC) continue; 00519 if (resp.param[0] != 0) continue; 00520 if (resp.param[1] != 0) continue; 00521 if (resp.param[2] != 0) continue; 00522 if (resp.param[3] != 0) continue; 00523 success = true; 00524 break; 00525 } 00526 return success; 00527 } 00528 00529 static uint32_t divide_round_up(uint32_t dividen, uint32_t divisor) 00530 { 00531 return (dividen + divisor - 1) / divisor; 00532 } 00533 00534 static uint32_t min(uint32_t value1, uint32_t value2) 00535 { 00536 return value1 < value2 ? value1 : value2; 00537 } 00538 00539 static uint32_t queue_used(uint32_t head, uint32_t tail, uint32_t size) 00540 { 00541 if (head < tail) { 00542 return head + size - tail; 00543 } else { 00544 return head - tail; 00545 } 00546 }
Generated on Wed Jul 13 2022 05:09:17 by
1.7.2
Camera OV528