2017-08-19 02:38:41 +00:00
|
|
|
/*
|
|
|
|
* Registers by Arducam https://github.com/ArduCAM/Arduino/blob/master/ArduCAM/ov5640_regs.h
|
|
|
|
* https://github.com/ArduCAM/Arduino/blob/master/ArduCAM/ArduCAM.cpp
|
|
|
|
*/
|
|
|
|
|
2017-08-18 23:45:30 +00:00
|
|
|
#include "ch.h"
|
|
|
|
#include "hal.h"
|
|
|
|
#include "ov5640.h"
|
|
|
|
#include "pi2c.h"
|
|
|
|
#include "board.h"
|
|
|
|
#include "debug.h"
|
2017-08-21 03:00:23 +00:00
|
|
|
#include "ssdv.h"
|
2017-08-18 23:45:30 +00:00
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#define OV5640_I2C_ADR 0x3C
|
|
|
|
|
|
|
|
struct regval_list {
|
|
|
|
uint16_t reg;
|
|
|
|
uint8_t val;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct regval_list OV5640YUV_Sensor_Dvp_Init[] =
|
|
|
|
{
|
2017-08-21 01:51:03 +00:00
|
|
|
{ 0x4740, 0x04 },
|
2017-08-18 23:45:30 +00:00
|
|
|
|
|
|
|
{ 0x4050, 0x6e },
|
|
|
|
{ 0x4051, 0x8f },
|
|
|
|
|
|
|
|
{ 0x3008, 0x42 },
|
2017-09-11 04:45:19 +00:00
|
|
|
{ 0x3103, 0x03 },
|
2017-08-18 23:45:30 +00:00
|
|
|
{ 0x3017, 0x7f },
|
|
|
|
{ 0x3018, 0xff },
|
|
|
|
{ 0x302c, 0x02 },
|
2017-09-11 04:45:19 +00:00
|
|
|
{ 0x3108, 0x21 }, // PCLK root divider [5:4]
|
2017-08-18 23:45:30 +00:00
|
|
|
{ 0x3630, 0x2e },//2e
|
|
|
|
{ 0x3632, 0xe2 },
|
|
|
|
{ 0x3633, 0x23 },//23
|
|
|
|
{ 0x3621, 0xe0 },
|
|
|
|
{ 0x3704, 0xa0 },
|
|
|
|
{ 0x3703, 0x5a },
|
|
|
|
{ 0x3715, 0x78 },
|
|
|
|
{ 0x3717, 0x01 },
|
|
|
|
{ 0x370b, 0x60 },
|
|
|
|
{ 0x3705, 0x1a },
|
|
|
|
{ 0x3905, 0x02 },
|
|
|
|
{ 0x3906, 0x10 },
|
|
|
|
{ 0x3901, 0x0a },
|
|
|
|
{ 0x3731, 0x12 },
|
|
|
|
{ 0x3600, 0x08 },
|
|
|
|
{ 0x3601, 0x33 },
|
|
|
|
{ 0x302d, 0x60 },
|
|
|
|
{ 0x3620, 0x52 },
|
|
|
|
{ 0x371b, 0x20 },
|
|
|
|
{ 0x471c, 0x50 },
|
|
|
|
|
|
|
|
{ 0x3a18, 0x00 },
|
|
|
|
{ 0x3a19, 0xf8 },
|
|
|
|
|
|
|
|
{ 0x3635, 0x1c },//1c
|
|
|
|
{ 0x3634, 0x40 },
|
|
|
|
{ 0x3622, 0x01 },
|
|
|
|
|
|
|
|
{ 0x3c04, 0x28 },
|
|
|
|
{ 0x3c05, 0x98 },
|
|
|
|
{ 0x3c06, 0x00 },
|
|
|
|
{ 0x3c07, 0x08 },
|
|
|
|
{ 0x3c08, 0x00 },
|
|
|
|
{ 0x3c09, 0x1c },
|
|
|
|
{ 0x3c0a, 0x9c },
|
|
|
|
{ 0x3c0b, 0x40 },
|
|
|
|
|
2017-08-28 02:14:56 +00:00
|
|
|
{ 0x3820, 0x46 },
|
2017-08-18 23:45:30 +00:00
|
|
|
{ 0x3821, 0x01 }, //07
|
|
|
|
|
|
|
|
//windows setup
|
|
|
|
{ 0x3800, 0x00 },
|
|
|
|
{ 0x3801, 0x00 },
|
|
|
|
{ 0x3802, 0x00 },
|
|
|
|
{ 0x3803, 0x04 },
|
|
|
|
{ 0x3804, 0x0a },
|
|
|
|
{ 0x3805, 0x3f },
|
|
|
|
{ 0x3806, 0x07 },
|
|
|
|
{ 0x3807, 0x9b },
|
|
|
|
{ 0x3808, 0x05 },
|
|
|
|
{ 0x3809, 0x00 },
|
|
|
|
{ 0x380a, 0x03 },
|
|
|
|
{ 0x380b, 0xc0 },
|
|
|
|
{ 0x3810, 0x00 },
|
|
|
|
{ 0x3811, 0x10 },
|
|
|
|
{ 0x3812, 0x00 },
|
|
|
|
{ 0x3813, 0x06 },
|
|
|
|
{ 0x3814, 0x31 },
|
|
|
|
{ 0x3815, 0x31 },
|
|
|
|
|
2017-09-11 04:45:19 +00:00
|
|
|
{ 0x3034, 0x1a }, // PLL charge pump control [7:4]
|
|
|
|
{ 0x3035, 0x11 }, // System clock divider [7:4]
|
|
|
|
{ 0x3036, 0x46 }, // PLL multiplier [7:0]
|
|
|
|
{ 0x3037, 0x14 }, // PLL root divider [4], PLL pre-divider [3:0]
|
|
|
|
{ 0x3038, 0x00 }, // System control registers (changing not recommended)
|
|
|
|
{ 0x3039, 0x00 }, // PLL bypass [7]
|
2017-08-18 23:45:30 +00:00
|
|
|
|
|
|
|
{ 0x380c, 0x07 },
|
|
|
|
{ 0x380d, 0x68 },
|
|
|
|
{ 0x380e, 0x03 }, //03
|
|
|
|
{ 0x380f, 0xd8 }, //d8
|
|
|
|
|
|
|
|
{ 0x3c01, 0xb4 },
|
|
|
|
{ 0x3c00, 0x04 },
|
|
|
|
{ 0x3a08, 0x00 },
|
|
|
|
{ 0x3a09, 0x93 },
|
|
|
|
{ 0x3a0e, 0x06 },
|
|
|
|
{ 0x3a0a, 0x00 },
|
|
|
|
{ 0x3a0b, 0x7b },
|
|
|
|
{ 0x3a0d, 0x08 },
|
|
|
|
|
|
|
|
{ 0x3a00, 0x3c }, //15fps-10fps
|
|
|
|
{ 0x3a02, 0x05 },
|
|
|
|
{ 0x3a03, 0xc4 },
|
|
|
|
{ 0x3a14, 0x05 },
|
|
|
|
{ 0x3a15, 0xc4 },
|
|
|
|
|
|
|
|
{ 0x3618, 0x00 },
|
|
|
|
{ 0x3612, 0x29 },
|
|
|
|
{ 0x3708, 0x64 },
|
|
|
|
{ 0x3709, 0x52 },
|
|
|
|
{ 0x370c, 0x03 },
|
|
|
|
|
|
|
|
{ 0x4001, 0x02 },
|
|
|
|
{ 0x4004, 0x02 },
|
|
|
|
{ 0x3000, 0x00 },
|
|
|
|
{ 0x3002, 0x1c },
|
|
|
|
{ 0x3004, 0xff },
|
|
|
|
{ 0x3006, 0xc3 },
|
|
|
|
{ 0x300e, 0x58 },
|
|
|
|
{ 0x302e, 0x00 },
|
|
|
|
{ 0x4300, 0x30 },
|
|
|
|
{ 0x501f, 0x00 },
|
|
|
|
{ 0x4713, 0x03 },
|
2017-09-10 01:22:58 +00:00
|
|
|
{ 0x4404, 0x34 },
|
2017-08-18 23:45:30 +00:00
|
|
|
{ 0x4407, 0x04 },
|
|
|
|
{ 0x460b, 0x35 },
|
|
|
|
{ 0x460c, 0x22 },//add by bright
|
|
|
|
{ 0x3824, 0x01 },//add by bright
|
|
|
|
{ 0x5001, 0xa3 },
|
|
|
|
|
|
|
|
{ 0x3406, 0x01 },//awbinit
|
|
|
|
{ 0x3400, 0x06 },
|
|
|
|
{ 0x3401, 0x80 },
|
|
|
|
{ 0x3402, 0x04 },
|
|
|
|
{ 0x3403, 0x00 },
|
|
|
|
{ 0x3404, 0x06 },
|
|
|
|
{ 0x3405, 0x00 },
|
|
|
|
//awb
|
|
|
|
{ 0x5180, 0xff },
|
|
|
|
{ 0x5181, 0xf2 },
|
|
|
|
{ 0x5182, 0x00 },
|
|
|
|
{ 0x5183, 0x14 },
|
|
|
|
{ 0x5184, 0x25 },
|
|
|
|
{ 0x5185, 0x24 },
|
|
|
|
{ 0x5186, 0x16 },
|
|
|
|
{ 0x5187, 0x16 },
|
|
|
|
{ 0x5188, 0x16 },
|
|
|
|
{ 0x5189, 0x62 },
|
|
|
|
{ 0x518a, 0x62 },
|
|
|
|
{ 0x518b, 0xf0 },
|
|
|
|
{ 0x518c, 0xb2 },
|
|
|
|
{ 0x518d, 0x50 },
|
|
|
|
{ 0x518e, 0x30 },
|
|
|
|
{ 0x518f, 0x30 },
|
|
|
|
{ 0x5190, 0x50 },
|
|
|
|
{ 0x5191, 0xf8 },
|
|
|
|
{ 0x5192, 0x04 },
|
|
|
|
{ 0x5193, 0x70 },
|
|
|
|
{ 0x5194, 0xf0 },
|
|
|
|
{ 0x5195, 0xf0 },
|
|
|
|
{ 0x5196, 0x03 },
|
|
|
|
{ 0x5197, 0x01 },
|
|
|
|
{ 0x5198, 0x04 },
|
|
|
|
{ 0x5199, 0x12 },
|
|
|
|
{ 0x519a, 0x04 },
|
|
|
|
{ 0x519b, 0x00 },
|
|
|
|
{ 0x519c, 0x06 },
|
|
|
|
{ 0x519d, 0x82 },
|
|
|
|
{ 0x519e, 0x38 },
|
|
|
|
//color matrix
|
|
|
|
{ 0x5381, 0x1e },
|
|
|
|
{ 0x5382, 0x5b },
|
|
|
|
{ 0x5383, 0x14 },
|
|
|
|
{ 0x5384, 0x06 },
|
|
|
|
{ 0x5385, 0x82 },
|
|
|
|
{ 0x5386, 0x88 },
|
|
|
|
{ 0x5387, 0x7c },
|
|
|
|
{ 0x5388, 0x60 },
|
|
|
|
{ 0x5389, 0x1c },
|
|
|
|
{ 0x538a, 0x01 },
|
|
|
|
{ 0x538b, 0x98 },
|
|
|
|
//sharp&noise
|
|
|
|
{ 0x5300, 0x08 },
|
|
|
|
{ 0x5301, 0x30 },
|
|
|
|
{ 0x5302, 0x3f },
|
|
|
|
{ 0x5303, 0x10 },
|
|
|
|
{ 0x5304, 0x08 },
|
|
|
|
{ 0x5305, 0x30 },
|
|
|
|
{ 0x5306, 0x18 },
|
|
|
|
{ 0x5307, 0x28 },
|
|
|
|
{ 0x5309, 0x08 },
|
|
|
|
{ 0x530a, 0x30 },
|
|
|
|
{ 0x530b, 0x04 },
|
|
|
|
{ 0x530c, 0x06 },
|
|
|
|
//gamma
|
|
|
|
{ 0x5480, 0x01 },
|
|
|
|
{ 0x5481, 0x06 },
|
|
|
|
{ 0x5482, 0x12 },
|
|
|
|
{ 0x5483, 0x24 },
|
|
|
|
{ 0x5484, 0x4a },
|
|
|
|
{ 0x5485, 0x58 },
|
|
|
|
{ 0x5486, 0x65 },
|
|
|
|
{ 0x5487, 0x72 },
|
|
|
|
{ 0x5488, 0x7d },
|
|
|
|
{ 0x5489, 0x88 },
|
|
|
|
{ 0x548a, 0x92 },
|
|
|
|
{ 0x548b, 0xa3 },
|
|
|
|
{ 0x548c, 0xb2 },
|
|
|
|
{ 0x548d, 0xc8 },
|
|
|
|
{ 0x548e, 0xdd },
|
|
|
|
{ 0x548f, 0xf0 },
|
|
|
|
{ 0x5490, 0x15 },
|
|
|
|
//UV adjust
|
|
|
|
{ 0x5580, 0x06 },
|
|
|
|
{ 0x5583, 0x40 },
|
|
|
|
{ 0x5584, 0x20 },
|
|
|
|
{ 0x5589, 0x10 },
|
|
|
|
{ 0x558a, 0x00 },
|
|
|
|
{ 0x558b, 0xf8 },
|
|
|
|
//lens shading
|
|
|
|
{ 0x5000, 0xa7 },
|
|
|
|
{ 0x5800, 0x20 },
|
|
|
|
{ 0x5801, 0x19 },
|
|
|
|
{ 0x5802, 0x17 },
|
|
|
|
{ 0x5803, 0x16 },
|
|
|
|
{ 0x5804, 0x18 },
|
|
|
|
{ 0x5805, 0x21 },
|
|
|
|
{ 0x5806, 0x0F },
|
|
|
|
{ 0x5807, 0x0A },
|
|
|
|
{ 0x5808, 0x07 },
|
|
|
|
{ 0x5809, 0x07 },
|
|
|
|
{ 0x580a, 0x0A },
|
|
|
|
{ 0x580b, 0x0C },
|
|
|
|
{ 0x580c, 0x0A },
|
|
|
|
{ 0x580d, 0x03 },
|
|
|
|
{ 0x580e, 0x01 },
|
|
|
|
{ 0x580f, 0x01 },
|
|
|
|
{ 0x5810, 0x03 },
|
|
|
|
{ 0x5811, 0x09 },
|
|
|
|
{ 0x5812, 0x0A },
|
|
|
|
{ 0x5813, 0x03 },
|
|
|
|
{ 0x5814, 0x01 },
|
|
|
|
{ 0x5815, 0x01 },
|
|
|
|
{ 0x5816, 0x03 },
|
|
|
|
{ 0x5817, 0x08 },
|
|
|
|
{ 0x5818, 0x10 },
|
|
|
|
{ 0x5819, 0x0A },
|
|
|
|
{ 0x581a, 0x06 },
|
|
|
|
{ 0x581b, 0x06 },
|
|
|
|
{ 0x581c, 0x08 },
|
|
|
|
{ 0x581d, 0x0E },
|
|
|
|
{ 0x581e, 0x22 },
|
|
|
|
{ 0x581f, 0x18 },
|
|
|
|
{ 0x5820, 0x13 },
|
|
|
|
{ 0x5821, 0x12 },
|
|
|
|
{ 0x5822, 0x16 },
|
|
|
|
{ 0x5823, 0x1E },
|
|
|
|
{ 0x5824, 0x64 },
|
|
|
|
{ 0x5825, 0x2A },
|
|
|
|
{ 0x5826, 0x2C },
|
|
|
|
{ 0x5827, 0x2A },
|
|
|
|
{ 0x5828, 0x46 },
|
|
|
|
{ 0x5829, 0x2A },
|
|
|
|
{ 0x582a, 0x26 },
|
|
|
|
{ 0x582b, 0x24 },
|
|
|
|
{ 0x582c, 0x26 },
|
|
|
|
{ 0x582d, 0x2A },
|
|
|
|
{ 0x582e, 0x28 },
|
|
|
|
{ 0x582f, 0x42 },
|
|
|
|
{ 0x5830, 0x40 },
|
|
|
|
{ 0x5831, 0x42 },
|
|
|
|
{ 0x5832, 0x08 },
|
|
|
|
{ 0x5833, 0x28 },
|
|
|
|
{ 0x5834, 0x26 },
|
|
|
|
{ 0x5835, 0x24 },
|
|
|
|
{ 0x5836, 0x26 },
|
|
|
|
{ 0x5837, 0x2A },
|
|
|
|
{ 0x5838, 0x44 },
|
|
|
|
{ 0x5839, 0x4A },
|
|
|
|
{ 0x583a, 0x2C },
|
|
|
|
{ 0x583b, 0x2a },
|
|
|
|
{ 0x583c, 0x46 },
|
|
|
|
{ 0x583d, 0xCE },
|
|
|
|
|
|
|
|
{ 0x5688, 0x22 },
|
|
|
|
{ 0x5689, 0x22 },
|
|
|
|
{ 0x568a, 0x42 },
|
|
|
|
{ 0x568b, 0x24 },
|
|
|
|
{ 0x568c, 0x42 },
|
|
|
|
{ 0x568d, 0x24 },
|
|
|
|
{ 0x568e, 0x22 },
|
|
|
|
{ 0x568f, 0x22 },
|
|
|
|
|
|
|
|
{ 0x5025, 0x00 },
|
|
|
|
|
|
|
|
{ 0x3a0f, 0x30 },
|
|
|
|
{ 0x3a10, 0x28 },
|
|
|
|
{ 0x3a1b, 0x30 },
|
|
|
|
{ 0x3a1e, 0x28 },
|
|
|
|
{ 0x3a11, 0x61 },
|
|
|
|
{ 0x3a1f, 0x10 },
|
|
|
|
|
|
|
|
{ 0x4005, 0x1a },
|
|
|
|
{ 0x3406, 0x00 },//awbinit
|
|
|
|
{ 0x3503, 0x00 },//awbinit
|
|
|
|
{ 0x3008, 0x02 },
|
|
|
|
{ 0xffff, 0xff },
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static const struct regval_list ov5640_vga_preview[] =
|
|
|
|
{
|
|
|
|
// YUV VGA 30fps, night mode 5fps
|
|
|
|
// Input Clock = 24Mhz, PCLK = 56MHz
|
2017-08-20 12:33:46 +00:00
|
|
|
{ 0x3035, 0x11 }, // PLL
|
2017-08-18 23:45:30 +00:00
|
|
|
{ 0x3036, 0x46 }, // PLL
|
|
|
|
{ 0x3c07, 0x08 }, // light meter 1 threshold [7:0]
|
2017-08-28 02:14:56 +00:00
|
|
|
{ 0x3820, 0x46 }, // Sensor flip off, ISP flip on
|
2017-08-18 23:45:30 +00:00
|
|
|
{ 0x3821, 0x01 }, // Sensor mirror on, ISP mirror on, H binning on
|
|
|
|
{ 0x3814, 0x31 }, // X INC
|
|
|
|
{ 0x3815, 0x31 }, // Y INC
|
|
|
|
{ 0x3800, 0x00 }, // HS
|
|
|
|
{ 0x3801, 0x00 }, // HS
|
|
|
|
{ 0x3802, 0x00 }, // VS
|
|
|
|
{ 0x3803, 0x04 }, // VS
|
|
|
|
{ 0x3804, 0x0a }, // HW (HE)
|
|
|
|
{ 0x3805, 0x3f }, // HW (HE)
|
|
|
|
{ 0x3806, 0x07 }, // VH (VE)
|
|
|
|
{ 0x3807, 0x9b }, // VH (VE)
|
|
|
|
{ 0x3808, 0x02 }, // DVPHO
|
|
|
|
{ 0x3809, 0x80 }, // DVPHO
|
|
|
|
{ 0x380a, 0x01 }, // DVPVO
|
|
|
|
{ 0x380b, 0xe0 }, // DVPVO
|
|
|
|
{ 0x380c, 0x07 }, // HTS
|
|
|
|
{ 0x380d, 0x68 }, // HTS
|
|
|
|
{ 0x380e, 0x03 }, // VTS
|
|
|
|
{ 0x380f, 0xd8 }, // VTS
|
|
|
|
{ 0x3813, 0x06 }, // Timing Voffset
|
|
|
|
{ 0x3618, 0x00 },
|
|
|
|
{ 0x3612, 0x29 },
|
|
|
|
{ 0x3709, 0x52 },
|
|
|
|
{ 0x370c, 0x03 },
|
|
|
|
{ 0x3a02, 0x17 }, // 60Hz max exposure, night mode 5fps
|
|
|
|
{ 0x3a03, 0x10 }, // 60Hz max exposure
|
|
|
|
// banding filters are calculated automatically in camera driver
|
|
|
|
//{ 0x3a08, 0x01 }, // B50 step
|
|
|
|
//{ 0x3a09, 0x27 }, // B50 step
|
|
|
|
//{ 0x3a0a, 0x00 }, // B60 step
|
|
|
|
//{ 0x3a0b, 0xf6 }, // B60 step
|
|
|
|
//{ 0x3a0e, 0x03 }, // 50Hz max band
|
|
|
|
//{ 0x3a0d, 0x04 }, // 60Hz max band
|
|
|
|
{ 0x3a14, 0x17 }, // 50Hz max exposure, night mode 5fps
|
|
|
|
{ 0x3a15, 0x10 }, // 50Hz max exposure
|
|
|
|
{ 0x4004, 0x02 }, // BLC 2 lines
|
|
|
|
{ 0x3002, 0x1c }, // reset JFIFO, SFIFO, JPEG
|
|
|
|
{ 0x3006, 0xc3 }, // disable clock of JPEG2x, JPEG
|
|
|
|
{ 0x4713, 0x03 }, // JPEG mode 3
|
|
|
|
{ 0x4407, 0x04 }, // Quantization scale
|
|
|
|
{ 0x460b, 0x35 },
|
|
|
|
{ 0x460c, 0x22 },
|
|
|
|
{ 0x4837, 0x22 }, // DVP CLK divider
|
|
|
|
{ 0x3824, 0x02 }, // DVP CLK divider
|
|
|
|
{ 0x5001, 0xa3 }, // SDE on, scale on, UV average off, color matrix on, AWB on
|
|
|
|
{ 0x3503, 0x00 }, // AEC/AGC on
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct regval_list OV5640_RGB_QVGA[] =
|
|
|
|
{
|
|
|
|
{0x3008, 0x02},
|
2017-08-20 12:33:46 +00:00
|
|
|
{0x3035, 0x11},
|
2017-08-18 23:45:30 +00:00
|
|
|
{0x4740, 0x21},
|
|
|
|
{0x4300, 0x61},
|
|
|
|
{0x3808, 0x01},
|
|
|
|
{0x3809, 0x40},
|
|
|
|
{0x380a, 0x00},
|
|
|
|
{0x380b, 0xf0},
|
|
|
|
{0x501f, 0x01},
|
|
|
|
{0xffff, 0xff},
|
|
|
|
};
|
|
|
|
|
|
|
|
//2592x1944 QSXGA
|
|
|
|
static const struct regval_list OV5640_JPEG_QSXGA[] =
|
|
|
|
{
|
2017-08-28 02:14:56 +00:00
|
|
|
{0x3820 ,0x46},
|
|
|
|
{0x3821 ,0x20},
|
2017-08-18 23:45:30 +00:00
|
|
|
{0x3814 ,0x11},
|
|
|
|
{0x3815 ,0x11},
|
|
|
|
{0x3803 ,0x00},
|
|
|
|
{0x3807 ,0x9f},
|
|
|
|
{0x3808 ,0x0a},
|
|
|
|
{0x3809 ,0x20},
|
|
|
|
{0x380a ,0x07},
|
|
|
|
{0x380b ,0x98},
|
|
|
|
{0x380c ,0x0b},
|
|
|
|
{0x380d ,0x1c},
|
|
|
|
{0x380e ,0x07},
|
|
|
|
{0x380f ,0xb0},
|
|
|
|
{0x3813 ,0x04},
|
|
|
|
{0x3618 ,0x04},
|
|
|
|
{0x3612 ,0x4b},
|
|
|
|
{0x3708 ,0x64},
|
|
|
|
{0x3709 ,0x12},
|
|
|
|
{0x370c ,0x00},
|
|
|
|
{0x3a02 ,0x07},
|
|
|
|
{0x3a03 ,0xb0},
|
|
|
|
{0x3a0e ,0x06},
|
|
|
|
{0x3a0d ,0x08},
|
|
|
|
{0x3a14 ,0x07},
|
|
|
|
{0x3a15 ,0xb0},
|
|
|
|
{0x4001 ,0x02},
|
|
|
|
{0x4004 ,0x06},
|
|
|
|
{0x3002 ,0x00},
|
|
|
|
{0x3006 ,0xff},
|
|
|
|
{0x3824 ,0x04},
|
|
|
|
{0x5001 ,0x83},
|
|
|
|
{0x3036 ,0x69},
|
2017-09-08 14:28:01 +00:00
|
|
|
{0x3035 ,0x12},
|
2017-08-18 23:45:30 +00:00
|
|
|
{0x4005 ,0x1A},
|
|
|
|
{0xffff, 0xff},
|
|
|
|
};
|
|
|
|
|
|
|
|
//5MP
|
|
|
|
static const struct regval_list OV5640_5MP_JPEG[] =
|
|
|
|
{
|
|
|
|
{0x3800 ,0x00},
|
|
|
|
{0x3801 ,0x00},
|
|
|
|
{0x3802 ,0x00},
|
|
|
|
{0x3803 ,0x00},
|
|
|
|
{0x3804 ,0xA },
|
|
|
|
{0x3805 ,0x3f},
|
|
|
|
{0x3806 ,0x7 },
|
|
|
|
{0x3807 ,0x9f},
|
|
|
|
{0x3808 ,0xA },
|
|
|
|
{0x3809 ,0x20},
|
|
|
|
{0x380a ,0x7 },
|
|
|
|
{0x380b ,0x98},
|
|
|
|
{0x380c ,0xc },
|
|
|
|
{0x380d ,0x80},
|
|
|
|
{0x380e ,0x7 },
|
|
|
|
{0x380f ,0xd0},
|
|
|
|
{0x5001 ,0xa3},
|
|
|
|
{0x5680 ,0x0 },
|
|
|
|
{0x5681 ,0x0 },
|
|
|
|
{0x5682 ,0xA },
|
|
|
|
{0x5683 ,0x20},
|
|
|
|
{0x5684 ,0x0 },
|
|
|
|
{0x5685 ,0x0 },
|
|
|
|
{0x5686 ,0x7 },
|
|
|
|
{0x5687 ,0x98},
|
|
|
|
{0xffff, 0xff},
|
|
|
|
};
|
|
|
|
|
|
|
|
//320x240 QVGA
|
|
|
|
static const struct regval_list OV5640_QSXGA2QVGA[] =
|
|
|
|
{
|
2017-09-03 02:10:34 +00:00
|
|
|
{0x3800 ,0x00},
|
|
|
|
{0x3801 ,0x00},
|
|
|
|
{0x3802 ,0x00},
|
|
|
|
{0x3803 ,0x00},
|
|
|
|
{0x3804 ,0xA },
|
|
|
|
{0x3805 ,0x3f},
|
|
|
|
{0x3806 ,0x7 },
|
|
|
|
{0x3807 ,0x9f},
|
|
|
|
{0x3808 ,0x1 },
|
|
|
|
{0x3809 ,0x40},
|
|
|
|
{0x380a ,0x0 },
|
|
|
|
{0x380b ,0xf0},
|
|
|
|
{0x380c ,0xc },
|
|
|
|
{0x380d ,0x80},
|
|
|
|
{0x380e ,0x7 },
|
|
|
|
{0x380f ,0xd0},
|
|
|
|
{0x5001 ,0xa3},
|
|
|
|
{0x5680 ,0x0 },
|
|
|
|
{0x5681 ,0x0 },
|
|
|
|
{0x5682 ,0xA },
|
|
|
|
{0x5683 ,0x20},
|
|
|
|
{0x5684 ,0x0 },
|
|
|
|
{0x5685 ,0x0 },
|
|
|
|
{0x5686 ,0x7 },
|
|
|
|
{0x5687 ,0x98},
|
|
|
|
{0xffff, 0xff},
|
2017-08-18 23:45:30 +00:00
|
|
|
};
|
|
|
|
|
2017-09-06 23:53:32 +00:00
|
|
|
//320x240 QQVGA
|
|
|
|
static const struct regval_list OV5640_QSXGA2QQVGA[] =
|
|
|
|
{
|
|
|
|
{0x3800 ,0x00},
|
|
|
|
{0x3801 ,0x00},
|
|
|
|
{0x3802 ,0x00},
|
|
|
|
{0x3803 ,0x00},
|
|
|
|
{0x3804 ,0xA },
|
|
|
|
{0x3805 ,0x3f},
|
|
|
|
{0x3806 ,0x7 },
|
|
|
|
{0x3807 ,0x9f},
|
|
|
|
{0x3808 ,0x0 },
|
|
|
|
{0x3809 ,0xA0},
|
|
|
|
{0x380a ,0x0 },
|
|
|
|
{0x380b ,0x70},
|
|
|
|
{0x380c ,0xc },
|
|
|
|
{0x380d ,0x80},
|
|
|
|
{0x380e ,0x7 },
|
|
|
|
{0x380f ,0xd0},
|
|
|
|
{0x5001 ,0xa3},
|
|
|
|
{0x5680 ,0x0 },
|
|
|
|
{0x5681 ,0x0 },
|
|
|
|
{0x5682 ,0xA },
|
|
|
|
{0x5683 ,0x20},
|
|
|
|
{0x5684 ,0x0 },
|
|
|
|
{0x5685 ,0x0 },
|
|
|
|
{0x5686 ,0x7 },
|
|
|
|
{0x5687 ,0x98},
|
|
|
|
{0xffff, 0xff},
|
|
|
|
};
|
|
|
|
|
2017-08-18 23:45:30 +00:00
|
|
|
//640x480 VGA
|
|
|
|
static const struct regval_list OV5640_QSXGA2VGA[] =
|
|
|
|
{
|
2017-09-03 02:10:34 +00:00
|
|
|
{0x3800 ,0x00},
|
|
|
|
{0x3801 ,0x00},
|
|
|
|
{0x3802 ,0x00},
|
|
|
|
{0x3803 ,0x00},
|
|
|
|
{0x3804 ,0xA },
|
|
|
|
{0x3805 ,0x3f},
|
|
|
|
{0x3806 ,0x7 },
|
|
|
|
{0x3807 ,0x9f},
|
|
|
|
{0x3808 ,0x2 },
|
|
|
|
{0x3809 ,0x80},
|
|
|
|
{0x380a ,0x1 },
|
|
|
|
{0x380b ,0xe0},
|
|
|
|
{0x380c ,0xc },
|
|
|
|
{0x380d ,0x80},
|
|
|
|
{0x380e ,0x7 },
|
|
|
|
{0x380f ,0xd0},
|
|
|
|
{0x5001 ,0xa3},
|
|
|
|
{0x5680 ,0x0 },
|
|
|
|
{0x5681 ,0x0 },
|
|
|
|
{0x5682 ,0xA },
|
2017-08-18 23:45:30 +00:00
|
|
|
{0x5683 ,0x20},
|
|
|
|
{0x5684 ,0x0 },
|
2017-09-03 02:10:34 +00:00
|
|
|
{0x5685 ,0x0 },
|
|
|
|
{0x5686 ,0x7 },
|
|
|
|
{0x5687 ,0x98},
|
|
|
|
{0xffff, 0xff},
|
2017-08-18 23:45:30 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
//800x480 WVGA
|
|
|
|
static const struct regval_list OV5640_QSXGA2WVGA[] =
|
|
|
|
{
|
|
|
|
{0x3800 ,0x00},
|
|
|
|
{0x3801 ,0x00},
|
|
|
|
{0x3802 ,0x00},
|
|
|
|
{0x3803 ,0x00},
|
|
|
|
{0x3804 ,0xA },
|
|
|
|
{0x3805 ,0x3f},
|
|
|
|
{0x3806 ,0x7 },
|
|
|
|
{0x3807 ,0x9f},
|
|
|
|
{0x3808 ,0x3 },
|
|
|
|
{0x3809 ,0x20},
|
|
|
|
{0x380a ,0x1 },
|
|
|
|
{0x380b ,0xe0},
|
|
|
|
{0x380c ,0xc },
|
|
|
|
{0x380d ,0x80},
|
|
|
|
{0x380e ,0x7 },
|
|
|
|
{0x380f ,0xd0},
|
|
|
|
{0x3810, 0x00},
|
|
|
|
{0x3811, 0x10},
|
|
|
|
{0x3812, 0x01},
|
|
|
|
{0x3813, 0x48},
|
|
|
|
{0x5001 ,0xa3},
|
|
|
|
{0x5680 ,0x0 },
|
|
|
|
{0x5681 ,0x0 },
|
|
|
|
{0x5682 ,0xA },
|
|
|
|
{0x5683 ,0x20},
|
|
|
|
{0x5684 ,0x0 },
|
|
|
|
{0x5685 ,0x0 },
|
|
|
|
{0x5686 ,0x7 },
|
|
|
|
{0x5687 ,0x98},
|
|
|
|
{0xffff, 0xff},
|
|
|
|
};
|
|
|
|
|
|
|
|
//352x288 CIF
|
|
|
|
static const struct regval_list OV5640_QSXGA2CIF[] =
|
|
|
|
{
|
|
|
|
{0x3800 ,0x00},
|
|
|
|
{0x3801 ,0x00},
|
|
|
|
{0x3802 ,0x00},
|
|
|
|
{0x3803 ,0x00},
|
|
|
|
{0x3804 ,0xA },
|
|
|
|
{0x3805 ,0x3f},
|
|
|
|
{0x3806 ,0x7 },
|
|
|
|
{0x3807 ,0x9f},
|
|
|
|
{0x3808 ,0x1 },
|
|
|
|
{0x3809 ,0x60},
|
|
|
|
{0x380a ,0x1 },
|
|
|
|
{0x380b ,0x20},
|
|
|
|
{0x380c ,0xc },
|
|
|
|
{0x380d ,0x80},
|
|
|
|
{0x380e ,0x7 },
|
|
|
|
{0x380f ,0xd0},
|
|
|
|
{0x3810, 0x00},
|
|
|
|
{0x3811, 0x10},
|
|
|
|
{0x3812, 0x00},
|
|
|
|
{0x3813, 0x70},
|
|
|
|
{0x5001 ,0xa3},
|
|
|
|
{0x5680 ,0x0 },
|
|
|
|
{0x5681 ,0x0 },
|
|
|
|
{0x5682 ,0xA },
|
|
|
|
{0x5683 ,0x20},
|
|
|
|
{0x5684 ,0x0 },
|
|
|
|
{0x5685 ,0x0 },
|
|
|
|
{0x5686 ,0x7 },
|
|
|
|
{0x5687 ,0x98},
|
|
|
|
{0xffff, 0xff},
|
|
|
|
};
|
|
|
|
|
|
|
|
//1280x960 SXGA
|
|
|
|
static const struct regval_list OV5640_QSXGA2SXGA[] =
|
|
|
|
{
|
|
|
|
{0x3800 ,0x00},
|
|
|
|
{0x3801 ,0x00},
|
|
|
|
{0x3802 ,0x00},
|
|
|
|
{0x3803 ,0x00},
|
|
|
|
{0x3804 ,0xA },
|
|
|
|
{0x3805 ,0x3f},
|
|
|
|
{0x3806 ,0x7 },
|
|
|
|
{0x3807 ,0x9f},
|
|
|
|
{0x3808 ,0x5 },
|
|
|
|
{0x3809 ,0x0 },
|
|
|
|
{0x380a ,0x3 },
|
|
|
|
{0x380b ,0xc0},
|
|
|
|
{0x380c ,0xc },
|
|
|
|
{0x380d ,0x80},
|
|
|
|
{0x380e ,0x7 },
|
|
|
|
{0x380f ,0xd0},
|
|
|
|
{0x5001 ,0xa3},
|
|
|
|
{0x5680 ,0x0 },
|
|
|
|
{0x5681 ,0x0 },
|
|
|
|
{0x5682 ,0xA },
|
|
|
|
{0x5683 ,0x20},
|
|
|
|
{0x5684 ,0x0 },
|
|
|
|
{0x5685 ,0x0 },
|
|
|
|
{0x5686 ,0x7 },
|
|
|
|
{0x5687 ,0x98},
|
|
|
|
{0xffff, 0xff},
|
|
|
|
};
|
|
|
|
|
|
|
|
//2048x1536 QXGA
|
|
|
|
static const struct regval_list OV5640_QSXGA2QXGA[] =
|
|
|
|
{
|
|
|
|
{0x3800 ,0x00},
|
|
|
|
{0x3801 ,0x00},
|
|
|
|
{0x3802 ,0x00},
|
|
|
|
{0x3803 ,0x00},
|
|
|
|
{0x3804 ,0xA },
|
|
|
|
{0x3805 ,0x3f},
|
|
|
|
{0x3806 ,0x7 },
|
|
|
|
{0x3807 ,0x9f},
|
|
|
|
{0x3808 ,0x8 },
|
|
|
|
{0x3809 ,0x0 },
|
|
|
|
{0x380a ,0x6 },
|
|
|
|
{0x380b ,0x0 },
|
|
|
|
{0x380c ,0xc },
|
|
|
|
{0x380d ,0x80},
|
|
|
|
{0x380e ,0x7 },
|
|
|
|
{0x380f ,0xd0},
|
|
|
|
{0x5001 ,0xa3},
|
|
|
|
{0x5680 ,0x0 },
|
|
|
|
{0x5681 ,0x0 },
|
|
|
|
{0x5682 ,0xA },
|
|
|
|
{0x5683 ,0x20},
|
|
|
|
{0x5684 ,0x0 },
|
|
|
|
{0x5685 ,0x0 },
|
|
|
|
{0x5686 ,0x7 },
|
|
|
|
{0x5687 ,0x98},
|
|
|
|
{0xffff, 0xff},
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//1600x1200 UXGA
|
|
|
|
static const struct regval_list OV5640_QSXGA2UXGA[] =
|
|
|
|
{
|
|
|
|
{0x3800 ,0x00},
|
|
|
|
{0x3801 ,0x00},
|
|
|
|
{0x3802 ,0x00},
|
|
|
|
{0x3803 ,0x00},
|
|
|
|
{0x3804 ,0xA },
|
|
|
|
{0x3805 ,0x3f},
|
|
|
|
{0x3806 ,0x7 },
|
|
|
|
{0x3807 ,0x9f},
|
|
|
|
{0x3808 ,0x6 },
|
|
|
|
{0x3809 ,0x40},
|
|
|
|
{0x380a ,0x4 },
|
|
|
|
{0x380b ,0xb0},
|
|
|
|
{0x380c ,0xc },
|
|
|
|
{0x380d ,0x80},
|
|
|
|
{0x380e ,0x7 },
|
|
|
|
{0x380f ,0xd0},
|
|
|
|
{0x5001 ,0xa3},
|
|
|
|
{0x5680 ,0x0 },
|
|
|
|
{0x5681 ,0x0 },
|
|
|
|
{0x5682 ,0xA },
|
|
|
|
{0x5683 ,0x20},
|
|
|
|
{0x5684 ,0x0 },
|
|
|
|
{0x5685 ,0x0 },
|
|
|
|
{0x5686 ,0x7 },
|
|
|
|
{0x5687 ,0x98},
|
|
|
|
{0xffff, 0xff},
|
|
|
|
};
|
|
|
|
|
|
|
|
//1024x768 XGA
|
|
|
|
static const struct regval_list OV5640_QSXGA2XGA[] =
|
|
|
|
{
|
|
|
|
{0x3800 ,0x00},
|
|
|
|
{0x3801 ,0x00},
|
|
|
|
{0x3802 ,0x00},
|
|
|
|
{0x3803 ,0x00},
|
|
|
|
{0x3804 ,0xA },
|
|
|
|
{0x3805 ,0x3f},
|
|
|
|
{0x3806 ,0x7 },
|
|
|
|
{0x3807 ,0x9f},
|
|
|
|
{0x3808 ,0x4 },
|
|
|
|
{0x3809 ,0x0 },
|
|
|
|
{0x380a ,0x3 },
|
|
|
|
{0x380b ,0x0 },
|
|
|
|
{0x380c ,0xc },
|
|
|
|
{0x380d ,0x80},
|
|
|
|
{0x380e ,0x7 },
|
|
|
|
{0x380f ,0xd0},
|
|
|
|
{0x5001 ,0xa3},
|
|
|
|
{0x5680 ,0x0 },
|
|
|
|
{0x5681 ,0x0 },
|
|
|
|
{0x5682 ,0xA },
|
|
|
|
{0x5683 ,0x20},
|
|
|
|
{0x5684 ,0x0 },
|
|
|
|
{0x5685 ,0x0 },
|
|
|
|
{0x5686 ,0x7 },
|
|
|
|
{0x5687 ,0x98},
|
|
|
|
{0xffff, 0xff},
|
|
|
|
};
|
|
|
|
|
2017-09-10 01:22:58 +00:00
|
|
|
// TODO: Implement a state machine instead of multiple flags
|
2017-09-08 23:02:02 +00:00
|
|
|
static bool LptimRdy = false;
|
2017-08-19 09:51:15 +00:00
|
|
|
static bool capture_finished;
|
2017-08-19 01:36:34 +00:00
|
|
|
static bool vsync;
|
2017-08-23 08:10:29 +00:00
|
|
|
static bool dma_error;
|
|
|
|
static uint32_t dma_flags;
|
2017-08-18 23:45:30 +00:00
|
|
|
|
2017-09-10 01:22:58 +00:00
|
|
|
static uint8_t* dma_buffer;
|
|
|
|
|
2017-09-03 02:10:34 +00:00
|
|
|
static uint32_t oldSpeed;
|
|
|
|
static uint32_t oldWS;
|
|
|
|
|
2017-09-10 01:22:58 +00:00
|
|
|
/**
|
|
|
|
* Increase AHB clock to 48 MHz and saves the old speed
|
|
|
|
*/
|
2017-09-01 22:36:45 +00:00
|
|
|
void set48MHz(void)
|
|
|
|
{
|
2017-09-03 02:10:34 +00:00
|
|
|
oldSpeed = RCC->CFGR & RCC_CFGR_HPRE_Msk;
|
|
|
|
oldWS = FLASH->ACR & FLASH_ACR_LATENCY_Msk;
|
|
|
|
|
2017-09-01 22:36:45 +00:00
|
|
|
uint32_t new = (FLASH->ACR & ~FLASH_ACR_LATENCY_Msk) | FLASH_ACR_LATENCY_3WS;
|
|
|
|
FLASH->ACR = new;
|
|
|
|
while(FLASH->ACR != new);
|
|
|
|
|
|
|
|
new = (RCC->CFGR & ~RCC_CFGR_HPRE_Msk) | RCC_CFGR_HPRE_DIV1;
|
|
|
|
RCC->CFGR = new;
|
|
|
|
while(RCC->CFGR != new);
|
|
|
|
}
|
|
|
|
|
2017-09-10 01:22:58 +00:00
|
|
|
/**
|
|
|
|
* Reduce AHB clock back to the old speed which has been saved by set48MHz()
|
|
|
|
*/
|
2017-09-01 22:36:45 +00:00
|
|
|
void set6MHz(void)
|
|
|
|
{
|
2017-09-03 02:10:34 +00:00
|
|
|
uint32_t new = (RCC->CFGR & ~RCC_CFGR_HPRE_Msk) | oldSpeed;
|
2017-09-01 22:36:45 +00:00
|
|
|
RCC->CFGR = new;
|
|
|
|
while(RCC->CFGR != new);
|
|
|
|
|
2017-09-03 02:10:34 +00:00
|
|
|
new = (FLASH->ACR & ~FLASH_ACR_LATENCY_Msk) | oldWS;
|
2017-09-01 22:36:45 +00:00
|
|
|
FLASH->ACR = new;
|
|
|
|
while(FLASH->ACR != new);
|
|
|
|
}
|
|
|
|
|
2017-08-21 03:00:23 +00:00
|
|
|
/**
|
|
|
|
* Analyzes the image for JPEG errors. Returns true if the image is error free.
|
|
|
|
*/
|
|
|
|
static bool analyze_image(uint8_t *image, uint32_t image_len)
|
|
|
|
{
|
|
|
|
ssdv_t ssdv;
|
|
|
|
uint8_t pkt[SSDV_PKT_SIZE];
|
|
|
|
uint8_t *b;
|
|
|
|
uint32_t bi = 0;
|
|
|
|
uint8_t c = SSDV_OK;
|
|
|
|
|
2017-09-05 06:35:23 +00:00
|
|
|
ssdv_enc_init(&ssdv, SSDV_TYPE_NORMAL, "", 0, 7);
|
2017-08-21 03:00:23 +00:00
|
|
|
ssdv_enc_set_buffer(&ssdv, pkt);
|
|
|
|
|
2017-08-22 00:39:01 +00:00
|
|
|
while(true) // FIXME: I get caught in these loops occasionally and never return
|
2017-08-21 03:00:23 +00:00
|
|
|
{
|
|
|
|
while((c = ssdv_enc_get_packet(&ssdv)) == SSDV_FEED_ME)
|
|
|
|
{
|
|
|
|
b = &image[bi];
|
|
|
|
uint8_t r = bi < image_len-128 ? 128 : image_len - bi;
|
|
|
|
bi += r;
|
|
|
|
if(r <= 0)
|
2017-09-05 06:35:23 +00:00
|
|
|
{
|
|
|
|
TRACE_ERROR("CAM > Error in image");
|
2017-08-30 03:29:59 +00:00
|
|
|
return false;
|
2017-09-05 06:35:23 +00:00
|
|
|
}
|
2017-08-21 03:00:23 +00:00
|
|
|
ssdv_enc_feed(&ssdv, b, r);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(c == SSDV_EOI) // End of image
|
|
|
|
return true;
|
|
|
|
if(c != SSDV_OK) // Error in JPEG image
|
2017-09-05 06:35:23 +00:00
|
|
|
{
|
|
|
|
TRACE_ERROR("CAM > Error in image");
|
2017-08-21 03:00:23 +00:00
|
|
|
return false;
|
2017-09-05 06:35:23 +00:00
|
|
|
}
|
2017-09-02 01:24:10 +00:00
|
|
|
|
2017-09-05 06:35:23 +00:00
|
|
|
chThdSleepMilliseconds(5);
|
2017-08-21 03:00:23 +00:00
|
|
|
}
|
2017-08-22 00:39:01 +00:00
|
|
|
}
|
2017-08-21 03:00:23 +00:00
|
|
|
|
2017-08-18 23:45:30 +00:00
|
|
|
/**
|
|
|
|
* Captures an image from the camera.
|
2017-09-10 01:22:58 +00:00
|
|
|
* @buffer Buffer in which the image can be sampled
|
|
|
|
* @size Size of buffer
|
|
|
|
* @res Resolution of the image
|
|
|
|
* If resolution MAX_RES has been chosen, a highest resolution will be chosen
|
|
|
|
* which it suitable for the amount of buffer. Due to the JPEG compression
|
|
|
|
* that could lead to different resolutions on different method calls.
|
|
|
|
* The method returns the size of the image.
|
2017-08-18 23:45:30 +00:00
|
|
|
*/
|
2017-09-10 01:22:58 +00:00
|
|
|
uint32_t OV5640_Snapshot2RAM(uint8_t* buffer, uint32_t size, resolution_t res, bool enableJpegValidation)
|
2017-08-18 23:45:30 +00:00
|
|
|
{
|
2017-09-11 04:45:19 +00:00
|
|
|
uint8_t cntr = 10;
|
2017-08-30 03:29:59 +00:00
|
|
|
bool status;
|
2017-09-08 14:28:01 +00:00
|
|
|
bool jpegValid;
|
2017-09-10 01:22:58 +00:00
|
|
|
uint32_t size_sampled;
|
|
|
|
|
|
|
|
// Set resoultion
|
|
|
|
if(res == RES_MAX)
|
|
|
|
{
|
|
|
|
OV5640_SetResolution(RES_UXGA); // FIXME: We actually have to choose the resolution which fits in the memory
|
|
|
|
} else {
|
|
|
|
OV5640_SetResolution(res);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Capture image until we get a good image (max 10 tries)
|
2017-08-21 03:00:23 +00:00
|
|
|
do {
|
2017-09-10 01:22:58 +00:00
|
|
|
// Clearing buffer
|
|
|
|
uint32_t i;
|
|
|
|
for(i=0; i<size; i++)
|
|
|
|
buffer[i] = 0;
|
2017-08-22 00:39:01 +00:00
|
|
|
|
2017-08-21 03:00:23 +00:00
|
|
|
TRACE_INFO("CAM > Capture image");
|
2017-09-10 01:22:58 +00:00
|
|
|
status = OV5640_Capture(buffer, size);
|
2017-08-22 00:39:01 +00:00
|
|
|
TRACE_INFO("CAM > Capture finished");
|
|
|
|
|
2017-09-10 01:22:58 +00:00
|
|
|
size_sampled = size - 1;
|
|
|
|
while(!buffer[size_sampled] && size_sampled > 0)
|
|
|
|
size_sampled--;
|
2017-08-22 00:39:01 +00:00
|
|
|
|
2017-09-10 01:22:58 +00:00
|
|
|
TRACE_INFO("CAM > Image size: %d bytes", size_sampled);
|
|
|
|
|
|
|
|
// Validate JPEG image
|
|
|
|
if(enableJpegValidation)
|
|
|
|
{
|
|
|
|
TRACE_INFO("CAM > Validate integrity of JPEG");
|
|
|
|
jpegValid = analyze_image(buffer, size);
|
|
|
|
TRACE_INFO("CAM > JPEG image %s", jpegValid ? "valid" : "invalid");
|
|
|
|
} else {
|
|
|
|
jpegValid = true;
|
|
|
|
}
|
2017-08-22 00:39:01 +00:00
|
|
|
|
2017-09-08 14:28:01 +00:00
|
|
|
} while((!jpegValid || !status) && cntr--);
|
2017-08-18 23:45:30 +00:00
|
|
|
|
2017-09-10 01:22:58 +00:00
|
|
|
return size_sampled;
|
2017-08-18 23:45:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const stm32_dma_stream_t *dmastp;
|
|
|
|
|
2017-08-21 11:23:55 +00:00
|
|
|
#if OV5640_USE_DMA_DBM == TRUE
|
|
|
|
uint16_t dma_index;
|
|
|
|
uint16_t dma_buffers;
|
|
|
|
#define DMA_SEGMENT_SIZE 1024
|
|
|
|
#define DMA_FIFO_BURST_ALIGN 32
|
|
|
|
|
|
|
|
|
|
|
|
#if !defined(dmaStreamGetCurrentTarget)
|
|
|
|
/**
|
|
|
|
* @brief Get DMA stream current target.
|
|
|
|
* @note This function can be invoked in both ISR or thread context.
|
|
|
|
* @pre The stream must have been allocated using @p dmaStreamAllocate().
|
|
|
|
* @post After use the stream can be released using @p dmaStreamRelease().
|
|
|
|
*
|
|
|
|
* @param[in] dmastp pointer to a stm32_dma_stream_t structure
|
|
|
|
* @return Current target index
|
|
|
|
*
|
|
|
|
* @special
|
|
|
|
*/
|
|
|
|
#define dmaStreamGetCurrentTarget(dmastp) \
|
|
|
|
((uint8_t)(((dmastp)->stream->CR >> DMA_SxCR_CT_Pos) & 1U))
|
|
|
|
|
|
|
|
#endif /* !defined(dmaStreamGetCurrentTarget) */
|
|
|
|
#endif /* OV5640_USE_DMA_DBM == TRUE */
|
|
|
|
|
2017-08-18 23:45:30 +00:00
|
|
|
inline int32_t dma_start(void) {
|
2017-08-19 09:51:15 +00:00
|
|
|
/* Clear any pending interrupts. */
|
2017-08-18 23:45:30 +00:00
|
|
|
dmaStreamClearInterrupt(dmastp);
|
2017-08-19 09:51:15 +00:00
|
|
|
dmaStreamEnable(dmastp);
|
|
|
|
return 0;
|
2017-08-18 23:45:30 +00:00
|
|
|
}
|
|
|
|
|
2017-08-19 09:51:15 +00:00
|
|
|
/*
|
|
|
|
* Stop DMA release stream and return count remaining.
|
|
|
|
* Note that any DMA FIFO transfer will complete.
|
|
|
|
* The Chibios DMAV2 driver waits for EN to clear before proceeding.
|
|
|
|
*/
|
|
|
|
inline uint16_t dma_stop(void) {
|
2017-08-18 23:45:30 +00:00
|
|
|
dmaStreamDisable(dmastp);
|
2017-08-19 09:51:15 +00:00
|
|
|
uint16_t transfer = dmaStreamGetTransactionSize(dmastp);
|
2017-08-18 23:45:30 +00:00
|
|
|
dmaStreamRelease(dmastp);
|
2017-08-19 09:51:15 +00:00
|
|
|
return transfer;
|
2017-08-18 23:45:30 +00:00
|
|
|
}
|
|
|
|
|
2017-08-21 11:23:55 +00:00
|
|
|
#if OV5640_USE_DMA_DBM == TRUE
|
|
|
|
|
2017-08-18 23:45:30 +00:00
|
|
|
static void dma_interrupt(void *p, uint32_t flags) {
|
2017-08-21 11:23:55 +00:00
|
|
|
/* No parameter passed. */
|
|
|
|
(void)p;
|
|
|
|
|
2017-08-23 08:10:29 +00:00
|
|
|
dma_flags = flags;
|
2017-08-21 11:23:55 +00:00
|
|
|
if (flags & (STM32_DMA_ISR_FEIF | STM32_DMA_ISR_TEIF)) {
|
|
|
|
/*
|
|
|
|
* DMA transfer error or FIFO error.
|
|
|
|
* See 9.34.19 of RM0430.
|
2017-08-23 08:10:29 +00:00
|
|
|
*
|
|
|
|
* Disable timer DMA request and flag fault.
|
2017-08-21 11:23:55 +00:00
|
|
|
*/
|
|
|
|
TIM1->DIER &= ~TIM_DIER_TDE;
|
2017-08-23 08:10:29 +00:00
|
|
|
dma_error = true;
|
|
|
|
dmaStreamClearInterrupt(dmastp);
|
2017-08-21 11:23:55 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & STM32_DMA_ISR_HTIF) {
|
|
|
|
/*
|
|
|
|
* Half transfer complete.
|
|
|
|
* Check if DMA is writing to the last buffer.
|
|
|
|
*/
|
|
|
|
if (dma_index == (dma_buffers - 1)) {
|
|
|
|
/*
|
|
|
|
* This is the last buffer so we have to terminate DMA.
|
|
|
|
* The DBM switch is done in h/w.
|
|
|
|
* DMA could write beyond total buffer if not stopped.
|
|
|
|
*
|
2017-08-23 08:10:29 +00:00
|
|
|
* Since this is the last DMA buffer this is treated as an error.
|
2017-08-21 11:23:55 +00:00
|
|
|
* The DMA should normally be terminated by VSYNC before last buffer.
|
|
|
|
* Stop DMA and TIM DMA trigger and flag error.
|
|
|
|
*/
|
|
|
|
|
|
|
|
TIM1->DIER &= ~TIM_DIER_TDE;
|
2017-08-23 08:10:29 +00:00
|
|
|
dma_error = true;
|
|
|
|
dmaStreamClearInterrupt(dmastp);
|
2017-08-21 11:23:55 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Else Safe to allow buffer to fill.
|
|
|
|
* DMA DBM will switch buffers in h/w when this one is full.
|
|
|
|
* Just clear the interrupt and wait for TCIF.
|
|
|
|
*/
|
|
|
|
dmaStreamClearInterrupt(dmastp);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (flags & STM32_DMA_ISR_TCIF) {
|
|
|
|
/*
|
|
|
|
* Full buffer transfer complete.
|
|
|
|
* Update non-active memory address register.
|
|
|
|
* DMA will use new address at h/w DBM switch.
|
|
|
|
*/
|
2017-08-23 08:10:29 +00:00
|
|
|
|
2017-08-21 11:23:55 +00:00
|
|
|
|
|
|
|
if (dmaStreamGetCurrentTarget(dmastp) == 1) {
|
2017-09-10 01:22:58 +00:00
|
|
|
dmaStreamSetMemory0(dmastp, &dma_buffer[++dma_index * DMA_SEGMENT_SIZE]);
|
2017-08-21 11:23:55 +00:00
|
|
|
} else {
|
2017-09-10 01:22:58 +00:00
|
|
|
dmaStreamSetMemory1(dmastp, &dma_buffer[++dma_index * DMA_SEGMENT_SIZE]);
|
2017-08-21 11:23:55 +00:00
|
|
|
}
|
2017-08-23 08:10:29 +00:00
|
|
|
dmaStreamClearInterrupt(dmastp);
|
2017-08-21 11:23:55 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2017-08-18 23:45:30 +00:00
|
|
|
|
2017-08-21 11:23:55 +00:00
|
|
|
#else
|
2017-08-18 23:45:30 +00:00
|
|
|
|
2017-08-21 11:23:55 +00:00
|
|
|
static void dma_interrupt(void *p, uint32_t flags) {
|
|
|
|
(void)p;
|
|
|
|
|
2017-08-23 08:10:29 +00:00
|
|
|
dma_flags = flags;
|
|
|
|
dmaStreamClearInterrupt(dmastp);
|
|
|
|
if (flags & (STM32_DMA_ISR_FEIF | STM32_DMA_ISR_TEIF } STM32_DMA_ISR_DMEIF)) {
|
2017-08-21 11:23:55 +00:00
|
|
|
/*
|
2017-08-23 08:10:29 +00:00
|
|
|
* DMA transfer error, FIFO error or Direct mode error.
|
2017-08-21 11:23:55 +00:00
|
|
|
* See 9.34.19 of RM0430.
|
|
|
|
*/
|
|
|
|
dmaStreamClearInterrupt(dmastp);
|
|
|
|
TIM1->DIER &= ~TIM_DIER_TDE;
|
2017-08-23 08:10:29 +00:00
|
|
|
dma_error = true;
|
2017-08-21 11:23:55 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((flags & STM32_DMA_ISR_TCIF) != 0) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If DMA has run to end within a frame then this is an error.
|
|
|
|
* In single buffer mode DMA should always be terminated by VSYNC.
|
|
|
|
*
|
|
|
|
* Stop PCLK from LPTIM1 and disable TIM1 DMA trigger.
|
2017-08-20 03:22:16 +00:00
|
|
|
* Dont stop the DMA here. Its going to be stopped by the leading edge of VSYNC.
|
2017-08-21 11:23:55 +00:00
|
|
|
*/
|
|
|
|
TIM1->DIER &= ~TIM_DIER_TDE;
|
|
|
|
LPTIM1->CR &= ~LPTIM_CR_CNTSTRT;
|
2017-08-23 08:10:29 +00:00
|
|
|
dma_error = true;
|
2017-08-21 11:23:55 +00:00
|
|
|
return;
|
|
|
|
}
|
2017-08-18 23:45:30 +00:00
|
|
|
}
|
|
|
|
|
2017-08-21 11:23:55 +00:00
|
|
|
#endif /* USE_OV5640_DMA_DBM */
|
2017-08-18 23:45:30 +00:00
|
|
|
/*
|
|
|
|
* The LPTIM interrupt handler.
|
2017-08-23 08:10:29 +00:00
|
|
|
* TODO: Remove LPTIM1 interrupt.
|
|
|
|
* Not needed in COUNTMODE.
|
|
|
|
* LPTIM clock kernel initialises in 2 internal clock cycles
|
2017-08-18 23:45:30 +00:00
|
|
|
*/
|
|
|
|
OSAL_IRQ_HANDLER(STM32_LPTIM1_HANDLER) {
|
|
|
|
|
|
|
|
/* Note:
|
2017-08-21 11:23:55 +00:00
|
|
|
* LPTIM1 is vector 97.
|
|
|
|
* Check CORTEX_NUM_PARAMS in cmparams.h >= 106.
|
|
|
|
* Vector table is expanded in increments of 8.
|
2017-08-18 23:45:30 +00:00
|
|
|
*/
|
|
|
|
OSAL_IRQ_PROLOGUE();
|
|
|
|
/* Reset interrupt flag for ARR. */
|
|
|
|
LPTIM1->ICR = LPTIM_ICR_ARRMCF;
|
|
|
|
/*
|
|
|
|
* LPTIM interrupts can be disabled at this stage.
|
|
|
|
* We don't need this interrupt again until a new capture is started.
|
|
|
|
*/
|
|
|
|
LPTIM1->IER &= ~LPTIM_IER_ARRMIE;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The first interrupt indicates LPTIM core has been initialized by PCLK.
|
|
|
|
* This flag is used to synchronise capture start.
|
|
|
|
* If on leading edge of VSYNC lptim_rdy is true then capture can start.
|
|
|
|
* If not wait for the next VSYNC.
|
|
|
|
* This is needed because of LPTIM core setup requirement when clocked externally.
|
|
|
|
*/
|
|
|
|
LptimRdy = true;
|
|
|
|
|
|
|
|
OSAL_IRQ_EPILOGUE();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-08-21 11:23:55 +00:00
|
|
|
* VSYNC is asserted during a frame.
|
|
|
|
* See OV5640 datasheet for details.
|
|
|
|
*/
|
2017-08-18 23:45:30 +00:00
|
|
|
CH_IRQ_HANDLER(Vector5C) {
|
|
|
|
CH_IRQ_PROLOGUE();
|
|
|
|
|
|
|
|
if (LptimRdy) {
|
|
|
|
// VSYNC handling
|
|
|
|
if(!vsync) {
|
2017-09-01 00:02:30 +00:00
|
|
|
// Increase AHB clock to 48 MHz
|
2017-09-01 22:36:45 +00:00
|
|
|
set48MHz();
|
Finalized clockling (so far) for power savings.
All dividers for all clocks are static except for HPRE.
HPRE is dynamically changed between /1 and /8. It is usually set to /8.
If the camera is capturing the image, it is set to /1. This is necessary
while the sampling method needs a to sample the fast data from the camera.
After capture, the prescaler is switched back to /8.
HPRE will affect the speed of AHB1 and AHB2. Both have the same speed.
At image capture, both are running at 48Mhz and 6Mhz at all other times.
The clock change has a drastic effect of the power consumption.
--------------------------------------------------
Running at 1.8V
Position packet transmission, APRS AFSK, one packet every 1min (GPS off)
Image transmission, APRS AFSK, one packet every 20sec, redundant TX
=> average consumption 55mW
--------------------------------------------------
Running at 1.8V
Position packet transmission, APRS AFSK, one packet every 1min (GPS off)
=> average consumption 34mW
2017-08-30 23:27:09 +00:00
|
|
|
|
2017-08-18 23:45:30 +00:00
|
|
|
/*
|
2017-08-19 09:51:15 +00:00
|
|
|
* Rising edge of VSYNC after LPTIM1 has been initialised.
|
2017-08-18 23:45:30 +00:00
|
|
|
* Start DMA channel.
|
|
|
|
* Enable TIM1 trigger of DMA.
|
|
|
|
*/
|
|
|
|
dma_start();
|
|
|
|
TIM1->DIER |= TIM_DIER_TDE;
|
|
|
|
vsync = true;
|
|
|
|
} else {
|
Finalized clockling (so far) for power savings.
All dividers for all clocks are static except for HPRE.
HPRE is dynamically changed between /1 and /8. It is usually set to /8.
If the camera is capturing the image, it is set to /1. This is necessary
while the sampling method needs a to sample the fast data from the camera.
After capture, the prescaler is switched back to /8.
HPRE will affect the speed of AHB1 and AHB2. Both have the same speed.
At image capture, both are running at 48Mhz and 6Mhz at all other times.
The clock change has a drastic effect of the power consumption.
--------------------------------------------------
Running at 1.8V
Position packet transmission, APRS AFSK, one packet every 1min (GPS off)
Image transmission, APRS AFSK, one packet every 20sec, redundant TX
=> average consumption 55mW
--------------------------------------------------
Running at 1.8V
Position packet transmission, APRS AFSK, one packet every 1min (GPS off)
=> average consumption 34mW
2017-08-30 23:27:09 +00:00
|
|
|
// Reduce AHB clock to 6 MHz
|
2017-09-01 22:36:45 +00:00
|
|
|
set6MHz();
|
Finalized clockling (so far) for power savings.
All dividers for all clocks are static except for HPRE.
HPRE is dynamically changed between /1 and /8. It is usually set to /8.
If the camera is capturing the image, it is set to /1. This is necessary
while the sampling method needs a to sample the fast data from the camera.
After capture, the prescaler is switched back to /8.
HPRE will affect the speed of AHB1 and AHB2. Both have the same speed.
At image capture, both are running at 48Mhz and 6Mhz at all other times.
The clock change has a drastic effect of the power consumption.
--------------------------------------------------
Running at 1.8V
Position packet transmission, APRS AFSK, one packet every 1min (GPS off)
Image transmission, APRS AFSK, one packet every 20sec, redundant TX
=> average consumption 55mW
--------------------------------------------------
Running at 1.8V
Position packet transmission, APRS AFSK, one packet every 1min (GPS off)
=> average consumption 34mW
2017-08-30 23:27:09 +00:00
|
|
|
|
2017-08-19 09:51:15 +00:00
|
|
|
/* VSYNC leading with vsync true.
|
|
|
|
* This means end of capture for the frame.
|
2017-08-18 23:45:30 +00:00
|
|
|
* Stop & release the DMA channel.
|
2017-08-19 09:51:15 +00:00
|
|
|
* Disable TIM1 trigger of DMA and stop PCLK counting on LPTIM1.
|
|
|
|
* If buffer was filled in DMA then that is an error.
|
|
|
|
* We check that here.
|
2017-08-18 23:45:30 +00:00
|
|
|
*/
|
|
|
|
dma_stop();
|
|
|
|
TIM1->DIER &= ~TIM_DIER_TDE;
|
2017-09-08 23:02:02 +00:00
|
|
|
//LPTIM1->CR &= ~LPTIM_CR_CNTSTRT;
|
2017-08-18 23:45:30 +00:00
|
|
|
|
2017-08-19 09:51:15 +00:00
|
|
|
/*
|
|
|
|
* Disable VSYNC edge interrupts.
|
|
|
|
* Flag image capture complete.
|
|
|
|
*/
|
2017-08-18 23:45:30 +00:00
|
|
|
nvicDisableVector(EXTI1_IRQn);
|
2017-08-19 09:51:15 +00:00
|
|
|
capture_finished = true;
|
2017-08-18 23:45:30 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* LPTIM1 is not yet initialised.
|
|
|
|
* So we enable LPTIM1 to start counting.
|
|
|
|
*/
|
|
|
|
LPTIM1->CR |= LPTIM_CR_CNTSTRT;
|
|
|
|
}
|
|
|
|
|
|
|
|
EXTI->PR |= EXTI_PR_PR1;
|
|
|
|
CH_IRQ_EPILOGUE();
|
|
|
|
}
|
|
|
|
|
2017-09-10 01:22:58 +00:00
|
|
|
bool OV5640_Capture(uint8_t* buffer, uint32_t size)
|
2017-08-18 23:45:30 +00:00
|
|
|
{
|
Finalized clockling (so far) for power savings.
All dividers for all clocks are static except for HPRE.
HPRE is dynamically changed between /1 and /8. It is usually set to /8.
If the camera is capturing the image, it is set to /1. This is necessary
while the sampling method needs a to sample the fast data from the camera.
After capture, the prescaler is switched back to /8.
HPRE will affect the speed of AHB1 and AHB2. Both have the same speed.
At image capture, both are running at 48Mhz and 6Mhz at all other times.
The clock change has a drastic effect of the power consumption.
--------------------------------------------------
Running at 1.8V
Position packet transmission, APRS AFSK, one packet every 1min (GPS off)
Image transmission, APRS AFSK, one packet every 20sec, redundant TX
=> average consumption 55mW
--------------------------------------------------
Running at 1.8V
Position packet transmission, APRS AFSK, one packet every 1min (GPS off)
=> average consumption 34mW
2017-08-30 23:27:09 +00:00
|
|
|
/*
|
|
|
|
* Note:
|
|
|
|
* If there are no Chibios devices enabled that use DMA then...
|
|
|
|
* In makefile add entry to UDEFS:
|
|
|
|
* UDEFS = -DSTM32_DMA_REQUIRED
|
|
|
|
*/
|
2017-08-18 23:45:30 +00:00
|
|
|
|
|
|
|
/* Setup DMA for transfer on TIM1_TRIG - DMA2 stream 0, channel 6 */
|
2017-08-20 03:22:16 +00:00
|
|
|
dmastp = STM32_DMA_STREAM(STM32_DMA_STREAM_ID(2, 0));
|
|
|
|
uint32_t dmamode = STM32_DMA_CR_CHSEL(6) |
|
2017-08-18 23:45:30 +00:00
|
|
|
STM32_DMA_CR_PL(3) |
|
|
|
|
STM32_DMA_CR_DIR_P2M |
|
|
|
|
STM32_DMA_CR_MSIZE_WORD |
|
|
|
|
STM32_DMA_CR_MBURST_INCR4 |
|
|
|
|
STM32_DMA_CR_PSIZE_BYTE |
|
|
|
|
STM32_DMA_CR_MINC |
|
|
|
|
STM32_DMA_CR_DMEIE |
|
|
|
|
STM32_DMA_CR_TEIE |
|
2017-08-21 11:23:55 +00:00
|
|
|
#if OV5640_USE_DMA_DBM == TRUE
|
|
|
|
STM32_DMA_CR_DBM |
|
2017-08-22 00:39:01 +00:00
|
|
|
STM32_DMA_CR_HTIE |
|
2017-08-21 11:23:55 +00:00
|
|
|
#endif
|
2017-08-18 23:45:30 +00:00
|
|
|
STM32_DMA_CR_TCIE;
|
|
|
|
|
|
|
|
dmaStreamAllocate(dmastp, 2, (stm32_dmaisr_t)dma_interrupt, NULL);
|
|
|
|
|
|
|
|
dmaStreamSetPeripheral(dmastp, &GPIOA->IDR); // We want to read the data from here
|
2017-09-10 01:22:58 +00:00
|
|
|
|
2017-08-21 11:23:55 +00:00
|
|
|
#if OV5640_USE_DMA_DBM == TRUE
|
2017-09-10 01:22:58 +00:00
|
|
|
dma_buffer = buffer;
|
|
|
|
|
2017-08-21 11:23:55 +00:00
|
|
|
/*
|
|
|
|
* Buffer address must be word aligned.
|
|
|
|
* Also note requirement for burst transfers from FIFO.
|
|
|
|
* Bursts from FIFO to memory must not cross a 1K address boundary.
|
|
|
|
* See RM0430 9.3.12
|
|
|
|
*
|
|
|
|
* TODO: To use DMA_FIFO_BURST_ALIGN in setting of ssdv buffer alignment.
|
|
|
|
* Currently this is set to 32 manually in config.c.
|
|
|
|
*/
|
|
|
|
|
2017-09-10 01:22:58 +00:00
|
|
|
if (((uint32_t)buffer % DMA_FIFO_BURST_ALIGN) != 0) {
|
2017-08-23 08:10:29 +00:00
|
|
|
TRACE_ERROR("CAM > Buffer not allocated on DMA burst boundary");
|
2017-08-21 11:23:55 +00:00
|
|
|
return false;
|
2017-08-23 08:10:29 +00:00
|
|
|
}
|
2017-08-21 11:23:55 +00:00
|
|
|
/*
|
|
|
|
* Set the initial buffer addresses.
|
|
|
|
* The updating of DMA:MxAR is done in the the DMA interrupt function.
|
|
|
|
*/
|
2017-09-10 01:22:58 +00:00
|
|
|
dmaStreamSetMemory0(dmastp, &buffer[0]);
|
|
|
|
dmaStreamSetMemory1(dmastp, &buffer[DMA_SEGMENT_SIZE]);
|
2017-08-22 03:26:04 +00:00
|
|
|
dmaStreamSetTransactionSize(dmastp, DMA_SEGMENT_SIZE);
|
2017-08-21 11:23:55 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Calculate the number of whole buffers.
|
|
|
|
* TODO: Make this include remainder memory as partial buffer?
|
|
|
|
*/
|
2017-09-10 01:22:58 +00:00
|
|
|
dma_buffers = (size / DMA_SEGMENT_SIZE);
|
2017-08-23 08:10:29 +00:00
|
|
|
if (dma_buffers == 0) {
|
|
|
|
TRACE_ERROR("CAM > Capture buffer less than minimum DMA segment size");
|
2017-08-21 11:23:55 +00:00
|
|
|
return false;
|
2017-08-23 08:10:29 +00:00
|
|
|
}
|
2017-08-21 11:23:55 +00:00
|
|
|
/* Start with buffer index 0. */
|
|
|
|
dma_index = 0;
|
|
|
|
#else
|
2017-09-10 01:22:58 +00:00
|
|
|
dmaStreamSetMemory0(dmastp, buffer);
|
|
|
|
dmaStreamSetTransactionSize(dmastp, size);
|
2017-08-21 11:23:55 +00:00
|
|
|
|
|
|
|
#endif
|
|
|
|
dmaStreamSetMode(dmastp, dmamode); // Setup DMA
|
|
|
|
dmaStreamSetFIFO(dmastp, STM32_DMA_FCR_DMDIS | STM32_DMA_FCR_FTH_FULL \
|
|
|
|
| STM32_DMA_FCR_FEIE);
|
|
|
|
dmaStreamClearInterrupt(dmastp);
|
|
|
|
|
2017-08-23 08:10:29 +00:00
|
|
|
dma_error = false;
|
|
|
|
dma_flags = 0;
|
2017-08-19 09:51:15 +00:00
|
|
|
|
|
|
|
// Setup timer for PCLK
|
2017-09-10 01:22:58 +00:00
|
|
|
rccResetLPTIM1();
|
|
|
|
rccEnableLPTIM1(FALSE);
|
2017-08-18 23:45:30 +00:00
|
|
|
|
2017-09-10 01:22:58 +00:00
|
|
|
/*
|
|
|
|
* LPTIM1 is run in external count mode (CKSEL = 0, COUNTMODE = 1).
|
|
|
|
* CKPOL is set so leading and trailing edge of PCLK increment the counter.
|
|
|
|
* The internal clocking (checking edges of LPTIM1_IN) is set to use APB.
|
|
|
|
* The internal clock must be >4 times the frequency of the input (PCLK).
|
|
|
|
* NOTE: This does not guarantee that LPTIM1_OUT is coincident with PCLK.
|
|
|
|
* Depending on PCLK state when LPTIM1 is enabled OUT may get inverted.
|
|
|
|
*
|
|
|
|
* LPTIM1 is enabled on the VSYNC edge interrupt.
|
|
|
|
* After enabling LPTIM1 wait for the first interrupt (ARRIF).
|
|
|
|
* The interrupt must be disabled on the first interrupt (else flood).
|
|
|
|
*
|
|
|
|
* LPTIM1_OUT is gated to TIM1 internal trigger input 2.
|
|
|
|
*/
|
|
|
|
LPTIM1->CFGR = (LPTIM_CFGR_COUNTMODE | LPTIM_CFGR_CKPOL_1 | LPTIM_CFGR_WAVPOL);
|
|
|
|
LPTIM1->OR |= LPTIM_OR_TIM1_ITR2_RMP;
|
|
|
|
LPTIM1->CR |= LPTIM_CR_ENABLE;
|
|
|
|
LPTIM1->IER |= LPTIM_IER_ARRMIE;
|
2017-08-18 23:45:30 +00:00
|
|
|
|
2017-09-10 01:22:58 +00:00
|
|
|
/*
|
|
|
|
* When LPTIM1 is enabled and ready LPTIM1_OUT will be not set.
|
|
|
|
* WAVPOL inverts LPTIM1_OUT so it is not set.
|
|
|
|
* On the next PCLK edge LPTIM1 will count and match ARR.
|
|
|
|
* LPTIM1_OUT will set briefly and then clear again due ARR match.
|
|
|
|
* This triggers TIM1 with the short pulse from LPTIM1_OUT.
|
|
|
|
* TODO:
|
|
|
|
* This use of LPTIM1 works probably by good luck for now.
|
|
|
|
* Switch to direct triggering of TIM using Capture input is better.
|
|
|
|
* Requires a PCB change.
|
|
|
|
*/
|
|
|
|
LPTIM1->CMP = 0;
|
|
|
|
LPTIM1->ARR = 1;
|
2017-08-18 23:45:30 +00:00
|
|
|
|
|
|
|
/* Set vector and clear flag. */
|
|
|
|
nvicEnableVector(LPTIM1_IRQn, 7); // Enable interrupt
|
2017-09-10 01:22:58 +00:00
|
|
|
LptimRdy = false;
|
2017-08-18 23:45:30 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Setup slave timer to trigger DMA.
|
2017-08-23 08:10:29 +00:00
|
|
|
* We use TIM1 because it can be triggered from LPTIM1.
|
2017-08-18 23:45:30 +00:00
|
|
|
*/
|
|
|
|
rccResetTIM1();
|
|
|
|
rccEnableTIM1(FALSE);
|
|
|
|
|
2017-08-19 09:51:15 +00:00
|
|
|
/*
|
|
|
|
* TIM1_IC1 is mapped to TRC which means we are in trigger input mode.
|
|
|
|
* TIM1 is set in slave reset mode with input from ITR2.
|
|
|
|
* The timer will reset and trigger DMA on the leading edge of LPTIM1_OUT.
|
|
|
|
* The counter will count up while LPTIM1_OUT is high.
|
|
|
|
* We don't care about the count.
|
|
|
|
* We simply use the DMA initiated by the trigger input.
|
|
|
|
*/
|
|
|
|
TIM1->SMCR = TIM_SMCR_TS_1;
|
|
|
|
TIM1->SMCR |= TIM_SMCR_SMS_2;
|
2017-08-18 23:45:30 +00:00
|
|
|
TIM1->CCMR1 |= (TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC1S_1);
|
|
|
|
|
2017-08-19 09:51:15 +00:00
|
|
|
capture_finished = false;
|
2017-08-18 23:45:30 +00:00
|
|
|
vsync = false;
|
|
|
|
|
2017-09-05 06:35:23 +00:00
|
|
|
// Setup EXTI: EXTI1 PC for PC1 (VSYNC)
|
2017-08-18 23:45:30 +00:00
|
|
|
SYSCFG->EXTICR[0] |= SYSCFG_EXTICR1_EXTI1_PC;
|
|
|
|
EXTI->IMR = EXTI_IMR_MR1; // Activate interrupt for chan1 (=>PC1) and chan2 (=>PC2)
|
|
|
|
EXTI->RTSR = EXTI_RTSR_TR1; // Listen on rising edge
|
|
|
|
nvicEnableVector(EXTI1_IRQn, 1); // Enable interrupt
|
|
|
|
|
|
|
|
do { // Have a look for some bytes in memory for testing if capturing works
|
2017-08-27 19:14:30 +00:00
|
|
|
TRACE_INFO("CAM > ... capturing");
|
2017-09-10 01:22:58 +00:00
|
|
|
chThdSleepMilliseconds(100);
|
2017-08-23 08:10:29 +00:00
|
|
|
} while(!capture_finished && !dma_error);
|
|
|
|
|
2017-09-10 01:22:58 +00:00
|
|
|
if(dma_error) {
|
|
|
|
if(dma_flags & STM32_DMA_ISR_HTIF)
|
|
|
|
TRACE_ERROR("CAM > DMA abort - last buffer segment");
|
|
|
|
if(dma_flags & STM32_DMA_ISR_FEIF)
|
|
|
|
TRACE_ERROR("CAM > DMA FIFO error");
|
|
|
|
if(dma_flags & STM32_DMA_ISR_TEIF)
|
|
|
|
TRACE_ERROR("CAM > DMA stream transfer error");
|
|
|
|
if(dma_flags & STM32_DMA_ISR_DMEIF)
|
|
|
|
TRACE_ERROR("CAM > DMA direct mode error");
|
|
|
|
TRACE_ERROR("CAM > Error capturing image");
|
|
|
|
return false;
|
2017-08-19 09:51:15 +00:00
|
|
|
}
|
2017-08-18 23:45:30 +00:00
|
|
|
|
2017-08-23 08:10:29 +00:00
|
|
|
TRACE_INFO("CAM > Capture success");
|
2017-09-05 06:35:23 +00:00
|
|
|
|
2017-08-18 23:45:30 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initializes GPIO (for pseudo DCMI)
|
|
|
|
* The high speed clock supports communication by I2C (XCLK = 16MHz)
|
|
|
|
*/
|
|
|
|
void OV5640_InitGPIO(void)
|
|
|
|
{
|
|
|
|
palSetLineMode(LINE_CAM_HREF, PAL_MODE_INPUT_PULLUP | PAL_STM32_OSPEED_HIGHEST);
|
|
|
|
/* PC6 AF3 = TIM8_CH1. */
|
|
|
|
palSetLineMode(LINE_CAM_PCLK, PAL_MODE_ALTERNATE(1));
|
|
|
|
palSetLineMode(LINE_CAM_VSYNC, PAL_MODE_INPUT_PULLUP | PAL_STM32_OSPEED_HIGHEST);
|
|
|
|
palSetLineMode(LINE_CAM_XCLK, PAL_MODE_ALTERNATE(0));
|
|
|
|
palSetLineMode(LINE_CAM_D2, PAL_MODE_INPUT_PULLUP | PAL_STM32_OSPEED_HIGHEST);
|
|
|
|
palSetLineMode(LINE_CAM_D3, PAL_MODE_INPUT_PULLUP | PAL_STM32_OSPEED_HIGHEST);
|
|
|
|
palSetLineMode(LINE_CAM_D4, PAL_MODE_INPUT_PULLUP | PAL_STM32_OSPEED_HIGHEST);
|
|
|
|
palSetLineMode(LINE_CAM_D5, PAL_MODE_INPUT_PULLUP | PAL_STM32_OSPEED_HIGHEST);
|
|
|
|
palSetLineMode(LINE_CAM_D6, PAL_MODE_INPUT_PULLUP | PAL_STM32_OSPEED_HIGHEST);
|
|
|
|
palSetLineMode(LINE_CAM_D7, PAL_MODE_INPUT_PULLUP | PAL_STM32_OSPEED_HIGHEST);
|
|
|
|
palSetLineMode(LINE_CAM_D8, PAL_MODE_INPUT_PULLUP | PAL_STM32_OSPEED_HIGHEST);
|
|
|
|
palSetLineMode(LINE_CAM_D9, PAL_MODE_INPUT_PULLUP | PAL_STM32_OSPEED_HIGHEST);
|
|
|
|
|
|
|
|
palSetLineMode(LINE_CAM_EN, PAL_MODE_OUTPUT_PUSHPULL);
|
|
|
|
palSetLineMode(LINE_CAM_RESET, PAL_MODE_OUTPUT_PUSHPULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void OV5640_TransmitConfig(void)
|
|
|
|
{
|
2017-08-22 04:10:55 +00:00
|
|
|
TRACE_INFO("CAM > ... Software reset");
|
2017-08-19 02:38:41 +00:00
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x3103, 0x11);
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x3008, 0x82);
|
2017-08-18 23:45:30 +00:00
|
|
|
chThdSleepMilliseconds(100);
|
|
|
|
|
2017-08-22 04:10:55 +00:00
|
|
|
TRACE_INFO("CAM > ... Initialization");
|
2017-08-18 23:45:30 +00:00
|
|
|
for(uint32_t i=0; (OV5640YUV_Sensor_Dvp_Init[i].reg != 0xffff) || (OV5640YUV_Sensor_Dvp_Init[i].val != 0xff); i++)
|
2017-08-19 02:38:41 +00:00
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, OV5640YUV_Sensor_Dvp_Init[i].reg, OV5640YUV_Sensor_Dvp_Init[i].val);
|
2017-08-18 23:45:30 +00:00
|
|
|
|
|
|
|
chThdSleepMilliseconds(500);
|
|
|
|
|
2017-08-22 04:10:55 +00:00
|
|
|
TRACE_INFO("CAM > ... Configure JPEG");
|
2017-08-18 23:45:30 +00:00
|
|
|
for(uint32_t i=0; (OV5640_JPEG_QSXGA[i].reg != 0xffff) || (OV5640_JPEG_QSXGA[i].val != 0xff); i++)
|
2017-08-19 02:38:41 +00:00
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, OV5640_JPEG_QSXGA[i].reg, OV5640_JPEG_QSXGA[i].val);
|
2017-08-18 23:45:30 +00:00
|
|
|
|
2017-08-22 04:10:55 +00:00
|
|
|
TRACE_INFO("CAM > ... Light Mode: Auto");
|
2017-08-19 02:38:41 +00:00
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x3212, 0x03); // start group 3
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x3406, 0x00);
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x3400, 0x04);
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x3401, 0x00);
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x3402, 0x04);
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x3403, 0x00);
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x3404, 0x04);
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x3405, 0x00);
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x3212, 0x13); // end group 3
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x3212, 0xa3); // lanuch group 3
|
2017-08-22 04:10:55 +00:00
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x5183 ,0x0 );
|
2017-08-19 02:38:41 +00:00
|
|
|
|
2017-08-22 04:10:55 +00:00
|
|
|
TRACE_INFO("CAM > ... Saturation: 0");
|
2017-08-19 02:38:41 +00:00
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x3212, 0x03); // start group 3
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x5381, 0x1c);
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x5382, 0x5a);
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x5383, 0x06);
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x5384, 0x1a);
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x5385, 0x66);
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x5386, 0x80);
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x5387, 0x82);
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x5388, 0x80);
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x5389, 0x02);
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x538b, 0x98);
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x538a, 0x01);
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x3212, 0x13); // end group 3
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x3212, 0xa3); // launch group 3
|
|
|
|
|
2017-08-22 04:10:55 +00:00
|
|
|
TRACE_INFO("CAM > ... Brightness: 0");
|
2017-08-19 02:38:41 +00:00
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x3212, 0x03); // start group 3
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x5587, 0x00);
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x5588, 0x01);
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x3212, 0x13); // end group 3
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x3212, 0xa3); // launch group 3
|
|
|
|
|
2017-08-22 04:10:55 +00:00
|
|
|
TRACE_INFO("CAM > ... Contrast: 0");
|
2017-08-19 02:38:41 +00:00
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x3212, 0x03); // start group 3
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x3212, 0x03); // start group 3
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x5586, 0x20);
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x5585, 0x00);
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x3212, 0x13); // end group 3
|
2017-08-22 04:10:55 +00:00
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x3212, 0xa3); // launch group 3
|
2017-08-18 23:45:30 +00:00
|
|
|
}
|
|
|
|
|
2017-09-10 01:22:58 +00:00
|
|
|
void OV5640_SetResolution(resolution_t res)
|
|
|
|
{
|
|
|
|
TRACE_INFO("CAM > ... Configure Resolution");
|
|
|
|
switch(res) {
|
|
|
|
case RES_QQVGA:
|
|
|
|
for(uint32_t i=0; (OV5640_QSXGA2QQVGA[i].reg != 0xffff) || (OV5640_QSXGA2QQVGA[i].val != 0xff); i++)
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, OV5640_QSXGA2QQVGA[i].reg, OV5640_QSXGA2QQVGA[i].val);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RES_QVGA:
|
|
|
|
for(uint32_t i=0; (OV5640_QSXGA2QVGA[i].reg != 0xffff) || (OV5640_QSXGA2QVGA[i].val != 0xff); i++)
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, OV5640_QSXGA2QVGA[i].reg, OV5640_QSXGA2QVGA[i].val);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RES_VGA:
|
|
|
|
for(uint32_t i=0; (OV5640_QSXGA2VGA[i].reg != 0xffff) || (OV5640_QSXGA2VGA[i].val != 0xff); i++)
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, OV5640_QSXGA2VGA[i].reg, OV5640_QSXGA2VGA[i].val);
|
|
|
|
break;
|
2017-08-18 23:45:30 +00:00
|
|
|
|
2017-09-10 01:22:58 +00:00
|
|
|
case RES_XGA:
|
|
|
|
for(uint32_t i=0; (OV5640_QSXGA2XGA[i].reg != 0xffff) || (OV5640_QSXGA2XGA[i].val != 0xff); i++)
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, OV5640_QSXGA2XGA[i].reg, OV5640_QSXGA2XGA[i].val);
|
|
|
|
break;
|
2017-08-18 23:45:30 +00:00
|
|
|
|
2017-09-10 01:22:58 +00:00
|
|
|
case RES_UXGA:
|
|
|
|
for(uint32_t i=0; (OV5640_QSXGA2UXGA[i].reg != 0xffff) || (OV5640_QSXGA2UXGA[i].val != 0xff); i++)
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, OV5640_QSXGA2UXGA[i].reg, OV5640_QSXGA2UXGA[i].val);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default: // Default QVGA
|
|
|
|
for(uint32_t i=0; (OV5640_QSXGA2QVGA[i].reg != 0xffff) || (OV5640_QSXGA2QVGA[i].val != 0xff); i++)
|
|
|
|
I2C_write8_16bitreg(OV5640_I2C_ADR, OV5640_QSXGA2QVGA[i].reg, OV5640_QSXGA2QVGA[i].val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OV5640_init(void)
|
|
|
|
{
|
2017-08-18 23:45:30 +00:00
|
|
|
TRACE_INFO("CAM > Init pins");
|
|
|
|
OV5640_InitGPIO();
|
|
|
|
|
|
|
|
// Power on OV5640
|
|
|
|
TRACE_INFO("CAM > Switch on");
|
|
|
|
palSetLine(LINE_CAM_EN); // Switch on camera
|
2017-09-03 02:10:34 +00:00
|
|
|
palSetLine(LINE_CAM_RESET); // Toggle reset
|
2017-08-18 23:45:30 +00:00
|
|
|
|
2017-08-22 04:10:55 +00:00
|
|
|
chThdSleepMilliseconds(1000);
|
|
|
|
|
2017-08-18 23:45:30 +00:00
|
|
|
// Send settings to OV5640
|
|
|
|
TRACE_INFO("CAM > Transmit config to camera");
|
|
|
|
OV5640_TransmitConfig();
|
|
|
|
|
2017-08-22 04:10:55 +00:00
|
|
|
chThdSleepMilliseconds(1000);
|
2017-08-18 23:45:30 +00:00
|
|
|
}
|
|
|
|
|
2017-09-10 01:22:58 +00:00
|
|
|
void OV5640_deinit(void)
|
|
|
|
{
|
2017-08-18 23:45:30 +00:00
|
|
|
// Power off OV5640
|
|
|
|
TRACE_INFO("CAM > Switch off");
|
|
|
|
|
|
|
|
palSetLineMode(LINE_CAM_HREF, PAL_MODE_INPUT);
|
|
|
|
palSetLineMode(LINE_CAM_PCLK, PAL_MODE_INPUT);
|
|
|
|
palSetLineMode(LINE_CAM_VSYNC, PAL_MODE_INPUT);
|
|
|
|
|
|
|
|
palSetLineMode(LINE_CAM_XCLK, PAL_MODE_INPUT);
|
|
|
|
palSetLineMode(LINE_CAM_D2, PAL_MODE_INPUT);
|
|
|
|
palSetLineMode(LINE_CAM_D3, PAL_MODE_INPUT);
|
|
|
|
palSetLineMode(LINE_CAM_D4, PAL_MODE_INPUT);
|
|
|
|
palSetLineMode(LINE_CAM_D5, PAL_MODE_INPUT);
|
|
|
|
palSetLineMode(LINE_CAM_D6, PAL_MODE_INPUT);
|
|
|
|
palSetLineMode(LINE_CAM_D7, PAL_MODE_INPUT);
|
|
|
|
palSetLineMode(LINE_CAM_D8, PAL_MODE_INPUT);
|
|
|
|
palSetLineMode(LINE_CAM_D9, PAL_MODE_INPUT);
|
|
|
|
|
|
|
|
palSetLineMode(LINE_CAM_EN, PAL_MODE_INPUT);
|
|
|
|
palSetLineMode(LINE_CAM_RESET, PAL_MODE_INPUT);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool OV5640_isAvailable(void)
|
|
|
|
{
|
|
|
|
// Configure pins
|
|
|
|
OV5640_InitGPIO();
|
|
|
|
|
|
|
|
// Switch on camera
|
|
|
|
palSetLine(LINE_CAM_EN); // Switch on camera
|
|
|
|
palSetLine(LINE_CAM_RESET); // Toggle reset
|
|
|
|
|
|
|
|
chThdSleepMilliseconds(100);
|
|
|
|
|
|
|
|
uint8_t val, val2;
|
|
|
|
bool ret;
|
|
|
|
|
2017-08-19 02:38:41 +00:00
|
|
|
if(I2C_read8_16bitreg(OV5640_I2C_ADR, 0x300A, &val) && I2C_read8_16bitreg(OV5640_I2C_ADR, 0x300B, &val2)) {
|
2017-08-18 23:45:30 +00:00
|
|
|
ret = val == 0x56 && val2 == 0x40;
|
|
|
|
} else {
|
|
|
|
ret = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
palClearLine(LINE_CAM_EN); // Switch off camera
|
|
|
|
palSetLineMode(LINE_CAM_RESET, PAL_MODE_INPUT); // CAM_RESET
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-08-30 03:29:59 +00:00
|
|
|
uint32_t OV5640_getLightIntensity(void)
|
|
|
|
{
|
|
|
|
uint8_t val1,val2,val3;
|
|
|
|
I2C_read8_16bitreg(OV5640_I2C_ADR, 0x3C1B, &val1);
|
|
|
|
I2C_read8_16bitreg(OV5640_I2C_ADR, 0x3C1C, &val2);
|
|
|
|
I2C_read8_16bitreg(OV5640_I2C_ADR, 0x3C1D, &val3);
|
|
|
|
return (val1 << 16) | (val2 << 8) | val3;
|
|
|
|
}
|
|
|
|
|