diff --git a/build-number.txt b/build-number.txt index 3bfc51a..11a42ac 100644 --- a/build-number.txt +++ b/build-number.txt @@ -1 +1 @@ -562 +615 diff --git a/src/config.h b/src/config.h new file mode 100644 index 0000000..7a9b0db --- /dev/null +++ b/src/config.h @@ -0,0 +1,21 @@ +#pragma once + +// Use 2D Floyd-Steinberg dithering. Uncomment to use simple line-wise +// dithering. +#define CONFIG_USE_2D_DITHERING + +// Use a primitive autoexposure by shifting each frames luminosity based on the +// ratio of white to black pixels in the previous frames +// #define CONFIG_USE_EXPOSURE_CORRECTION + +// Capture a frame when it is within this tolerance of 50% black pixels +#define CONFIG_TOLERANCE 0.2 + +// Wait this number of frames before a frame is eligible for beaing captured +#define CONFIG_MIN_FRAMES 2 + +// Maximum number of frames to wait. Capture even if it is not within tolerance. +#define CONFIG_MAX_FRAMES 15 + +// Print number of black pixels per captured frame +// #define CONFIG_PRINT_EXPOSURE_DEBUG_INFORMATION \ No newline at end of file diff --git a/src/main.c b/src/main.c index 2085066..108a766 100644 --- a/src/main.c +++ b/src/main.c @@ -22,6 +22,24 @@ int main(void) extern uint8_t ImageBuffer[CAMERA_IMAGE_WIDTH * CAMERA_IMAGE_HEIGHT / 8]; Print_Image(ImageBuffer, CAMERA_IMAGE_WIDTH, CAMERA_IMAGE_HEIGHT, 2); +#ifdef CONFIG_PRINT_EXPOSURE_DEBUG_INFORMATION + char buffer[32] = "Finished after lines: "; + itoa(Camera_FinalFrameCount, buffer + strlen(buffer), 10); + + Print_Text(buffer, &Arpegius_32); + Print_Text("Black pixel counts:", &Arpegius_32); + for(int i = 0; i < Camera_FinalFrameCount; i++) + { + if(i >= (int)(sizeof(Camera_BlackPixelCounts) + / sizeof(Camera_BlackPixelCounts[0]))) + { + break; + } + itoa(Camera_BlackPixelCounts[i], buffer, 10); + Print_Text(buffer, &Arpegius_32); + } +#endif + LTP1245_FeedPaper(100); BMP_Save(ImageBuffer, CAMERA_IMAGE_WIDTH, CAMERA_IMAGE_HEIGHT); diff --git a/src/main.h b/src/main.h index fd56361..532c2d3 100644 --- a/src/main.h +++ b/src/main.h @@ -16,6 +16,7 @@ #include "font_arpegius_16.h" #include "font_arpegius_32.h" #include "bmp.h" +#include "config.h" int main(void); diff --git a/src/ov7670.c b/src/ov7670.c index 377c613..23c0c99 100644 --- a/src/ov7670.c +++ b/src/ov7670.c @@ -126,12 +126,12 @@ #define REG_HAECC2 0xa0 #define REG_SCALING_PCLK_DELAY 0xa2 #define REG_NT_CTRL 0xa4 -#define REG_BD50MAX 0xa5 -#define REG_HAECC3 0xa6 -#define REG_HAECC4 0xa7 -#define REG_HAECC5 0xa8 -#define REG_HAECC6 0xa9 -#define REG_HAECC7 0xaa +#define REG_AECGMAX 0xa5 +#define REG_LPH 0xa6 +#define REG_UPL 0xa7 +#define REG_TPL 0xa8 +#define REG_TPH 0xa9 +#define REG_NALG 0xaa #define REG_BD60MAX 0xab #define REG_STR_OPT 0xac #define REG_STR_R 0xad @@ -156,10 +156,13 @@ static volatile int FrameCount = 0; volatile int Camera_Captured = 0; static unsigned int BlackPixels = 0; -#ifdef CAMERA_USE_EXPOSURE_CORRECTION +#ifdef CONFIG_USE_EXPOSURE_CORRECTION static volatile int ExposureCorrection = 0; #endif +volatile unsigned int Camera_BlackPixelCounts[] = {0}; +volatile int Camera_FinalFrameCount = -1; + static uint8_t ReadRegister(uint8_t reg) { while(I2C1->SR2 & I2C_SR2_BUSY); @@ -301,6 +304,24 @@ void Camera_Init(void) WriteRegister(REG_COM14, 0x18 | 1); WriteRegister(REG_SCALING_PCLK_DIV, 1); + // Set maximum gain ceiling + WriteRegister(REG_COM9, 0xca); + + // Disable auto-exposure, enable auto-gain + WriteRegister(REG_COM8, 0xec); + + // // Disable auto-gain, enable auto-exposure + // WriteRegister(REG_COM8, 0xe9); + + // Use histogram-based auto-exposure + WriteRegister(REG_NALG, 0x94); + + // Increase AEC speed: + // ‘Decrease TPL but not less than UPL [default 0xc1] and increase TPH but + // not bigger than LPH [default 0xf0]’ + WriteRegister(REG_TPL, 0xc1); + WriteRegister(REG_TPH, 0xf0); + // Enable VSYNC interrupts. TIM3 is enabled at the first VSYNC. FrameCount = 0; Camera_Captured = 0; @@ -327,20 +348,34 @@ void TIM1_CC_IRQHandler(void) CurrentLine = 0; FrameCount++; -#ifdef CAMERA_USE_EXPOSURE_CORRECTION +#ifdef CONFIG_USE_EXPOSURE_CORRECTION // Correct exposure across frames ExposureCorrection += 32 * BlackPixels / CAMERA_PIXELS - 16; #endif // Check if the last frame's exposure is reasonable - if(FrameCount >= 5) + if(!Camera_Captured && FrameCount >= CONFIG_MIN_FRAMES + && ( + (BlackPixels > (int)(CAMERA_PIXELS / 2 + - CAMERA_PIXELS * CONFIG_TOLERANCE) + && BlackPixels < (int)(CAMERA_PIXELS / 2 + + CAMERA_PIXELS * CONFIG_TOLERANCE)) + || FrameCount >= CONFIG_MAX_FRAMES + )) { Camera_Captured = 1; + Camera_FinalFrameCount = FrameCount; // Disable everything TIM3->CR1 = 0; TIM1->CR1 = 0; } + if(FrameCount < (int)(sizeof(Camera_BlackPixelCounts) + / sizeof(Camera_BlackPixelCounts[0]))) + { + Camera_BlackPixelCounts[FrameCount] = BlackPixels; + } + // Reset black pixel counter BlackPixels = 0; @@ -361,7 +396,7 @@ void TIM3_IRQHandler(void) DMA1_Channel6->CCR = DMA_CCR_PL | DMA_CCR_MINC | DMA_CCR_EN; TIM3->DIER |= TIM_DIER_CC1DE; -#ifdef CAMERA_USE_2D_DITHERING +#ifdef CONFIG_USE_2D_DITHERING static int8_t y_errors[CAMERA_IMAGE_WIDTH + 2] = {0}; if(CurrentLine == 0) @@ -374,7 +409,7 @@ void TIM3_IRQHandler(void) && (CurrentLine / 2 < CAMERA_IMAGE_HEIGHT)) { -#ifdef CAMERA_USE_2D_DITHERING +#ifdef CONFIG_USE_2D_DITHERING // Apply errors propagated from the previous line. Since y_errors is // overwritten during x error diffusion, this is done now. for(int i = 0; i < CAMERA_IMAGE_WIDTH; i++) @@ -388,7 +423,7 @@ void TIM3_IRQHandler(void) for(int i = 0; i < CAMERA_IMAGE_WIDTH; i++) { int pixel = LineBuffer[i + 15] + x_error; -#ifdef CAMERA_USE_EXPOSURE_CORRECTION +#ifdef CONFIG_USE_EXPOSURE_CORRECTION if(ExposureCorrection < 0) { if(pixel < -ExposureCorrection) @@ -421,7 +456,7 @@ void TIM3_IRQHandler(void) ~(0x80 >> (i % 8)); } -#ifdef CAMERA_USE_2D_DITHERING +#ifdef CONFIG_USE_2D_DITHERING // Error propagated to the next pixel in the same line x_error = error * 7 / 16; diff --git a/src/ov7670.h b/src/ov7670.h index 8ffa57d..1f3666c 100644 --- a/src/ov7670.h +++ b/src/ov7670.h @@ -2,19 +2,16 @@ #include #include "stm32f1xx.h" +#include "config.h" #define CAMERA_IMAGE_WIDTH 160 #define CAMERA_IMAGE_HEIGHT 144 #define CAMERA_PIXELS (CAMERA_IMAGE_WIDTH * CAMERA_IMAGE_HEIGHT) -// Use 2D Floyd-Steinberg dithering. Uncomment to use simple line-wise -// dithering. -#define CAMERA_USE_2D_DITHERING - -// Use a primitive autoexposure by shifting each frames luminosity based on the -// ratio of white to black pixels in the previous frames -// #define CAMERA_USE_EXPOSURE_CORRECTION extern volatile int Camera_Captured; +extern volatile unsigned int Camera_BlackPixelCounts[CONFIG_MAX_FRAMES]; +extern volatile int Camera_FinalFrameCount; + void Camera_Init(void); \ No newline at end of file