Fixed bug: Image transmission over USB was only possible when debug on USB was activated

Fixed bug: Image transmission over USB was only possible when no image module was activated
Added feature: Print saved log on USB
Fixed camera initialization bug
Implemented dynamic camera resolution change without reinitialization
Created separated takePicture method in image.c
Develop
Sven Steudte 2017-09-10 03:22:58 +02:00
rodzic a29f90a9f8
commit e9cff81fa4
8 zmienionych plików z 211 dodań i 184 usunięć

Wyświetl plik

@ -365,8 +365,8 @@ module_conf_t config[7];
uint8_t ssdv_buffer[128*1024] __attribute__((aligned(32))); // Image buffer
systime_t track_cycle_time = S2ST(60); // Tracking cycle (all peripheral data [airpressure, GPS, temperature, ...] is collected each 60 seconds
systime_t log_cycle_time = S2ST(600); // Log cycle time in seconds (600 seconds)
bool keep_cam_switched_on = true; // Keep camera switched on and initialized after it has been switched on once, no configuration change is possible
systime_t log_cycle_time = S2ST(60); // Log cycle time in seconds (600 seconds)
bool keep_cam_switched_on = true; // Keep camera switched on and initialized, this makes image capturing faster but takes a lot of power over long time
uint16_t gps_on_vbat = 3000; // Battery voltage threshold at which GPS is switched on
uint16_t gps_off_vbat = 2500; // Battery voltage threshold at which GPS is switched off

Wyświetl plik

