kopia lustrzana https://github.com/DL7AD/pecanpico9
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.cDevelop
rodzic
a29f90a9f8
commit
e9cff81fa4
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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}
|
||||
};
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
Ładowanie…
Reference in New Issue