add exposure controls
This commit is contained in:
parent
9e152a4963
commit
ea0401a087
|
@ -4,15 +4,23 @@
|
||||||
#include "FreeRTOS.h"
|
#include "FreeRTOS.h"
|
||||||
#include "task.h"
|
#include "task.h"
|
||||||
|
|
||||||
|
#define _CAM_REG_NULL 0xFFFF
|
||||||
|
#define _CAM_REG_DELAY 0x0000
|
||||||
|
#define CAMERA_SETTLE_MS 10
|
||||||
|
#define CAMERA_FRAME_TIMEOUT 100
|
||||||
|
|
||||||
|
struct camera_regval {
|
||||||
|
uint16_t addr;
|
||||||
|
uint8_t val;
|
||||||
|
};
|
||||||
|
|
||||||
#if _CAM_MODEL == SC031GS
|
#if _CAM_MODEL == SC031GS
|
||||||
#include "sc031gs.h"
|
#include "sc031gs.h"
|
||||||
#else
|
#else
|
||||||
#error _CAM_MODEL must be defined
|
#error _CAM_MODEL must be defined
|
||||||
#endif
|
#endif
|
||||||
APP_NOCACHE(uint8_t g_camera_fb[CAMERA_FB_COUNT][CAMERA_FB_SIZE], CAMERA_BUFFER_ALIGN);
|
|
||||||
|
|
||||||
#define CAMERA_SETTLE_MS 10
|
APP_NOCACHE(uint8_t g_camera_fb[CAMERA_FB_COUNT][CAMERA_FB_SIZE], CAMERA_BUFFER_ALIGN);
|
||||||
#define CAMERA_FRAME_TIMEOUT 100
|
|
||||||
|
|
||||||
hal_err_t _camera_reset() {
|
hal_err_t _camera_reset() {
|
||||||
hal_gpio_set(GPIO_CAMERA_PWR, GPIO_SET);
|
hal_gpio_set(GPIO_CAMERA_PWR, GPIO_SET);
|
||||||
|
@ -36,19 +44,19 @@ hal_err_t _camera_load_reg(uint16_t addr, uint8_t val) {
|
||||||
return hal_i2c_send(I2C_CAMERA, _CAM_I2C_ADDR, buf, 3);
|
return hal_i2c_send(I2C_CAMERA, _CAM_I2C_ADDR, buf, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
hal_err_t _camera_load_regs() {
|
hal_err_t _camera_load_regs(const struct camera_regval regs[]) {
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
hal_err_t err = HAL_SUCCESS;
|
hal_err_t err = HAL_SUCCESS;
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
switch(camera_regs[i].addr) {
|
switch(regs[i].addr) {
|
||||||
case _CAM_REG_DELAY:
|
case _CAM_REG_DELAY:
|
||||||
vTaskDelay(pdMS_TO_TICKS(camera_regs[i].val));
|
vTaskDelay(pdMS_TO_TICKS(regs[i].val));
|
||||||
break;
|
break;
|
||||||
case _CAM_REG_NULL:
|
case _CAM_REG_NULL:
|
||||||
goto finish;
|
goto finish;
|
||||||
default:
|
default:
|
||||||
err = _camera_load_reg(camera_regs[i].addr, camera_regs[i].val);
|
err = _camera_load_reg(regs[i].addr, regs[i].val);
|
||||||
if (err != HAL_SUCCESS) {
|
if (err != HAL_SUCCESS) {
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
@ -73,7 +81,7 @@ hal_err_t camera_start() {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((err = _camera_load_regs()) != HAL_SUCCESS) {
|
if ((err = _camera_load_regs(camera_regs)) != HAL_SUCCESS) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,3 +108,21 @@ hal_err_t camera_next_frame(uint8_t** frame) {
|
||||||
hal_err_t camera_submit(uint8_t* frame) {
|
hal_err_t camera_submit(uint8_t* frame) {
|
||||||
return hal_camera_submit(frame);
|
return hal_camera_submit(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hal_err_t camera_set_exposure(camera_exposure_t exposure) {
|
||||||
|
struct camera_regval regs[3];
|
||||||
|
_camera_exposure_regs(regs, exposure);
|
||||||
|
return _camera_load_regs(regs);
|
||||||
|
}
|
||||||
|
|
||||||
|
hal_err_t camera_set_analog_gain(uint8_t gain) {
|
||||||
|
struct camera_regval regs[3];
|
||||||
|
_camera_analog_gain_regs(regs, gain);
|
||||||
|
return _camera_load_regs(regs);
|
||||||
|
}
|
||||||
|
|
||||||
|
hal_err_t camera_set_digital_gain(uint8_t gain) {
|
||||||
|
struct camera_regval regs[3];
|
||||||
|
_camera_digital_gain_regs(regs, gain);
|
||||||
|
return _camera_load_regs(regs);
|
||||||
|
}
|
||||||
|
|
|
@ -3,14 +3,17 @@
|
||||||
|
|
||||||
#include "hal.h"
|
#include "hal.h"
|
||||||
|
|
||||||
#define _CAM_REG_NULL 0xFFFF
|
|
||||||
#define _CAM_REG_DELAY 0X0000
|
|
||||||
#define _CAM_MODEL SC031GS
|
#define _CAM_MODEL SC031GS
|
||||||
|
#define CAMERA_MAX_ANALOG_GAIN 16
|
||||||
|
#define CAMERA_MAX_DIGITAL_GAIN 8
|
||||||
|
|
||||||
struct camera_regval {
|
typedef enum {
|
||||||
uint16_t addr;
|
EXPOSURE_500,
|
||||||
uint8_t val;
|
EXPOSURE_400,
|
||||||
};
|
EXPOSURE_300,
|
||||||
|
EXPOSURE_250,
|
||||||
|
EXPOSURE_125,
|
||||||
|
} camera_exposure_t;
|
||||||
|
|
||||||
hal_err_t camera_start();
|
hal_err_t camera_start();
|
||||||
hal_err_t camera_stop();
|
hal_err_t camera_stop();
|
||||||
|
@ -18,4 +21,8 @@ hal_err_t camera_stop();
|
||||||
hal_err_t camera_next_frame(uint8_t** frame);
|
hal_err_t camera_next_frame(uint8_t** frame);
|
||||||
hal_err_t camera_submit(uint8_t* frame);
|
hal_err_t camera_submit(uint8_t* frame);
|
||||||
|
|
||||||
|
hal_err_t camera_set_exposure(camera_exposure_t exposure);
|
||||||
|
hal_err_t camera_set_analog_gain(uint8_t gain);
|
||||||
|
hal_err_t camera_set_digital_gain(uint8_t gain);
|
||||||
|
|
||||||
#endif /* __CAMERA_H__ */
|
#endif /* __CAMERA_H__ */
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
|
|
||||||
static const struct camera_regval camera_regs[] = {
|
static const struct camera_regval camera_regs[] = {
|
||||||
{0x0103, 0x01}, // soft reset.
|
{0x0103, 0x01}, // soft reset.
|
||||||
{_CAM_REG_DELAY, 10}, // delay.
|
{_CAM_REG_DELAY, 10},
|
||||||
{0x0100,0x00},
|
{0x0100,0x00},
|
||||||
{0x300f,0x0f},
|
{0x300f,0x0f},
|
||||||
{0x3018,0x1f},
|
{0x3018,0x1f},
|
||||||
|
@ -125,12 +125,12 @@ static const struct camera_regval camera_regs[] = {
|
||||||
{0x3908,0x91},
|
{0x3908,0x91},
|
||||||
{0x3d08,0x01},
|
{0x3d08,0x01},
|
||||||
SC031GS_GAIN_CFG_TABLE,
|
SC031GS_GAIN_CFG_TABLE,
|
||||||
{SC031GS_EXPOSURE_H_REG,0x0f},
|
{SC031GS_EXPOSURE_H_REG,0x0e},
|
||||||
{SC031GS_EXPOSURE_L_REG,0xa0},
|
{SC031GS_EXPOSURE_L_REG,0x13},
|
||||||
{SC031GS_GAIN_ANALOG_H_REG,0x07},
|
{SC031GS_GAIN_ANALOG_H_REG,0x01},
|
||||||
{SC031GS_GAIN_ANALOG_L_REG,0x1f},
|
{SC031GS_GAIN_ANALOG_L_REG,0x10},
|
||||||
{SC031GS_GAIN_DIGITAL_H_REG,0x03},
|
{SC031GS_GAIN_DIGITAL_H_REG,0x01},
|
||||||
{SC031GS_GAIN_DIGITAL_L_REG,0x80},
|
{SC031GS_GAIN_DIGITAL_L_REG,0x10},
|
||||||
{0x4500,0x59},
|
{0x4500,0x59},
|
||||||
{0x4501,0xc4},
|
{0x4501,0xc4},
|
||||||
{0x5011,0x00},
|
{0x5011,0x00},
|
||||||
|
@ -143,6 +143,47 @@ static const struct camera_regval camera_regs[] = {
|
||||||
{0x3317,0x0f},
|
{0x3317,0x0f},
|
||||||
{_CAM_REG_NULL, 0x00},
|
{_CAM_REG_NULL, 0x00},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const uint16_t _camera_exposure_table[] = {
|
||||||
|
0x0e13, 0x1198, 0x1776, 0x1c27, 0x384e
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint16_t _camera_analog_gain_table[] = {
|
||||||
|
0x0010, 0x0110, 0x0118, 0x0310, 0x0314, 0x0318, 0x031c, 0x0710,
|
||||||
|
0x0712, 0x0714, 0x0716, 0x0718, 0x071a, 0x071c, 0x071e, 0x071f
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint16_t _camera_digital_gain_table[] = {
|
||||||
|
0x0080, 0x0180, 0x01c0, 0x0380, 0x03a0, 0x03c0, 0x03e0, 0x03f8,
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void _camera_exposure_regs(struct camera_regval regs[3], camera_exposure_t exposure) {
|
||||||
|
uint16_t val = _camera_exposure_table[exposure];
|
||||||
|
regs[0].addr = SC031GS_EXPOSURE_H_REG;
|
||||||
|
regs[0].val = val >> 8;
|
||||||
|
regs[1].addr = SC031GS_EXPOSURE_L_REG;
|
||||||
|
regs[1].val = val & 0xff;
|
||||||
|
regs[2].addr = _CAM_REG_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void _camera_analog_gain_regs(struct camera_regval regs[3], uint8_t gain) {
|
||||||
|
uint16_t val = _camera_analog_gain_table[gain - 1];
|
||||||
|
regs[0].addr = SC031GS_GAIN_ANALOG_H_REG;
|
||||||
|
regs[0].val = val >> 8;
|
||||||
|
regs[1].addr = SC031GS_GAIN_ANALOG_L_REG;
|
||||||
|
regs[1].val = val & 0xff;
|
||||||
|
regs[2].addr = _CAM_REG_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void _camera_digital_gain_regs(struct camera_regval regs[3], uint8_t gain) {
|
||||||
|
uint16_t val = _camera_digital_gain_table[gain - 1];
|
||||||
|
regs[0].addr = SC031GS_GAIN_DIGITAL_H_REG;
|
||||||
|
regs[0].val = val >> 8;
|
||||||
|
regs[1].addr = SC031GS_GAIN_DIGITAL_L_REG;
|
||||||
|
regs[1].val = val & 0xff;
|
||||||
|
regs[2].addr = _CAM_REG_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#error This file must be only imported once.
|
#error This file must be only imported once.
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -838,16 +838,7 @@ void quirc_threshold(struct quirc *q)
|
||||||
quirc_pixel_t *row = q->pixels;
|
quirc_pixel_t *row = q->pixels;
|
||||||
int width = q->w;
|
int width = q->w;
|
||||||
|
|
||||||
/*
|
fracmul = (32768 * (threshold_s - 1)) / threshold_s; // to use multiply instead of divide (not too many bits or we'll overflow)
|
||||||
* Ensure a sane, non-zero value for threshold_s.
|
|
||||||
*
|
|
||||||
* threshold_s can be zero if the image width is small. We need to avoid
|
|
||||||
* SIGFPE as it will be used as divisor.
|
|
||||||
*/
|
|
||||||
if (threshold_s < THRESHOLD_S_MIN)
|
|
||||||
threshold_s = THRESHOLD_S_MIN;
|
|
||||||
|
|
||||||
fracmul = (32768 * (threshold_s - 1)) / threshold_s; // to use multipy instead of divide (not too many bits or we'll overflow)
|
|
||||||
// to get the effect used below (a fraction of threshold_s-1/threshold_s
|
// to get the effect used below (a fraction of threshold_s-1/threshold_s
|
||||||
// The second constant is to reduce the averaged values to compare with the current pixel
|
// The second constant is to reduce the averaged values to compare with the current pixel
|
||||||
fracmul2 = (0x100000 * (100 - THRESHOLD_T)) / (200 * threshold_s); // use as many bits as possible without overflowing
|
fracmul2 = (0x100000 * (100 - THRESHOLD_T)) / (200 * threshold_s); // use as many bits as possible without overflowing
|
||||||
|
|
|
@ -83,6 +83,14 @@ app_err_t qrscan_scan() {
|
||||||
uint16_t score = QR_SCORE_RED;
|
uint16_t score = QR_SCORE_RED;
|
||||||
uint16_t prev_color = 0;
|
uint16_t prev_color = 0;
|
||||||
|
|
||||||
|
camera_exposure_t exposure = EXPOSURE_500;
|
||||||
|
uint8_t again = 1;
|
||||||
|
uint8_t dgain = 1;
|
||||||
|
|
||||||
|
camera_set_exposure(exposure);
|
||||||
|
camera_set_analog_gain(again);
|
||||||
|
camera_set_digital_gain(dgain);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (camera_next_frame(&fb) != HAL_SUCCESS) {
|
if (camera_next_frame(&fb) != HAL_SUCCESS) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -138,9 +146,46 @@ app_err_t qrscan_scan() {
|
||||||
|
|
||||||
keypad_key_t k = ui_wait_keypress(0);
|
keypad_key_t k = ui_wait_keypress(0);
|
||||||
|
|
||||||
if ((k == KEYPAD_KEY_CANCEL) || (k == KEYPAD_KEY_BACK)) {
|
if (k != KEYPAD_KEY_INVALID) {
|
||||||
res = ERR_CANCEL;
|
switch(k) {
|
||||||
goto end;
|
case KEYPAD_KEY_1:
|
||||||
|
if (exposure < EXPOSURE_125) {
|
||||||
|
camera_set_exposure(++exposure);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KEYPAD_KEY_7:
|
||||||
|
if (exposure > EXPOSURE_500) {
|
||||||
|
camera_set_exposure(--exposure);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KEYPAD_KEY_2:
|
||||||
|
if (again < CAMERA_MAX_ANALOG_GAIN) {
|
||||||
|
camera_set_analog_gain(++again);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KEYPAD_KEY_8:
|
||||||
|
if (again > 1) {
|
||||||
|
camera_set_analog_gain(--again);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KEYPAD_KEY_3:
|
||||||
|
if (again < CAMERA_MAX_DIGITAL_GAIN) {
|
||||||
|
camera_set_digital_gain(++dgain);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KEYPAD_KEY_9:
|
||||||
|
if (dgain > 1) {
|
||||||
|
camera_set_digital_gain(--dgain);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KEYPAD_KEY_CANCEL:
|
||||||
|
case KEYPAD_KEY_BACK:
|
||||||
|
res = ERR_CANCEL;
|
||||||
|
goto end;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue