Merge branch 'genesys-analog-devices-adc-calibration' into 'master'

genesys: Implement gain calibration for Analog-Devices ADC

See merge request sane-project/backends!176
merge-requests/177/merge
Povilas Kanapickas 2019-09-27 21:32:02 +00:00
commit 7a8da5c40b
3 zmienionych plików z 78 dodań i 29 usunięć

Wyświetl plik

@ -3069,40 +3069,17 @@ static void gl843_coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sen
// pick target value at 95th percentile of all values. There may be a lot of black values
// in transparency scans for example
std::sort(values.begin(), values.end());
uint16_t target_value = values[unsigned((values.size() - 1) * 0.95)];
uint16_t curr_output = values[unsigned((values.size() - 1) * 0.95)];
if (bpp == 16) {
target_value /= 256;
curr_output /= 256;
}
float target_value = calib_sensor.gain_white_ref * coeff;
/* the flow of data through the frontend ADC is as follows (see e.g. VM8192 datasheet)
input
-> apply offset (o = i + 260mV * (DAC[7:0]-127.5)/127.5) ->
-> apply gain (o = i * 208/(283-PGA[7:0])
-> ADC
Here we have some input data that was acquired with zero gain (PGA==0).
We want to compute gain such that the output would approach full ADC range (controlled by
gain_white_ref).
We want to solve the following for {PGA}:
{input} * 208 / (283 - 0) = {output}
{input} * 208 / (283 - {PGA}) = {target output}
The solution is the following equation:
{PGA} = 283 * (1 - {output} / {target output})
*/
float gain = ((float) target_value / (calib_sensor.gain_white_ref*coeff));
int code = 283 * (1 - gain);
if (code > 255)
code = 255;
else if (code < 0)
code = 0;
int code = compute_frontend_gain(curr_output, target_value, dev->frontend.layout.type);
dev->frontend.set_gain(j, code);
DBG(DBG_proc, "%s: channel %d, max=%d, gain = %f, setting:%d\n", __func__, j, target_value,
gain, code);
DBG(DBG_proc, "%s: channel %d, max=%d, target=%d, setting:%d\n", __func__, j, curr_output,
(int) target_value, code);
}
if (dev->model->is_cis) {

Wyświetl plik

@ -1387,6 +1387,65 @@ void compute_session(Genesys_Device* dev, ScanSession& s, const Genesys_Sensor&
compute_session_buffer_sizes(dev->model->asic_type, s);
}
std::uint8_t compute_frontend_gain_wolfson(float value, float target_value)
{
/* the flow of data through the frontend ADC is as follows (see e.g. WM8192 datasheet)
input
-> apply offset (o = i + 260mV * (DAC[7:0]-127.5)/127.5) ->
-> apply gain (o = i * 208/(283-PGA[7:0])
-> ADC
Here we have some input data that was acquired with zero gain (PGA==0).
We want to compute gain such that the output would approach full ADC range (controlled by
target_value).
We want to solve the following for {PGA}:
{value} = {input} * 208 / (283 - 0)
{target_value} = {input} * 208 / (283 - {PGA})
The solution is the following equation:
{PGA} = 283 * (1 - {value} / {target_value})
*/
float gain = value / target_value;
int code = 283 * (1 - gain);
return clamp(code, 0, 255);
}
std::uint8_t compute_frontend_gain_analog_devices(float value, float target_value)
{
/* The flow of data through the frontend ADC is as follows (see e.g. AD9826 datasheet)
input
-> apply offset (o = i + 300mV * (OFFSET[8] ? 1 : -1) * (OFFSET[7:0] / 127)
-> apply gain (o = i * 6 / (1 + 5 * ( 63 - PGA[5:0] ) / 63 ) )
-> ADC
We want to solve the following for {PGA}:
{value} = {input} * 6 / (1 + 5 * ( 63 - 0) / 63 ) )
{target_value} = {input} * 6 / (1 + 5 * ( 63 - {PGA}) / 63 ) )
The solution is the following equation:
{PGA} = (378 / 5) * ({target_value} - {value} / {target_value})
*/
int code = static_cast<int>((378.0f / 5.0f) * ((target_value - value) / target_value));
return clamp(code, 0, 63);
}
std::uint8_t compute_frontend_gain(float value, float target_value,
FrontendType frontend_type)
{
if (frontend_type == FrontendType::WOLFSON) {
return compute_frontend_gain_wolfson(value, target_value);
}
if (frontend_type == FrontendType::ANALOG_DEVICES) {
return compute_frontend_gain_analog_devices(value, target_value);
}
throw SaneException("Unknown frontend to compute gain for");
}
const SensorProfile& get_sensor_profile(AsicType asic_type, const Genesys_Sensor& sensor,
unsigned dpi, unsigned ccd_size_divisor)
{

Wyświetl plik

@ -640,6 +640,9 @@ void compute_session(Genesys_Device* dev, ScanSession& s, const Genesys_Sensor&
void genesys_fill_segmented_buffer(Genesys_Device* dev, uint8_t* work_buffer_dst, size_t size);
std::uint8_t compute_frontend_gain(float value, float target_value,
FrontendType frontend_type);
const SensorProfile& get_sensor_profile(AsicType asic_type, const Genesys_Sensor& sensor,
unsigned dpi, unsigned ccd_size_divisor);
@ -672,6 +675,16 @@ inline uint64_t multiply_by_depth_ceil(uint64_t pixels, uint64_t depth)
}
}
template<class T>
inline T clamp(const T& value, const T& lo, const T& hi)
{
if (value < lo)
return lo;
if (value > hi)
return hi;
return value;
}
/*---------------------------------------------------------------------------*/
/* ASIC specific functions declarations */
/*---------------------------------------------------------------------------*/