OV528 Camera Module Library

Committer:
aoba
Date:
Sat Feb 02 05:22:29 2019 +0000
Revision:
3:274014e87a49
Parent:
2:7a563410b23d
Changed the constant name for collision on recent Mbed

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jplunkett 0:3f9d7ef7266c 1 /* Copyright (c) 2016 ARM Limited
jplunkett 0:3f9d7ef7266c 2 *
jplunkett 0:3f9d7ef7266c 3 * Licensed under the Apache License, Version 2.0 (the "License");
jplunkett 0:3f9d7ef7266c 4 * you may not use this file except in compliance with the License.
jplunkett 0:3f9d7ef7266c 5 * You may obtain a copy of the License at
jplunkett 0:3f9d7ef7266c 6 *
jplunkett 0:3f9d7ef7266c 7 * http://www.apache.org/licenses/LICENSE-2.0
jplunkett 0:3f9d7ef7266c 8 *
jplunkett 0:3f9d7ef7266c 9 * Unless required by applicable law or agreed to in writing, software
jplunkett 0:3f9d7ef7266c 10 * distributed under the License is distributed on an "AS IS" BASIS,
jplunkett 0:3f9d7ef7266c 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
jplunkett 0:3f9d7ef7266c 12 * See the License for the specific language governing permissions and
jplunkett 0:3f9d7ef7266c 13 * limitations under the License.
jplunkett 0:3f9d7ef7266c 14 */
jplunkett 0:3f9d7ef7266c 15
jplunkett 0:3f9d7ef7266c 16 /*
jplunkett 0:3f9d7ef7266c 17 * Originally Based on the (Grove_Serial_Camera_Kit) - https://github.com/Seeed-Studio/Grove_Serial_Camera_Kit
jplunkett 0:3f9d7ef7266c 18 */
jplunkett 0:3f9d7ef7266c 19
jplunkett 0:3f9d7ef7266c 20 #include<stdint.h>
jplunkett 0:3f9d7ef7266c 21 #include<stdlib.h>
jplunkett 0:3f9d7ef7266c 22 #include<string.h>
jplunkett 0:3f9d7ef7266c 23
jplunkett 0:3f9d7ef7266c 24 #include "CameraOV528.h"
jplunkett 0:3f9d7ef7266c 25
jplunkett 0:3f9d7ef7266c 26 #define camera_printf(...)
jplunkett 0:3f9d7ef7266c 27
jplunkett 0:3f9d7ef7266c 28 #define PIC_CLOCK_HZ 14745600
jplunkett 0:3f9d7ef7266c 29 #define BOOT_BAUD 9600
jplunkett 0:3f9d7ef7266c 30
jplunkett 0:3f9d7ef7266c 31 #define COMMAND_LENGTH 6
jplunkett 0:3f9d7ef7266c 32 #define PIC_PAYLOAD_DATA_BEGIN 4
jplunkett 0:3f9d7ef7266c 33 #define PIC_PAYLOAD_OVERHEAD 6
jplunkett 0:3f9d7ef7266c 34 #define READ_WAKE_POS_INVALID 0xFFFFFFFF
jplunkett 0:3f9d7ef7266c 35
jplunkett 0:3f9d7ef7266c 36 #define DEFAULT_BAUD 115200
jplunkett 0:3f9d7ef7266c 37
jplunkett 0:3f9d7ef7266c 38 enum CameraCommand {
jplunkett 0:3f9d7ef7266c 39 INITIAL = 0x01,
jplunkett 0:3f9d7ef7266c 40 GET_PICTURE = 0x04,
jplunkett 0:3f9d7ef7266c 41 SNAPSHOT = 0x05,
jplunkett 0:3f9d7ef7266c 42 SET_PACKAGE_SIZE = 0x06,
jplunkett 0:3f9d7ef7266c 43 SET_BAUD_RATE = 0x07,
aoba 3:274014e87a49 44 RESET_CAMERA = 0x08,
jplunkett 0:3f9d7ef7266c 45 POWER_DOWN = 0x09,
jplunkett 0:3f9d7ef7266c 46 DATA = 0x0A,
jplunkett 0:3f9d7ef7266c 47 SYNC = 0x0D,
jplunkett 0:3f9d7ef7266c 48 ACK = 0x0E,
jplunkett 0:3f9d7ef7266c 49 NAK = 0x0F
jplunkett 0:3f9d7ef7266c 50 };
jplunkett 0:3f9d7ef7266c 51
jplunkett 0:3f9d7ef7266c 52 enum GetSetting {
jplunkett 0:3f9d7ef7266c 53 GET_SNAPSHOT = 1,
jplunkett 0:3f9d7ef7266c 54 GET_PREVIEW_PICTURE = 2,
jplunkett 0:3f9d7ef7266c 55 GET_JPEG_PREVIEW_PICTURE = 3,
jplunkett 0:3f9d7ef7266c 56 };
jplunkett 0:3f9d7ef7266c 57
jplunkett 0:3f9d7ef7266c 58 typedef struct {
jplunkett 0:3f9d7ef7266c 59 uint8_t header;
jplunkett 0:3f9d7ef7266c 60 uint8_t command;
jplunkett 0:3f9d7ef7266c 61 uint8_t param[4];
jplunkett 0:3f9d7ef7266c 62 } camera_command_t;
jplunkett 0:3f9d7ef7266c 63
jplunkett 0:3f9d7ef7266c 64 CameraOV528::Resolution supported_resolutions[] = {
jplunkett 0:3f9d7ef7266c 65 // CameraOV528::RES_80x60, //Does not work
jplunkett 0:3f9d7ef7266c 66 CameraOV528::RES_160x120,
jplunkett 0:3f9d7ef7266c 67 CameraOV528::RES_320x240,
jplunkett 0:3f9d7ef7266c 68 CameraOV528::RES_640x480,
jplunkett 0:3f9d7ef7266c 69 };
jplunkett 0:3f9d7ef7266c 70
jplunkett 0:3f9d7ef7266c 71 CameraOV528::Format supported_formats[] = {
jplunkett 0:3f9d7ef7266c 72 // CameraOV528::FMT_2_BIT_GRAY_SCALE, //Does not work
jplunkett 0:3f9d7ef7266c 73 // CameraOV528::FMT_4_BIT_GRAY_SCALE,
jplunkett 0:3f9d7ef7266c 74 // CameraOV528::FMT_8_BIT_GRAY_SCALE,
jplunkett 0:3f9d7ef7266c 75 // CameraOV528::FMT_2_BIT_COLOR,
jplunkett 0:3f9d7ef7266c 76 // CameraOV528::FMT_16_BIT,
jplunkett 0:3f9d7ef7266c 77 CameraOV528::FMT_JPEG,
jplunkett 0:3f9d7ef7266c 78 };
jplunkett 0:3f9d7ef7266c 79
jplunkett 0:3f9d7ef7266c 80 static uint32_t divide_round_up(uint32_t dividen, uint32_t divisor);
jplunkett 0:3f9d7ef7266c 81 static uint32_t min(uint32_t value1, uint32_t value2);
jplunkett 0:3f9d7ef7266c 82 static uint32_t queue_used(uint32_t head, uint32_t tail, uint32_t size);
jplunkett 0:3f9d7ef7266c 83
jplunkett 0:3f9d7ef7266c 84 CameraOV528::CameraOV528(PinName rx, PinName tx) : _serial(rx, tx), _read_sem(0)
jplunkett 0:3f9d7ef7266c 85 {
jplunkett 0:3f9d7ef7266c 86 _init_done = false;
jplunkett 0:3f9d7ef7266c 87 _resolution = RES_640x480;
jplunkett 0:3f9d7ef7266c 88 _format = FMT_JPEG;
jplunkett 0:3f9d7ef7266c 89 _baud = DEFAULT_BAUD;
jplunkett 0:3f9d7ef7266c 90
jplunkett 0:3f9d7ef7266c 91 _dev_resolution = _resolution;
jplunkett 0:3f9d7ef7266c 92 _dev_format = _format;
jplunkett 0:3f9d7ef7266c 93 _dev_baud = _baud;
jplunkett 0:3f9d7ef7266c 94
jplunkett 0:3f9d7ef7266c 95 picture_length = 0;
jplunkett 0:3f9d7ef7266c 96 picture_data_id = 0;
jplunkett 0:3f9d7ef7266c 97 picture_data_id_count = 0;
jplunkett 0:3f9d7ef7266c 98 memset(picture_buffer, 0, sizeof(picture_buffer));
jplunkett 0:3f9d7ef7266c 99 picture_buffer_size_limit = sizeof(picture_buffer);
jplunkett 0:3f9d7ef7266c 100 picture_buffer_pos = 0;
jplunkett 0:3f9d7ef7266c 101 picture_buffer_size = 0;
jplunkett 0:3f9d7ef7266c 102
jplunkett 0:3f9d7ef7266c 103 memset(_read_buf, 0, sizeof(_read_buf));
jplunkett 0:3f9d7ef7266c 104 _read_buf_head = 0;
jplunkett 0:3f9d7ef7266c 105 _read_buf_tail = 0;
jplunkett 0:3f9d7ef7266c 106 _read_wake_pos = READ_WAKE_POS_INVALID;
jplunkett 1:06afc809909b 107 this->log_func = debug;
jplunkett 0:3f9d7ef7266c 108 }
jplunkett 0:3f9d7ef7266c 109
jplunkett 0:3f9d7ef7266c 110 CameraOV528::~CameraOV528()
jplunkett 0:3f9d7ef7266c 111 {
jplunkett 0:3f9d7ef7266c 112 powerdown();
jplunkett 0:3f9d7ef7266c 113 }
jplunkett 0:3f9d7ef7266c 114
jplunkett 1:06afc809909b 115 void CameraOV528::attach_debug_function(void (*func)(const char* fmt, ...))
jplunkett 1:06afc809909b 116 {
jplunkett 1:06afc809909b 117 this->log_func = func;
jplunkett 1:06afc809909b 118 }
jplunkett 1:06afc809909b 119
jplunkett 1:06afc809909b 120 int CameraOV528::camera_error(const char* message)
jplunkett 1:06afc809909b 121 {
jplunkett 1:06afc809909b 122 log_func("%s\r\n",message);
jplunkett 1:06afc809909b 123 return -1;
jplunkett 1:06afc809909b 124 }
jplunkett 1:06afc809909b 125
jplunkett 1:06afc809909b 126 int CameraOV528::powerup()
jplunkett 0:3f9d7ef7266c 127 {
jplunkett 0:3f9d7ef7266c 128 if (_init_done) {
jplunkett 1:06afc809909b 129 return 0;
jplunkett 0:3f9d7ef7266c 130 }
jplunkett 0:3f9d7ef7266c 131
jplunkett 0:3f9d7ef7266c 132 _serial.attach(this, &CameraOV528::_rx_irq, SerialBase::RxIrq);
jplunkett 0:3f9d7ef7266c 133
jplunkett 0:3f9d7ef7266c 134 // Attempt to connect at the desired baud
jplunkett 0:3f9d7ef7266c 135 _serial.baud(_baud);
jplunkett 0:3f9d7ef7266c 136 bool success = _init_sequence();
jplunkett 0:3f9d7ef7266c 137
jplunkett 0:3f9d7ef7266c 138 // If unsuccessful try with boot baud
jplunkett 0:3f9d7ef7266c 139 if (!success) {
jplunkett 0:3f9d7ef7266c 140 _serial.baud(BOOT_BAUD);
jplunkett 0:3f9d7ef7266c 141 success = _init_sequence();
jplunkett 0:3f9d7ef7266c 142 }
jplunkett 0:3f9d7ef7266c 143
jplunkett 0:3f9d7ef7266c 144 if (!success) {
jplunkett 1:06afc809909b 145 return camera_error("Unable to communicate with camera");
jplunkett 0:3f9d7ef7266c 146 }
jplunkett 0:3f9d7ef7266c 147
jplunkett 0:3f9d7ef7266c 148 // Acknowledge the SYNC read in _init_sequence with an ACK
jplunkett 0:3f9d7ef7266c 149 _send_ack(SYNC, 0, 0, 0);
jplunkett 0:3f9d7ef7266c 150 camera_printf("\nCamera initialization done.\r\n");
jplunkett 0:3f9d7ef7266c 151
jplunkett 0:3f9d7ef7266c 152 _set_baud(_baud);
jplunkett 0:3f9d7ef7266c 153
jplunkett 0:3f9d7ef7266c 154 _set_fmt_and_res(_format, _resolution);
jplunkett 0:3f9d7ef7266c 155 _set_package_size(picture_buffer_size_limit);
jplunkett 0:3f9d7ef7266c 156
jplunkett 0:3f9d7ef7266c 157 _init_done = false;
jplunkett 1:06afc809909b 158 return 0;
jplunkett 0:3f9d7ef7266c 159 }
jplunkett 0:3f9d7ef7266c 160
jplunkett 1:06afc809909b 161 int CameraOV528::powerup(uint32_t baud)
jplunkett 0:3f9d7ef7266c 162 {
jplunkett 0:3f9d7ef7266c 163 _baud = baud;
jplunkett 1:06afc809909b 164 return powerup();
jplunkett 0:3f9d7ef7266c 165 }
jplunkett 0:3f9d7ef7266c 166
jplunkett 1:06afc809909b 167 int CameraOV528::powerdown()
jplunkett 0:3f9d7ef7266c 168 {
jplunkett 0:3f9d7ef7266c 169 if (!_init_done) {
jplunkett 1:06afc809909b 170 return 0;
jplunkett 0:3f9d7ef7266c 171 }
jplunkett 0:3f9d7ef7266c 172
jplunkett 0:3f9d7ef7266c 173 if (!_send_cmd(POWER_DOWN, 0)) {
jplunkett 1:06afc809909b 174 return camera_error("Powerdown failed");
jplunkett 0:3f9d7ef7266c 175 }
jplunkett 0:3f9d7ef7266c 176
jplunkett 0:3f9d7ef7266c 177 // Reset picture transfer variables
jplunkett 0:3f9d7ef7266c 178 picture_length = 0;
jplunkett 0:3f9d7ef7266c 179 picture_data_id = 0;
jplunkett 0:3f9d7ef7266c 180 picture_data_id_count = 0;
jplunkett 0:3f9d7ef7266c 181 memset(picture_buffer, 0, sizeof(picture_buffer));
jplunkett 0:3f9d7ef7266c 182 picture_buffer_size_limit = sizeof(picture_buffer);
jplunkett 0:3f9d7ef7266c 183 picture_buffer_pos = 0;
jplunkett 0:3f9d7ef7266c 184 picture_buffer_size = 0;
jplunkett 0:3f9d7ef7266c 185
jplunkett 0:3f9d7ef7266c 186 _serial.attach(NULL, SerialBase::RxIrq);
jplunkett 0:3f9d7ef7266c 187 _flush_rx();
jplunkett 0:3f9d7ef7266c 188
jplunkett 0:3f9d7ef7266c 189 _init_done = false;
jplunkett 1:06afc809909b 190 return 0;
jplunkett 0:3f9d7ef7266c 191 }
jplunkett 0:3f9d7ef7266c 192
jplunkett 1:06afc809909b 193 int CameraOV528::take_picture(void)
jplunkett 0:3f9d7ef7266c 194 {
jplunkett 0:3f9d7ef7266c 195 // Ensure driver is powered up
jplunkett 0:3f9d7ef7266c 196 powerup();
jplunkett 0:3f9d7ef7266c 197
jplunkett 0:3f9d7ef7266c 198 // Update settings if any have changed
jplunkett 0:3f9d7ef7266c 199 if ((_dev_format != _format) || (_dev_resolution != _resolution)) {
jplunkett 0:3f9d7ef7266c 200 _set_fmt_and_res(_format, _resolution);
jplunkett 0:3f9d7ef7266c 201 _dev_format = _format;
jplunkett 0:3f9d7ef7266c 202 _dev_resolution = _resolution;
jplunkett 0:3f9d7ef7266c 203 }
jplunkett 0:3f9d7ef7266c 204
jplunkett 0:3f9d7ef7266c 205 // Take snapshot
jplunkett 0:3f9d7ef7266c 206 camera_printf("Taking snapshot\r\n");
jplunkett 0:3f9d7ef7266c 207 if (!_send_cmd(SNAPSHOT, 0)) {
jplunkett 1:06afc809909b 208 return camera_error("Take snapshot failed");
jplunkett 0:3f9d7ef7266c 209 }
jplunkett 0:3f9d7ef7266c 210
jplunkett 0:3f9d7ef7266c 211 // Start picture transfer
jplunkett 0:3f9d7ef7266c 212 camera_printf("Starting transfer\r\n");
jplunkett 0:3f9d7ef7266c 213 const GetSetting request = GET_JPEG_PREVIEW_PICTURE;
jplunkett 0:3f9d7ef7266c 214 if (!_send_cmd(GET_PICTURE, request)) {
jplunkett 1:06afc809909b 215 return camera_error("Get picture command failed");
jplunkett 0:3f9d7ef7266c 216 }
jplunkett 0:3f9d7ef7266c 217 camera_command_t resp = {0};
jplunkett 0:3f9d7ef7266c 218 uint32_t size_read = _read((uint8_t*)&resp, COMMAND_LENGTH, 1000);
jplunkett 0:3f9d7ef7266c 219 if (size_read != COMMAND_LENGTH) {
jplunkett 1:06afc809909b 220 return camera_error("Get picture response invalid");
jplunkett 0:3f9d7ef7266c 221 }
jplunkett 1:06afc809909b 222 if (resp.header != 0xAA) camera_error("Get picture response invalid sync");
jplunkett 1:06afc809909b 223 if (resp.command != DATA) camera_error("Get picture response invalid data");
jplunkett 1:06afc809909b 224 if (resp.param[0] != request) camera_error("Get picture response invalid content");
jplunkett 0:3f9d7ef7266c 225 picture_length = (resp.param[1] << 0) |
jplunkett 0:3f9d7ef7266c 226 (resp.param[2] << 8) |
jplunkett 0:3f9d7ef7266c 227 (resp.param[3] << 16);
jplunkett 0:3f9d7ef7266c 228 picture_data_id = 0;
jplunkett 0:3f9d7ef7266c 229 uint32_t payload_length = picture_buffer_size_limit - PIC_PAYLOAD_OVERHEAD;
jplunkett 0:3f9d7ef7266c 230 picture_data_id_count = divide_round_up(picture_length, payload_length);
jplunkett 1:06afc809909b 231 return 0;
jplunkett 0:3f9d7ef7266c 232 }
jplunkett 0:3f9d7ef7266c 233
jplunkett 0:3f9d7ef7266c 234 uint32_t CameraOV528::get_picture_size()
jplunkett 0:3f9d7ef7266c 235 {
jplunkett 0:3f9d7ef7266c 236 return picture_length;
jplunkett 0:3f9d7ef7266c 237 }
jplunkett 0:3f9d7ef7266c 238
jplunkett 0:3f9d7ef7266c 239 uint32_t CameraOV528::read_picture_data(uint8_t * data, uint32_t size)
jplunkett 0:3f9d7ef7266c 240 {
jplunkett 0:3f9d7ef7266c 241 uint32_t size_copied = 0;
jplunkett 0:3f9d7ef7266c 242 while (size_copied < size) {
jplunkett 0:3f9d7ef7266c 243
jplunkett 0:3f9d7ef7266c 244 // Copy any data in the picture buffer
jplunkett 0:3f9d7ef7266c 245 uint32_t size_left = size - size_copied;
jplunkett 0:3f9d7ef7266c 246 uint32_t copy_size = min(picture_buffer_size, size_left);
jplunkett 0:3f9d7ef7266c 247 memcpy(data + size_copied, picture_buffer + picture_buffer_pos, copy_size);
jplunkett 0:3f9d7ef7266c 248 picture_buffer_pos += copy_size;
jplunkett 0:3f9d7ef7266c 249 picture_buffer_size -= copy_size;
jplunkett 0:3f9d7ef7266c 250 size_copied += copy_size;
jplunkett 0:3f9d7ef7266c 251
jplunkett 0:3f9d7ef7266c 252 // If picture buffer is empty read more data
jplunkett 0:3f9d7ef7266c 253 if (0 == picture_buffer_size) {
jplunkett 0:3f9d7ef7266c 254 _read_picture_block();
jplunkett 0:3f9d7ef7266c 255 }
jplunkett 0:3f9d7ef7266c 256
jplunkett 0:3f9d7ef7266c 257 // If there is still no more data to read then break from loop
jplunkett 0:3f9d7ef7266c 258 if (0 == picture_buffer_size) {
jplunkett 0:3f9d7ef7266c 259 break;
jplunkett 0:3f9d7ef7266c 260 }
jplunkett 0:3f9d7ef7266c 261 }
jplunkett 0:3f9d7ef7266c 262
jplunkett 0:3f9d7ef7266c 263 return size_copied;
jplunkett 0:3f9d7ef7266c 264 }
jplunkett 0:3f9d7ef7266c 265
jplunkett 0:3f9d7ef7266c 266 void CameraOV528::set_resolution(CameraOV528::Resolution resolution)
jplunkett 0:3f9d7ef7266c 267 {
jplunkett 0:3f9d7ef7266c 268 const uint32_t count = sizeof(supported_resolutions) / sizeof(supported_resolutions[0]);
jplunkett 0:3f9d7ef7266c 269 bool valid_resolution = false;
jplunkett 0:3f9d7ef7266c 270 for (uint32_t i = 0; i < count; i++) {
jplunkett 0:3f9d7ef7266c 271 if (resolution == supported_resolutions[i]) {
jplunkett 0:3f9d7ef7266c 272 valid_resolution = true;
jplunkett 0:3f9d7ef7266c 273 break;
jplunkett 0:3f9d7ef7266c 274 }
jplunkett 0:3f9d7ef7266c 275 }
jplunkett 0:3f9d7ef7266c 276
jplunkett 0:3f9d7ef7266c 277 if (!valid_resolution) {
jplunkett 1:06afc809909b 278 camera_error("Invalid resolution");
jplunkett 0:3f9d7ef7266c 279 }
jplunkett 0:3f9d7ef7266c 280
jplunkett 0:3f9d7ef7266c 281 _resolution = resolution;
jplunkett 0:3f9d7ef7266c 282
jplunkett 0:3f9d7ef7266c 283 }
jplunkett 0:3f9d7ef7266c 284
jplunkett 0:3f9d7ef7266c 285 void CameraOV528::set_format(CameraOV528::Format format)
jplunkett 0:3f9d7ef7266c 286 {
jplunkett 0:3f9d7ef7266c 287 const uint32_t count = sizeof(supported_formats) / sizeof(supported_formats[0]);
jplunkett 0:3f9d7ef7266c 288 bool valid_format = false;
jplunkett 0:3f9d7ef7266c 289 for (uint32_t i = 0; i < count; i++) {
jplunkett 0:3f9d7ef7266c 290 if (format == supported_formats[i]) {
jplunkett 0:3f9d7ef7266c 291 valid_format = true;
jplunkett 0:3f9d7ef7266c 292 break;
jplunkett 0:3f9d7ef7266c 293 }
jplunkett 0:3f9d7ef7266c 294 }
jplunkett 0:3f9d7ef7266c 295
jplunkett 0:3f9d7ef7266c 296 if (!valid_format) {
jplunkett 1:06afc809909b 297 camera_error("Invalid format");
jplunkett 0:3f9d7ef7266c 298 }
jplunkett 0:3f9d7ef7266c 299
jplunkett 0:3f9d7ef7266c 300 _format = format;
jplunkett 0:3f9d7ef7266c 301 }
jplunkett 0:3f9d7ef7266c 302
jplunkett 0:3f9d7ef7266c 303 void CameraOV528::_set_baud(uint32_t baud)
jplunkett 0:3f9d7ef7266c 304 {
jplunkett 0:3f9d7ef7266c 305 // Baud Rate = 14.7456MHz/(2*(2nd divider +1))/(2*(1st divider+1))
jplunkett 0:3f9d7ef7266c 306 uint32_t div2 = 1;
jplunkett 0:3f9d7ef7266c 307 uint32_t div1 = PIC_CLOCK_HZ / _baud / (2 * (div2 + 1)) / 2 - 1;
jplunkett 0:3f9d7ef7266c 308 // Assert no rounding errors
jplunkett 0:3f9d7ef7266c 309 MBED_ASSERT(PIC_CLOCK_HZ / ( 2 * (div2 + 1) ) / ( 2 * (div1 + 1)) == _baud);
jplunkett 0:3f9d7ef7266c 310 if (!_send_cmd(SET_BAUD_RATE, div1, div2)) {
jplunkett 1:06afc809909b 311 camera_error("_set_baud failed");
jplunkett 0:3f9d7ef7266c 312 }
jplunkett 0:3f9d7ef7266c 313 _serial.baud(_baud);
jplunkett 0:3f9d7ef7266c 314 }
jplunkett 0:3f9d7ef7266c 315
jplunkett 0:3f9d7ef7266c 316 void CameraOV528::_set_package_size(uint32_t size)
jplunkett 0:3f9d7ef7266c 317 {
jplunkett 0:3f9d7ef7266c 318 camera_printf("_set_package_size(%lu)\r\n", size);
jplunkett 0:3f9d7ef7266c 319 uint8_t size_low = (size >> 0) & 0xff;
jplunkett 0:3f9d7ef7266c 320 uint8_t size_high = (size >> 8) & 0xff;
jplunkett 0:3f9d7ef7266c 321 if (!_send_cmd(SET_PACKAGE_SIZE, 0x08, size_low, size_high, 0)) {
jplunkett 1:06afc809909b 322 camera_error("_set_package_size failed");
jplunkett 0:3f9d7ef7266c 323 }
jplunkett 0:3f9d7ef7266c 324 }
jplunkett 0:3f9d7ef7266c 325
jplunkett 0:3f9d7ef7266c 326 void CameraOV528::_set_fmt_and_res(Format fmt, Resolution res)
jplunkett 0:3f9d7ef7266c 327 {
jplunkett 0:3f9d7ef7266c 328 if (!_send_cmd(INITIAL, 0x00, _format, 0x00, _resolution)) {
jplunkett 1:06afc809909b 329 camera_error("_set_fmt_and_res failed");
jplunkett 0:3f9d7ef7266c 330 }
jplunkett 0:3f9d7ef7266c 331 }
jplunkett 0:3f9d7ef7266c 332
jplunkett 1:06afc809909b 333 int CameraOV528::_read_picture_block()
jplunkett 0:3f9d7ef7266c 334 {
jplunkett 0:3f9d7ef7266c 335 const uint32_t payload_length = picture_buffer_size_limit - PIC_PAYLOAD_OVERHEAD;
jplunkett 0:3f9d7ef7266c 336 if (picture_data_id >= picture_data_id_count) {
jplunkett 0:3f9d7ef7266c 337 // Transfer complete
jplunkett 1:06afc809909b 338 return 0;
jplunkett 0:3f9d7ef7266c 339 }
jplunkett 0:3f9d7ef7266c 340
jplunkett 0:3f9d7ef7266c 341 // Send an ACK to indicate that the next block id should be sent
jplunkett 0:3f9d7ef7266c 342 uint8_t id_low = (picture_data_id >> 0) & 0xff;
jplunkett 0:3f9d7ef7266c 343 uint8_t id_high = (picture_data_id >> 8) & 0xff;
jplunkett 0:3f9d7ef7266c 344 _send_ack(0x00, 0x00, id_low, id_high);
jplunkett 0:3f9d7ef7266c 345
jplunkett 0:3f9d7ef7266c 346 // Read image data
jplunkett 0:3f9d7ef7266c 347 memset(picture_buffer, 0, sizeof(picture_buffer));
jplunkett 0:3f9d7ef7266c 348 uint32_t size_left = picture_length - payload_length * picture_data_id;
jplunkett 0:3f9d7ef7266c 349 uint32_t size_to_read = min(size_left, payload_length) + PIC_PAYLOAD_OVERHEAD;
jplunkett 0:3f9d7ef7266c 350 uint32_t size_read = _read(picture_buffer, size_to_read);
jplunkett 0:3f9d7ef7266c 351 if (size_read != size_to_read) {
jplunkett 1:06afc809909b 352 return camera_error("Image data protocol error");
jplunkett 0:3f9d7ef7266c 353 }
jplunkett 0:3f9d7ef7266c 354
jplunkett 0:3f9d7ef7266c 355 // Validate checksum
jplunkett 0:3f9d7ef7266c 356 uint8_t checksum = 0;
jplunkett 0:3f9d7ef7266c 357 for (uint32_t i = 0; i < size_read - 2; i++) {
jplunkett 0:3f9d7ef7266c 358 checksum += picture_buffer[i];
jplunkett 0:3f9d7ef7266c 359 }
jplunkett 0:3f9d7ef7266c 360 if (picture_buffer[size_read - 2] != checksum) {
jplunkett 1:06afc809909b 361 return camera_error("Image data checksum failure");
jplunkett 0:3f9d7ef7266c 362 }
jplunkett 0:3f9d7ef7266c 363
jplunkett 0:3f9d7ef7266c 364 // Update buffer information
jplunkett 0:3f9d7ef7266c 365 picture_buffer_pos = PIC_PAYLOAD_DATA_BEGIN;
jplunkett 0:3f9d7ef7266c 366 picture_buffer_size = size_read - PIC_PAYLOAD_OVERHEAD;
jplunkett 0:3f9d7ef7266c 367
jplunkett 0:3f9d7ef7266c 368 // If this is the last packet then send the completion ACK
jplunkett 0:3f9d7ef7266c 369 if (picture_data_id + 1 == picture_data_id_count) {
jplunkett 0:3f9d7ef7266c 370 _send_ack(0x00, 0x00, 0xF0, 0xF0);
jplunkett 0:3f9d7ef7266c 371 }
jplunkett 0:3f9d7ef7266c 372
jplunkett 0:3f9d7ef7266c 373 // Increment position
jplunkett 0:3f9d7ef7266c 374 camera_printf("%lu of %lu\r\n", picture_data_id + 1, picture_data_id_count);
jplunkett 0:3f9d7ef7266c 375 camera_printf("size left %lu\r\n",
jplunkett 0:3f9d7ef7266c 376 picture_length - payload_length * picture_data_id +
jplunkett 0:3f9d7ef7266c 377 PIC_PAYLOAD_OVERHEAD - size_read);
jplunkett 0:3f9d7ef7266c 378 picture_data_id++;
jplunkett 1:06afc809909b 379 return 0;
jplunkett 0:3f9d7ef7266c 380 }
jplunkett 0:3f9d7ef7266c 381
jplunkett 0:3f9d7ef7266c 382 void CameraOV528::_send_ack(uint8_t p1, uint8_t p2, uint8_t p3, uint8_t p4)
jplunkett 0:3f9d7ef7266c 383 {
jplunkett 0:3f9d7ef7266c 384 camera_command_t cmd = {0};
jplunkett 0:3f9d7ef7266c 385 cmd.header = 0xAA;
jplunkett 0:3f9d7ef7266c 386 cmd.command = ACK;
jplunkett 0:3f9d7ef7266c 387 cmd.param[0] = p1;
jplunkett 0:3f9d7ef7266c 388 cmd.param[1] = p2;
jplunkett 0:3f9d7ef7266c 389 cmd.param[2] = p3;
jplunkett 0:3f9d7ef7266c 390 cmd.param[3] = p4;
jplunkett 0:3f9d7ef7266c 391 _send((uint8_t*)&cmd, COMMAND_LENGTH);
jplunkett 0:3f9d7ef7266c 392 }
jplunkett 0:3f9d7ef7266c 393
jplunkett 0:3f9d7ef7266c 394 void CameraOV528::_rx_irq(void)
jplunkett 0:3f9d7ef7266c 395 {
jplunkett 0:3f9d7ef7266c 396 if(_serial.readable()) {
jplunkett 0:3f9d7ef7266c 397
jplunkett 0:3f9d7ef7266c 398 // Check for overflow
jplunkett 0:3f9d7ef7266c 399 if (_read_buf_head + 1 == _read_buf_tail) {
jplunkett 1:06afc809909b 400 camera_error("RX buffer overflow");
jplunkett 0:3f9d7ef7266c 401 }
jplunkett 0:3f9d7ef7266c 402
jplunkett 0:3f9d7ef7266c 403 // Add data
jplunkett 0:3f9d7ef7266c 404 _read_buf[_read_buf_head] = (uint8_t)_serial.getc();
jplunkett 0:3f9d7ef7266c 405 _read_buf_head = (_read_buf_head + 1) % sizeof(_read_buf);
jplunkett 0:3f9d7ef7266c 406
jplunkett 0:3f9d7ef7266c 407 // Check if thread should be woken
jplunkett 0:3f9d7ef7266c 408 if (_read_buf_head == _read_wake_pos) {
jplunkett 0:3f9d7ef7266c 409 _read_sem.release();
jplunkett 0:3f9d7ef7266c 410 _read_wake_pos = READ_WAKE_POS_INVALID;
jplunkett 0:3f9d7ef7266c 411 }
jplunkett 0:3f9d7ef7266c 412 }
jplunkett 0:3f9d7ef7266c 413 }
jplunkett 0:3f9d7ef7266c 414
jplunkett 0:3f9d7ef7266c 415 bool CameraOV528::_send(const uint8_t *data, uint32_t size, uint32_t timeout_ms)
jplunkett 0:3f9d7ef7266c 416 {
jplunkett 0:3f9d7ef7266c 417 for (uint32_t i = 0; i < size; i++) {
jplunkett 0:3f9d7ef7266c 418 _serial.putc(data[i]);
jplunkett 0:3f9d7ef7266c 419 }
jplunkett 0:3f9d7ef7266c 420 return true;
jplunkett 0:3f9d7ef7266c 421 }
jplunkett 0:3f9d7ef7266c 422
jplunkett 0:3f9d7ef7266c 423 uint32_t CameraOV528::_read(uint8_t *data, uint32_t size, uint32_t timeout_ms)
jplunkett 0:3f9d7ef7266c 424 {
jplunkett 0:3f9d7ef7266c 425 MBED_ASSERT(size < sizeof(_read_buf));
jplunkett 0:3f9d7ef7266c 426 MBED_ASSERT(0 == _read_sem.wait(0));
jplunkett 0:3f9d7ef7266c 427
jplunkett 0:3f9d7ef7266c 428 core_util_critical_section_enter();
jplunkett 0:3f9d7ef7266c 429
jplunkett 0:3f9d7ef7266c 430 // Atomically set wakeup condition
jplunkett 0:3f9d7ef7266c 431 uint32_t size_available = queue_used(_read_buf_head, _read_buf_tail, sizeof(_read_buf));
jplunkett 0:3f9d7ef7266c 432 if (size_available >= size) {
jplunkett 0:3f9d7ef7266c 433 _read_wake_pos = READ_WAKE_POS_INVALID;
jplunkett 0:3f9d7ef7266c 434 } else {
jplunkett 0:3f9d7ef7266c 435 _read_wake_pos = (_read_buf_tail + size) % sizeof(_read_buf);
jplunkett 0:3f9d7ef7266c 436 }
jplunkett 0:3f9d7ef7266c 437
jplunkett 0:3f9d7ef7266c 438 core_util_critical_section_exit();
jplunkett 0:3f9d7ef7266c 439
jplunkett 0:3f9d7ef7266c 440 // Wait until the requested number of bytes are available
jplunkett 0:3f9d7ef7266c 441 if (_read_wake_pos != READ_WAKE_POS_INVALID) {
jplunkett 0:3f9d7ef7266c 442 int32_t tokens = _read_sem.wait(timeout_ms);
jplunkett 0:3f9d7ef7266c 443 if (tokens <= 0) {
jplunkett 0:3f9d7ef7266c 444 // Timeout occurred so make sure semaphore is cleared
jplunkett 0:3f9d7ef7266c 445 _read_wake_pos = READ_WAKE_POS_INVALID;
jplunkett 0:3f9d7ef7266c 446 _read_sem.wait(0);
jplunkett 0:3f9d7ef7266c 447 } else {
jplunkett 0:3f9d7ef7266c 448 // If the semaphore was signaled then the requested number of
jplunkett 0:3f9d7ef7266c 449 // bytes were read
jplunkett 0:3f9d7ef7266c 450 MBED_ASSERT(queue_used(_read_buf_head, _read_buf_tail, sizeof(_read_buf)) >= size);
jplunkett 0:3f9d7ef7266c 451 }
jplunkett 0:3f9d7ef7266c 452 }
jplunkett 0:3f9d7ef7266c 453
jplunkett 0:3f9d7ef7266c 454 // Copy bytes
jplunkett 0:3f9d7ef7266c 455 size_available = queue_used(_read_buf_head, _read_buf_tail, sizeof(_read_buf));
jplunkett 0:3f9d7ef7266c 456 uint32_t read_size = min(size_available, size);
jplunkett 0:3f9d7ef7266c 457 for (uint32_t i = 0; i < read_size; i++) {
jplunkett 0:3f9d7ef7266c 458 data[i] = _read_buf[_read_buf_tail];
jplunkett 0:3f9d7ef7266c 459 _read_buf_tail = (_read_buf_tail + 1) % sizeof(_read_buf);
jplunkett 0:3f9d7ef7266c 460 }
jplunkett 0:3f9d7ef7266c 461
jplunkett 0:3f9d7ef7266c 462 return read_size;
jplunkett 0:3f9d7ef7266c 463 }
jplunkett 0:3f9d7ef7266c 464
jplunkett 0:3f9d7ef7266c 465
jplunkett 0:3f9d7ef7266c 466 void CameraOV528::_flush_rx(void)
jplunkett 0:3f9d7ef7266c 467 {
jplunkett 0:3f9d7ef7266c 468
jplunkett 0:3f9d7ef7266c 469 core_util_critical_section_enter();
jplunkett 0:3f9d7ef7266c 470 _read_buf_head = 0;
jplunkett 0:3f9d7ef7266c 471 _read_buf_tail = 0;
jplunkett 0:3f9d7ef7266c 472 _read_wake_pos = 0;
jplunkett 0:3f9d7ef7266c 473 core_util_critical_section_exit();
jplunkett 0:3f9d7ef7266c 474 }
jplunkett 0:3f9d7ef7266c 475
jplunkett 0:3f9d7ef7266c 476 bool CameraOV528::_send_cmd(uint8_t cmd, uint8_t p1, uint8_t p2, uint8_t p3, uint8_t p4)
jplunkett 0:3f9d7ef7266c 477 {
jplunkett 0:3f9d7ef7266c 478 _flush_rx();
jplunkett 0:3f9d7ef7266c 479
jplunkett 0:3f9d7ef7266c 480 camera_command_t command = {0};
jplunkett 0:3f9d7ef7266c 481 command.header = 0xAA;
jplunkett 0:3f9d7ef7266c 482 command.command = cmd;
jplunkett 0:3f9d7ef7266c 483 command.param[0] = p1;
jplunkett 0:3f9d7ef7266c 484 command.param[1] = p2;
jplunkett 0:3f9d7ef7266c 485 command.param[2] = p3;
jplunkett 0:3f9d7ef7266c 486 command.param[3] = p4;
jplunkett 0:3f9d7ef7266c 487 _send((uint8_t*)&command, COMMAND_LENGTH);
jplunkett 0:3f9d7ef7266c 488
jplunkett 0:3f9d7ef7266c 489 camera_command_t resp = {0};
jplunkett 0:3f9d7ef7266c 490 uint32_t len = _read((uint8_t*)&resp, COMMAND_LENGTH);
jplunkett 0:3f9d7ef7266c 491 if (COMMAND_LENGTH != len) {
jplunkett 0:3f9d7ef7266c 492 camera_printf("Wrong command response length %lu\r\n", len);
jplunkett 0:3f9d7ef7266c 493 }
jplunkett 0:3f9d7ef7266c 494 if ((resp.header != 0xAA) || (resp.command != ACK) || (resp.param[0] != command.command)) {
jplunkett 0:3f9d7ef7266c 495 camera_printf("Invalid command: %i, %i, %i\r\n", resp.header, resp.command, resp.param[0]);
jplunkett 0:3f9d7ef7266c 496 return false;
jplunkett 0:3f9d7ef7266c 497 }
jplunkett 0:3f9d7ef7266c 498 return true;
jplunkett 0:3f9d7ef7266c 499 }
jplunkett 0:3f9d7ef7266c 500
jplunkett 0:3f9d7ef7266c 501 bool CameraOV528::_init_sequence()
jplunkett 0:3f9d7ef7266c 502 {
jplunkett 0:3f9d7ef7266c 503 camera_printf("connecting to camera...");
jplunkett 0:3f9d7ef7266c 504 bool success = false;
jplunkett 0:3f9d7ef7266c 505 for (uint32_t i = 0; i < 4; i++) {
jplunkett 0:3f9d7ef7266c 506 camera_printf(".");
jplunkett 0:3f9d7ef7266c 507
jplunkett 0:3f9d7ef7266c 508 // Send SYNC command repeatedly
jplunkett 0:3f9d7ef7266c 509 if (!_send_cmd(SYNC, 0, 0, 0, 0)) {
jplunkett 0:3f9d7ef7266c 510 continue;
jplunkett 0:3f9d7ef7266c 511 }
jplunkett 0:3f9d7ef7266c 512 // Device should send back SYNC command
jplunkett 0:3f9d7ef7266c 513 camera_command_t resp = {0};
jplunkett 0:3f9d7ef7266c 514 if (_read((uint8_t*)&resp, COMMAND_LENGTH, 500) != COMMAND_LENGTH) {
jplunkett 0:3f9d7ef7266c 515 continue;
jplunkett 0:3f9d7ef7266c 516 }
jplunkett 0:3f9d7ef7266c 517 if (resp.header != 0xAA) continue;
jplunkett 0:3f9d7ef7266c 518 if (resp.command != SYNC) continue;
jplunkett 0:3f9d7ef7266c 519 if (resp.param[0] != 0) continue;
jplunkett 0:3f9d7ef7266c 520 if (resp.param[1] != 0) continue;
jplunkett 0:3f9d7ef7266c 521 if (resp.param[2] != 0) continue;
jplunkett 0:3f9d7ef7266c 522 if (resp.param[3] != 0) continue;
jplunkett 0:3f9d7ef7266c 523 success = true;
jplunkett 0:3f9d7ef7266c 524 break;
jplunkett 0:3f9d7ef7266c 525 }
jplunkett 0:3f9d7ef7266c 526 return success;
jplunkett 0:3f9d7ef7266c 527 }
jplunkett 0:3f9d7ef7266c 528
jplunkett 0:3f9d7ef7266c 529 static uint32_t divide_round_up(uint32_t dividen, uint32_t divisor)
jplunkett 0:3f9d7ef7266c 530 {
jplunkett 0:3f9d7ef7266c 531 return (dividen + divisor - 1) / divisor;
jplunkett 0:3f9d7ef7266c 532 }
jplunkett 0:3f9d7ef7266c 533
jplunkett 0:3f9d7ef7266c 534 static uint32_t min(uint32_t value1, uint32_t value2)
jplunkett 0:3f9d7ef7266c 535 {
jplunkett 0:3f9d7ef7266c 536 return value1 < value2 ? value1 : value2;
jplunkett 0:3f9d7ef7266c 537 }
jplunkett 0:3f9d7ef7266c 538
jplunkett 0:3f9d7ef7266c 539 static uint32_t queue_used(uint32_t head, uint32_t tail, uint32_t size)
jplunkett 0:3f9d7ef7266c 540 {
jplunkett 0:3f9d7ef7266c 541 if (head < tail) {
jplunkett 0:3f9d7ef7266c 542 return head + size - tail;
jplunkett 0:3f9d7ef7266c 543 } else {
jplunkett 0:3f9d7ef7266c 544 return head - tail;
jplunkett 0:3f9d7ef7266c 545 }
jplunkett 2:7a563410b23d 546 }