add exposure controls

This commit is contained in:
Michele Balistreri 2024-03-04 11:44:42 +01:00
parent 9e152a4963
commit ea0401a087
No known key found for this signature in database
GPG Key ID: E9567DA33A4F791A
5 changed files with 144 additions and 34 deletions

View File

@ -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);
}

View File

@ -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__ */

View File

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

View File

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

View File

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