Compare commits

...

3 commits

6 changed files with 93 additions and 21 deletions

View file

@ -1 +1 @@
562 615

21
src/config.h Normal file
View file

@ -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

View file

@ -22,6 +22,24 @@ int main(void)
extern uint8_t ImageBuffer[CAMERA_IMAGE_WIDTH * CAMERA_IMAGE_HEIGHT / 8]; extern uint8_t ImageBuffer[CAMERA_IMAGE_WIDTH * CAMERA_IMAGE_HEIGHT / 8];
Print_Image(ImageBuffer, CAMERA_IMAGE_WIDTH, CAMERA_IMAGE_HEIGHT, 2); 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); LTP1245_FeedPaper(100);
BMP_Save(ImageBuffer, CAMERA_IMAGE_WIDTH, CAMERA_IMAGE_HEIGHT); BMP_Save(ImageBuffer, CAMERA_IMAGE_WIDTH, CAMERA_IMAGE_HEIGHT);

View file

@ -16,6 +16,7 @@
#include "font_arpegius_16.h" #include "font_arpegius_16.h"
#include "font_arpegius_32.h" #include "font_arpegius_32.h"
#include "bmp.h" #include "bmp.h"
#include "config.h"
int main(void); int main(void);

View file

@ -126,12 +126,12 @@
#define REG_HAECC2 0xa0 #define REG_HAECC2 0xa0
#define REG_SCALING_PCLK_DELAY 0xa2 #define REG_SCALING_PCLK_DELAY 0xa2
#define REG_NT_CTRL 0xa4 #define REG_NT_CTRL 0xa4
#define REG_BD50MAX 0xa5 #define REG_AECGMAX 0xa5
#define REG_HAECC3 0xa6 #define REG_LPH 0xa6
#define REG_HAECC4 0xa7 #define REG_UPL 0xa7
#define REG_HAECC5 0xa8 #define REG_TPL 0xa8
#define REG_HAECC6 0xa9 #define REG_TPH 0xa9
#define REG_HAECC7 0xaa #define REG_NALG 0xaa
#define REG_BD60MAX 0xab #define REG_BD60MAX 0xab
#define REG_STR_OPT 0xac #define REG_STR_OPT 0xac
#define REG_STR_R 0xad #define REG_STR_R 0xad
@ -156,10 +156,13 @@ static volatile int FrameCount = 0;
volatile int Camera_Captured = 0; volatile int Camera_Captured = 0;
static unsigned int BlackPixels = 0; static unsigned int BlackPixels = 0;
#ifdef CAMERA_USE_EXPOSURE_CORRECTION #ifdef CONFIG_USE_EXPOSURE_CORRECTION
static volatile int ExposureCorrection = 0; static volatile int ExposureCorrection = 0;
#endif #endif
volatile unsigned int Camera_BlackPixelCounts[] = {0};
volatile int Camera_FinalFrameCount = -1;
static uint8_t ReadRegister(uint8_t reg) static uint8_t ReadRegister(uint8_t reg)
{ {
while(I2C1->SR2 & I2C_SR2_BUSY); while(I2C1->SR2 & I2C_SR2_BUSY);
@ -301,6 +304,24 @@ void Camera_Init(void)
WriteRegister(REG_COM14, 0x18 | 1); WriteRegister(REG_COM14, 0x18 | 1);
WriteRegister(REG_SCALING_PCLK_DIV, 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. // Enable VSYNC interrupts. TIM3 is enabled at the first VSYNC.
FrameCount = 0; FrameCount = 0;
Camera_Captured = 0; Camera_Captured = 0;
@ -327,20 +348,34 @@ void TIM1_CC_IRQHandler(void)
CurrentLine = 0; CurrentLine = 0;
FrameCount++; FrameCount++;
#ifdef CAMERA_USE_EXPOSURE_CORRECTION #ifdef CONFIG_USE_EXPOSURE_CORRECTION
// Correct exposure across frames // Correct exposure across frames
ExposureCorrection += 32 * BlackPixels / CAMERA_PIXELS - 16; ExposureCorrection += 32 * BlackPixels / CAMERA_PIXELS - 16;
#endif #endif
// Check if the last frame's exposure is reasonable // 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_Captured = 1;
Camera_FinalFrameCount = FrameCount;
// Disable everything // Disable everything
TIM3->CR1 = 0; TIM3->CR1 = 0;
TIM1->CR1 = 0; TIM1->CR1 = 0;
} }
if(FrameCount < (int)(sizeof(Camera_BlackPixelCounts)
/ sizeof(Camera_BlackPixelCounts[0])))
{
Camera_BlackPixelCounts[FrameCount] = BlackPixels;
}
// Reset black pixel counter // Reset black pixel counter
BlackPixels = 0; BlackPixels = 0;
@ -361,7 +396,7 @@ void TIM3_IRQHandler(void)
DMA1_Channel6->CCR = DMA_CCR_PL | DMA_CCR_MINC | DMA_CCR_EN; DMA1_Channel6->CCR = DMA_CCR_PL | DMA_CCR_MINC | DMA_CCR_EN;
TIM3->DIER |= TIM_DIER_CC1DE; 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}; static int8_t y_errors[CAMERA_IMAGE_WIDTH + 2] = {0};
if(CurrentLine == 0) if(CurrentLine == 0)
@ -374,7 +409,7 @@ void TIM3_IRQHandler(void)
&& (CurrentLine / 2 < CAMERA_IMAGE_HEIGHT)) && (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 // Apply errors propagated from the previous line. Since y_errors is
// overwritten during x error diffusion, this is done now. // overwritten during x error diffusion, this is done now.
for(int i = 0; i < CAMERA_IMAGE_WIDTH; i++) 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++) for(int i = 0; i < CAMERA_IMAGE_WIDTH; i++)
{ {
int pixel = LineBuffer[i + 15] + x_error; int pixel = LineBuffer[i + 15] + x_error;
#ifdef CAMERA_USE_EXPOSURE_CORRECTION #ifdef CONFIG_USE_EXPOSURE_CORRECTION
if(ExposureCorrection < 0) if(ExposureCorrection < 0)
{ {
if(pixel < -ExposureCorrection) if(pixel < -ExposureCorrection)
@ -421,7 +456,7 @@ void TIM3_IRQHandler(void)
~(0x80 >> (i % 8)); ~(0x80 >> (i % 8));
} }
#ifdef CAMERA_USE_2D_DITHERING #ifdef CONFIG_USE_2D_DITHERING
// Error propagated to the next pixel in the same line // Error propagated to the next pixel in the same line
x_error = error * 7 / 16; x_error = error * 7 / 16;

View file

@ -2,19 +2,16 @@
#include <stdlib.h> #include <stdlib.h>
#include "stm32f1xx.h" #include "stm32f1xx.h"
#include "config.h"
#define CAMERA_IMAGE_WIDTH 160 #define CAMERA_IMAGE_WIDTH 160
#define CAMERA_IMAGE_HEIGHT 144 #define CAMERA_IMAGE_HEIGHT 144
#define CAMERA_PIXELS (CAMERA_IMAGE_WIDTH * CAMERA_IMAGE_HEIGHT) #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 int Camera_Captured;
extern volatile unsigned int Camera_BlackPixelCounts[CONFIG_MAX_FRAMES];
extern volatile int Camera_FinalFrameCount;
void Camera_Init(void); void Camera_Init(void);