@ -4,6 +4,7 @@
#include <stdlib.h>
#include "config.h"
#include "image.h"
#include "tracking.h"
const SerialConfig uart_config =
{
@ -15,7 +16,7 @@ const SerialConfig uart_config =
mutex_t trace_mtx; // Used internal to synchronize multiple chprintf in debug.h
bool debug_on_usb = true;
bool debug_on_usb = false;
void debugOnUSB_Off(BaseSequentialStream *chp, int argc, char *argv[])
{
@ -36,7 +37,6 @@ void debugOnUSB_On(BaseSequentialStream *chp, int argc, char *argv[])
static uint8_t usb_buffer[96*1024] __attribute__((aligned(32))); // USB image buffer
void printPicture(BaseSequentialStream *chp, int argc, char *argv[])
{
(void)chp;
(void)argc;
(void)argv;
@ -52,7 +52,6 @@ void printPicture(BaseSequentialStream *chp, int argc, char *argv[])
// Transmit image via USB
if(camera_found)
{
bool start_detected = false;
for(uint32_t i=0; i<conf.size_sampled; i++)
{
@ -60,21 +59,58 @@ void printPicture(BaseSequentialStream *chp, int argc, char *argv[])
if(!start_detected && conf.ram_buffer[i] == 0xFF && conf.ram_buffer[i+1] == 0xE0) {
start_detected = true;
TRACE_USB("DATA > image/jpeg,%d", conf.size_sampled-i+1); // Flag the data on serial output
streamPut(&SDU1, 0xFF);
streamPut(&SDU1, 0xD8);
streamPut(chp, 0xFF);
streamPut(chp, 0xD8);
}
if(start_detected)
streamPut(&SDU1, conf.ram_buffer[i]);
streamPut(chp, conf.ram_buffer[i]);
}
if(!start_detected)
{
TRACE_USB("DATA > image,jpeg,0");
TRACE_USB("DATA > error,no SOI flag found");
}
} else { // No camera found
for(uint32_t i=0; i<sizeof(noCameraFound); i++)
streamPut(&SDU1, noCameraFound[i]);
TRACE_USB("DATA > image,jpeg,0");
TRACE_USB("DATA > error,no camera found");
}
}
trackPoint_t* getLogBuffer(uint16_t id)
{
if(sizeof(trackPoint_t)*id < LOG_SECTOR_SIZE-sizeof(trackPoint_t))
{
return (trackPoint_t*)(LOG_FLASH_ADDR1 + id * sizeof(trackPoint_t));
} else if((id-(LOG_SECTOR_SIZE/sizeof(trackPoint_t)))*sizeof(trackPoint_t) < LOG_SECTOR_SIZE-sizeof(trackPoint_t)) {
return (trackPoint_t*)(LOG_FLASH_ADDR2 + (id-(LOG_SECTOR_SIZE/sizeof(trackPoint_t))) * sizeof(trackPoint_t));
} else { // Outside of memory address allocation
return NULL;
}
}
void readLog(BaseSequentialStream *chp, int argc, char *argv[])
{
(void)argc;
(void)argv;
trackPoint_t *tp;
for(uint16_t i=0; (tp = getLogBuffer(i)) != NULL; i++)
if(tp->id != 0xFFFFFFFF)
{
chprintf( chp,
"%d,%04d-%02d-%02d,%02d:%02d:%02d,%d.%05d,%d.%05d,%d,%d,%d,%d.%03d,%d.%03d,%d.%03d,%d,%d,%d.%01d,%2d.%02d,%2d.%01d\r\n",
tp->id,tp->time.year, tp->time.month, tp->time.day, tp->time.hour, tp->time.minute, tp->time.day,
tp->gps_lat/10000000, (tp->gps_lat > 0 ? 1:-1)*(tp->gps_lat/100)%100000, tp->gps_lon/10000000, (tp->gps_lon > 0 ? 1:-1)*(tp->gps_lon/100)%100000, tp->gps_alt,
tp->gps_sats, tp->gps_ttff,
tp->adc_vbat/1000, (tp->adc_vbat%1000), tp->adc_vsol/1000, (tp->adc_vsol%1000), tp->adc_vusb/1000, (tp->adc_vusb%1000), tp->adc_pbat, tp->adc_rbat,
tp->air_press/10, tp->air_press%10, tp->air_temp/100, tp->air_temp%100, tp->air_hum/10, tp->air_hum%10
);
}
}
void printConfig(BaseSequentialStream *chp, int argc, char *argv[])
{
if(argc < 1)

Wyświetl plik

@ -42,12 +42,13 @@ extern bool debug_on_usb;
chprintf((BaseSequentialStream*)&SD3, (format), ##args); \
chprintf((BaseSequentialStream*)&SD3, "\r\n"); \
\
TRACE_BASE_USB(format, type, ##args); \
if(debug_on_usb) \
TRACE_BASE_USB(format, type, ##args); \
chMtxUnlock(&trace_mtx); \
}
#define TRACE_BASE_USB(format, type, args...) { \
if(usb_initialized && debug_on_usb) { \
if(usb_initialized) { \
if(TRACE_TIME) { \
chprintf((BaseSequentialStream*)&SDU1, "[%8d.%03d]", chVTGetSystemTimeX()/CH_CFG_ST_FREQUENCY, (chVTGetSystemTimeX()*1000/CH_CFG_ST_FREQUENCY)%1000); \
} \
@ -107,6 +108,7 @@ void debugOnUSB_Off(BaseSequentialStream *chp, int argc, char *argv[]);
void debugOnUSB_On(BaseSequentialStream *chp, int argc, char *argv[]);
void printConfig(BaseSequentialStream *chp, int argc, char *argv[]);
void printPicture(BaseSequentialStream *chp, int argc, char *argv[]);
void readLog(BaseSequentialStream *chp, int argc, char *argv[]);
#endif

Wyświetl plik

@ -136,6 +136,7 @@ static const struct regval_list OV5640YUV_Sensor_Dvp_Init[] =
{ 0x4300, 0x30 },
{ 0x501f, 0x00 },
{ 0x4713, 0x03 },
{ 0x4404, 0x34 },
{ 0x4407, 0x04 },
{ 0x460b, 0x35 },
{ 0x460c, 0x22 },//add by bright
@ -753,20 +754,21 @@ static const struct regval_list OV5640_QSXGA2XGA[] =
{0xffff, 0xff},
};
static ssdv_conf_t *ov5640_conf;
/* TODO: Implement a state machine instead of multiple flags. */
// TODO: Implement a state machine instead of multiple flags
static bool LptimRdy = false;
static bool capture_finished;
static bool vsync;
static bool dma_error;
static uint32_t dma_flags;
static uint8_t* dma_buffer;
static uint32_t oldSpeed;
static uint32_t oldWS;
/* Increase AHB clock to 48 MHz */
/**
* Increase AHB clock to 48 MHz and saves the old speed
*/
void set48MHz(void)
{
oldSpeed = RCC->CFGR & RCC_CFGR_HPRE_Msk;
@ -781,9 +783,11 @@ void set48MHz(void)
while(RCC->CFGR != new);
}
/**
* Reduce AHB clock back to the old speed which has been saved by set48MHz()
*/
void set6MHz(void)
{
// Reduce AHB clock to 6 MHz
uint32_t new = (RCC->CFGR & ~RCC_CFGR_HPRE_Msk) | oldSpeed;
RCC->CFGR = new;
while(RCC->CFGR != new);
@ -835,36 +839,61 @@ static bool analyze_image(uint8_t *image, uint32_t image_len)
}
}
bool OV5640_BufferOverflow(void)
{
return ov5640_conf->size_sampled == ov5640_conf->ram_size - 1; // If SRAM was used completly its most likley that and overflow has occured (TODO: This is not 100% accurate)
}
/**
* Captures an image from the camera.
* @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.
*/
bool OV5640_Snapshot2RAM(bool enableJpegValidation)
uint32_t OV5640_Snapshot2RAM(uint8_t* buffer, uint32_t size, resolution_t res, bool enableJpegValidation)
{
// Capture image until we get a good image (max 10 tries)
uint8_t cntr = 10;
uint8_t cntr = 5;
bool status;
bool jpegValid;
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)
do {
// Clearing buffer
uint32_t i;
for(i=0; i<size; i++)
buffer[i] = 0;
TRACE_INFO("CAM > Capture image");
status = OV5640_Capture();
status = OV5640_Capture(buffer, size);
TRACE_INFO("CAM > Capture finished");
ov5640_conf->size_sampled = ov5640_conf->ram_size - 1;
while(!ov5640_conf->ram_buffer[ov5640_conf->size_sampled] && ov5640_conf->size_sampled > 0)
ov5640_conf->size_sampled--;
size_sampled = size - 1;
while(!buffer[size_sampled] && size_sampled > 0)
size_sampled--;
TRACE_INFO("CAM > Image size: %d bytes", ov5640_conf->size_sampled);
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;
}
jpegValid = enableJpegValidation ? true : analyze_image(ov5640_conf->ram_buffer, ov5640_conf->ram_size);
} while((!jpegValid || !status) && cntr--);
return true;
return size_sampled;
}
const stm32_dma_stream_t *dmastp;
@ -971,9 +1000,9 @@ static void dma_interrupt(void *p, uint32_t flags) {
if (dmaStreamGetCurrentTarget(dmastp) == 1) {
dmaStreamSetMemory0(dmastp, &ov5640_conf->ram_buffer[++dma_index * DMA_SEGMENT_SIZE]);
dmaStreamSetMemory0(dmastp, &dma_buffer[++dma_index * DMA_SEGMENT_SIZE]);
} else {
dmaStreamSetMemory1(dmastp, &ov5640_conf->ram_buffer[++dma_index * DMA_SEGMENT_SIZE]);
dmaStreamSetMemory1(dmastp, &dma_buffer[++dma_index * DMA_SEGMENT_SIZE]);
}
dmaStreamClearInterrupt(dmastp);
return;
@ -1104,9 +1133,8 @@ CH_IRQ_HANDLER(Vector5C) {
CH_IRQ_EPILOGUE();
}
bool OV5640_Capture(void)
bool OV5640_Capture(uint8_t* buffer, uint32_t size)
{
/*
* Note:
* If there are no Chibios devices enabled that use DMA then...
@ -1128,14 +1156,16 @@ bool OV5640_Capture(void)
#if OV5640_USE_DMA_DBM == TRUE
STM32_DMA_CR_DBM |
STM32_DMA_CR_HTIE |
#endif
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
#if OV5640_USE_DMA_DBM == TRUE
dma_buffer = buffer;
/*
* Buffer address must be word aligned.
* Also note requirement for burst transfers from FIFO.
@ -1146,7 +1176,7 @@ bool OV5640_Capture(void)
* Currently this is set to 32 manually in config.c.
*/
if (((uint32_t)ov5640_conf->ram_buffer % DMA_FIFO_BURST_ALIGN) != 0) {
if (((uint32_t)buffer % DMA_FIFO_BURST_ALIGN) != 0) {
TRACE_ERROR("CAM > Buffer not allocated on DMA burst boundary");
return false;
}
@ -1154,15 +1184,15 @@ bool OV5640_Capture(void)
* Set the initial buffer addresses.
* The updating of DMA:MxAR is done in the the DMA interrupt function.
*/
dmaStreamSetMemory0(dmastp, &ov5640_conf->ram_buffer[0]);
dmaStreamSetMemory1(dmastp, &ov5640_conf->ram_buffer[DMA_SEGMENT_SIZE]);
dmaStreamSetMemory0(dmastp, &buffer[0]);
dmaStreamSetMemory1(dmastp, &buffer[DMA_SEGMENT_SIZE]);
dmaStreamSetTransactionSize(dmastp, DMA_SEGMENT_SIZE);
/*
* Calculate the number of whole buffers.
* TODO: Make this include remainder memory as partial buffer?
*/
dma_buffers = (ov5640_conf->ram_size / DMA_SEGMENT_SIZE);
dma_buffers = (size / DMA_SEGMENT_SIZE);
if (dma_buffers == 0) {
TRACE_ERROR("CAM > Capture buffer less than minimum DMA segment size");
return false;
@ -1170,8 +1200,8 @@ bool OV5640_Capture(void)
/* Start with buffer index 0. */
dma_index = 0;
#else
dmaStreamSetMemory0(dmastp, ov5640_conf->ram_buffer);
dmaStreamSetTransactionSize(dmastp, ov5640_conf->ram_size);
dmaStreamSetMemory0(dmastp, buffer);
dmaStreamSetTransactionSize(dmastp, size);
#endif
dmaStreamSetMode(dmastp, dmamode); // Setup DMA
@ -1183,48 +1213,45 @@ bool OV5640_Capture(void)
dma_flags = 0;
// Setup timer for PCLK
if(!LptimRdy)
{
rccResetLPTIM1();
rccEnableLPTIM1(FALSE);
rccResetLPTIM1();
rccEnableLPTIM1(FALSE);
/*
* 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;
/*
* 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;
/*
* 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;
}
/*
* 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;
/* Set vector and clear flag. */
nvicEnableVector(LPTIM1_IRQn, 7); // Enable interrupt
//LptimRdy = false;
LptimRdy = false;
/*
* Setup slave timer to trigger DMA.
@ -1256,20 +1283,20 @@ bool OV5640_Capture(void)
do { // Have a look for some bytes in memory for testing if capturing works
TRACE_INFO("CAM > ... capturing");
chThdSleepMilliseconds(50);
chThdSleepMilliseconds(100);
} while(!capture_finished && !dma_error);
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;
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;
}
TRACE_INFO("CAM > Capture success");
@ -1320,38 +1347,6 @@ void OV5640_TransmitConfig(void)
for(uint32_t i=0; (OV5640_JPEG_QSXGA[i].reg != 0xffff) || (OV5640_JPEG_QSXGA[i].val != 0xff); i++)
I2C_write8_16bitreg(OV5640_I2C_ADR, OV5640_JPEG_QSXGA[i].reg, OV5640_JPEG_QSXGA[i].val);
TRACE_INFO("CAM > ... Configure Resolution");
switch(ov5640_conf->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;
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;
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);
}
TRACE_INFO("CAM > ... Light Mode: Auto");
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x3212, 0x03); // start group 3
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x3406, 0x00);
@ -1397,14 +1392,43 @@ void OV5640_TransmitConfig(void)
I2C_write8_16bitreg(OV5640_I2C_ADR, 0x3212, 0xa3); // launch group 3
}
void OV5640_init(ssdv_conf_t *config) {
ov5640_conf = config;
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;
// Clearing buffer
uint32_t i;
for(i=0; i<ov5640_conf->ram_size; i++)
ov5640_conf->ram_buffer[i] = 0;
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;
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;
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)
{
TRACE_INFO("CAM > Init pins");
OV5640_InitGPIO();
@ -1422,7 +1446,8 @@ void OV5640_init(ssdv_conf_t *config) {
chThdSleepMilliseconds(1000);
}
void OV5640_deinit(void) {
void OV5640_deinit(void)
{
// Power off OV5640
TRACE_INFO("CAM > Switch off");

Wyświetl plik

@ -11,14 +11,15 @@
#define OV5640_USE_DMA_DBM TRUE
bool OV5640_Snapshot2RAM(bool enableJpegValidation);
bool OV5640_Capture(void);
uint32_t OV5640_Snapshot2RAM(uint8_t* buffer, uint32_t size, resolution_t resolution, bool enableJpegValidation);
bool OV5640_Capture(uint8_t* buffer, uint32_t size);
void OV5640_InitGPIO(void);
bool OV5640_BufferOverflow(void);
void OV5640_TransmitConfig(void);
void OV5640_init(ssdv_conf_t *config);
void OV5640_SetResolution(resolution_t res);
void OV5640_init(void);
void OV5640_deinit(void);
bool OV5640_isAvailable(void);
uint32_t OV5640_getLightIntensity(void);
#endif

Wyświetl plik

@ -11,6 +11,7 @@ static const ShellCommand commands[] = {
{"dbgon", debugOnUSB_On},
{"dbgoff", debugOnUSB_Off},
{"picture", printPicture},
{"log", readLog},
// {"printconfig", printConfig}, FIXME: This feature is faulty at the moment
{NULL, NULL}
};

Wyświetl plik

@ -435,57 +435,24 @@ bool takePicture(ssdv_conf_t *conf, bool enableJpegValidation)
TRACE_INFO("IMG > OV5640 found");
camera_found = true;
if(conf->res == RES_MAX) // Attempt maximum resolution (limited by memory)
{
conf->res = RES_UXGA; // Try maximum resolution
do {
// Init camera
if(!camInitialized) {
OV5640_init(conf);
camInitialized = true;
}
// Sample data from DCMI through DMA into RAM
uint8_t tries = 5; // Try 5 times at maximum
bool status;
do { // Try capturing image until capture successful
lockRadio(); // Lock radio
status = OV5640_Snapshot2RAM(enableJpegValidation);
unlockRadio(); // Unlock radio
} while(!status && --tries);
conf->res--; // Decrement resolution in next attempt (if status==false)
} while(OV5640_BufferOverflow() && conf->res >= RES_QVGA);
conf->res = RES_MAX; // Revert register
} else { // Static resolution
// Init camera
if(!camInitialized) {
OV5640_init(conf);
camInitialized = true;
}
// Sample data from DCMI through DMA into RAM
uint8_t tries = 5; // Try 5 times at maximum
bool status;
do { // Try capturing image until capture successful
status = OV5640_Snapshot2RAM(enableJpegValidation);
} while(!status && --tries);
// Init camera
if(!camInitialized) {
OV5640_init();
camInitialized = true;
}
// Sample data from pseudo DCMI through DMA into RAM
lockRadio(); // Lock radio
conf->size_sampled = OV5640_Snapshot2RAM(conf->ram_buffer, conf->ram_size, conf->res, enableJpegValidation);
unlockRadio(); // Unlock radio
// Switch off camera
if(!keep_cam_switched_on) {
OV5640_deinit();
camInitialized = false;
}
} else { // Camera error
} else { // Camera not found
camInitialized = false;
TRACE_ERROR("IMG > No camera found");

Wyświetl plik

@ -4,11 +4,6 @@
#include "ch.h"
#include "hal.h"
#define IMG_ID_FLASH_ADDR 0x80A0000 /* Image ID flash memory address */
#define IMG_ID_FLASH_SIZE (128*1024) /* Image ID flash memory size */
extern const uint8_t noCameraFound[4071];
void start_image_thread(module_conf_t *conf);
bool takePicture(ssdv_conf_t *conf, bool enableJpegValidation);
extern mutex_t camera_mtx;