Commit a1b1048b authored by Alejandro Homs Puron's avatar Alejandro Homs Puron Committed by operator for beamline
Browse files

Merge branch 'fix_timing_ranges' into 'fix_v3.1.1_issues'

parents 41445775 e7bf69e6
......@@ -150,7 +150,7 @@ enum ClockDiv {
FullSpeed,
HalfSpeed,
QuarterSpeed,
SuperSlowSpeed,
SuperSlowSpeed,
};
enum DetStatus {
......
......@@ -78,6 +78,10 @@ class Eiger : public Model
FloatList& min_val_list);
virtual void getTimeRanges(TimeRanges& time_ranges);
static void calcTimeRanges(PixelDepth pixel_depth,
ClockDiv clock_div,
ParallelMode parallel_mode,
TimeRanges& time_ranges);
// the returned object must be deleted by the caller
Correction *createCorrectionTask();
......@@ -89,6 +93,8 @@ class Eiger : public Model
void getFixedClockDiv(bool& fixed_clock_div);
void setClockDiv(ClockDiv clock_div);
void getClockDiv(ClockDiv& clock_div);
void setSubExpTime(double sub_exp_time);
void getSubExpTime(double& sub_exp_time);
void setAllTrimBits(int sub_mod_idx, int val);
void getAllTrimBits(int sub_mod_idx, int& val);
......@@ -338,9 +344,6 @@ class Eiger : public Model
int getNbEigerModules()
{ return getNbDetModules() / 2; }
static double KiloHzPeriod(double f)
{ return 1e6 / (f * 1e3); }
void getRecvFrameDim(FrameDim& frame_dim, bool raw, bool geom);
CorrBase *createBadRecvFrameCorr();
......@@ -360,6 +363,22 @@ class Eiger : public Model
static const int HalfModuleChips;
static const int RecvPorts;
struct LinScale {
double factor, offset;
LinScale(double f, double o) : factor(f), offset(o) {}
double calcY(double x) const
{ return x * factor + offset; }
double calcX(double y) const
{ return (y - offset) / factor; }
};
static const int BitsPerXfer;
static const int SuperColNbCols;
static const double BaseChipXferFreq;
static const double MaxFebBebBandwidth;
static const LinScale ChipXfer2Buff;
static const LinScale ChipRealReadout;
FrameDim m_recv_frame_dim;
CorrList m_corr_list;
PortGeometryList m_port_geom_list;
......
......@@ -65,6 +65,10 @@ class Eiger : public SlsDetector::Model
std::vector<double>& min_val_list /Out/);
virtual void getTimeRanges(SlsDetector::TimeRanges& time_ranges /Out/);
static void calcTimeRanges(SlsDetector::PixelDepth pixel_depth,
SlsDetector::Defs::ClockDiv clock_div,
SlsDetector::Eiger::ParallelMode parallel_mode,
SlsDetector::TimeRanges& time_ranges /Out/);
void setParallelMode(SlsDetector::Eiger::ParallelMode mode);
void getParallelMode(SlsDetector::Eiger::ParallelMode& mode);
......@@ -73,6 +77,8 @@ class Eiger : public SlsDetector::Model
void getFixedClockDiv(bool& fixed_clock_div);
void setClockDiv(SlsDetector::Defs::ClockDiv clock_div);
void getClockDiv(SlsDetector::Defs::ClockDiv& clock_div /Out/);
void setSubExpTime(double sub_exp_time);
void getSubExpTime(double& sub_exp_time /Out/);
void setAllTrimBits(int sub_mod_idx, int val);
void getAllTrimBits(int sub_mod_idx, int& val /Out/);
......
......@@ -33,6 +33,13 @@ const int Eiger::ChipGap = 2;
const int Eiger::HalfModuleChips = 4;
const int Eiger::RecvPorts = 2;
const int Eiger::BitsPerXfer = 4;
const int Eiger::SuperColNbCols = 8;
const double Eiger::BaseChipXferFreq = 200; // Mbit/s
const double Eiger::MaxFebBebBandwidth = 25600; // Mbit/s
const Eiger::LinScale Eiger::ChipXfer2Buff(2.59, 0.85);
const Eiger::LinScale Eiger::ChipRealReadout(1.074, -4);
Eiger::CorrBase::CorrBase(Eiger *eiger)
: m_eiger(eiger)
{
......@@ -464,52 +471,74 @@ void Eiger::getTimeRanges(TimeRanges& time_ranges)
{
DEB_MEMBER_FUNCT();
PixelDepth pixel_depth;
Camera* cam = getCamera();
ParallelMode parallel_mode;
getParallelMode(parallel_mode);
cam->getPixelDepth(pixel_depth);
ClockDiv clock_div;
getClockDiv(clock_div);
PixelDepth pixel_depth;
cam->getPixelDepth(pixel_depth);
ParallelMode parallel_mode;
getParallelMode(parallel_mode);
calcTimeRanges(pixel_depth, clock_div, parallel_mode, time_ranges);
}
void Eiger::calcTimeRanges(PixelDepth pixel_depth, ClockDiv clock_div,
ParallelMode parallel_mode,
TimeRanges& time_ranges)
{
DEB_STATIC_FUNCT();
DEB_PARAM() << DEB_VAR3(pixel_depth, clock_div, parallel_mode);
// times are in usec, freq in MHz
int period_factor = 1 << int(clock_div);
double xfer_freq = BaseChipXferFreq / period_factor;
DEB_TRACE() << DEB_VAR2(period_factor, xfer_freq);
double xfer_2_buff = ChipXfer2Buff.calcY(period_factor);
DEB_TRACE() << DEB_VAR1(xfer_2_buff);
const int super_col_pixels = SuperColNbCols * ChipSize;
double theo_single_readout = super_col_pixels * BitsPerXfer / xfer_freq;
// theoretical -> measured correction
double real_single_readout = ChipRealReadout.calcY(theo_single_readout);
DEB_TRACE() << DEB_VAR2(theo_single_readout, real_single_readout);
int readout_cycles;
if (pixel_depth == PixelDepth4)
readout_cycles = 1;
else if (pixel_depth == PixelDepth8)
readout_cycles = 2;
else
readout_cycles = 3;
double min_chip_readout = real_single_readout * readout_cycles;
DEB_TRACE() << DEB_VAR2(readout_cycles, min_chip_readout);
int mem_xfer_blocks = pixel_depth / BitsPerXfer;
const int nb_super_cols = ChipSize / SuperColNbCols * HalfModuleChips;
double feb_beb_bw = (xfer_freq * nb_super_cols / readout_cycles *
mem_xfer_blocks);
DEB_TRACE() << DEB_VAR2(feb_beb_bw, MaxFebBebBandwidth);
double chip_readout = min_chip_readout;
if (feb_beb_bw > MaxFebBebBandwidth) {
chip_readout *= feb_beb_bw / MaxFebBebBandwidth;
DEB_TRACE() << "limiting chip readout freq: "
<< DEB_VAR2(min_chip_readout, chip_readout);
}
double full_readout = xfer_2_buff + chip_readout;
DEB_TRACE() << DEB_VAR1(full_readout);
bool parallel = (parallel_mode == Parallel);
double min_exp = 10;
double min_lat = 500;
double min_period = 500;
double max_freq_p = 0;
double readout_p = 0;
double readout_np = 0;
if (pixel_depth == PixelDepth4) {
min_lat = 10;
min_period = KiloHzPeriod(22);
} else if (pixel_depth == PixelDepth8) {
min_lat = 10;
min_period = KiloHzPeriod(11);
} else if (pixel_depth == PixelDepth16) {
if (clock_div == FullSpeed) {
max_freq_p = 6;
readout_p = 2.75;
readout_np = 126;
} else if (clock_div == HalfSpeed) {
max_freq_p = 2.9;
readout_p = 5.36;
readout_np = 252;
} else if (clock_div == QuarterSpeed) {
max_freq_p = 1.5;
readout_p = 10.6;
readout_np = 504;
}
} else if (clock_div == QuarterSpeed) {
max_freq_p = 2;
readout_p = 10.6;
readout_np = 504;
}
double min_period = (parallel ? 0 : min_exp) + full_readout;
double min_lat = parallel ? xfer_2_buff : full_readout;
if (max_freq_p * readout_p * readout_np != 0) {
min_lat = parallel ? readout_p : readout_np;
min_period = min_lat + KiloHzPeriod(max_freq_p) - readout_p;
}
// Timing hardware uses 32-bit, base-10 floating-point registers:
// 29 bits: mantissa
// 3 bits: exponent
// Time unit: 10 nsec
// Max value: 2^29 * 10^(2^3 - 1) * 10 nsec = 1.7 years
// Using 1000 sec as a reasonable upper limit
time_ranges.min_exp_time = min_exp * 1e-6;
time_ranges.max_exp_time = 1e3;
......@@ -537,8 +566,10 @@ void Eiger::updateImageSize()
if (isPixelDepth4())
createPixelDepth4Corr();
Camera *cam = getCamera();
bool raw;
getCamera()->getRawMode(raw);
cam->getRawMode(raw);
if (raw)
return;
......@@ -548,7 +579,11 @@ void Eiger::updateImageSize()
if (getNbEigerModules() > 1)
createInterModGapCorr();
if (m_fixed_clock_div) {
PixelDepth pixel_depth;
cam->getPixelDepth(pixel_depth);
if (pixel_depth == PixelDepth32) {
setClockDiv(QuarterSpeed);
} else if (m_fixed_clock_div) {
ClockDiv curr_clock_div;
getClockDiv(curr_clock_div);
if (curr_clock_div != m_clock_div) {
......@@ -589,6 +624,7 @@ void Eiger::setParallelMode(ParallelMode mode)
DEB_MEMBER_FUNCT();
DEB_PARAM() << DEB_VAR1(mode);
m_det->setParallelMode(mode);
updateTimeRanges();
}
void Eiger::getParallelMode(ParallelMode& mode)
......@@ -616,6 +652,14 @@ void Eiger::setClockDiv(ClockDiv clock_div)
{
DEB_MEMBER_FUNCT();
DEB_PARAM() << DEB_VAR1(clock_div);
if (clock_div == SuperSlowSpeed)
THROW_HW_ERROR(NotSupported) << "SuperSlowSpeed not tested yet";
PixelDepth pixel_depth;
Camera* cam = getCamera();
cam->getPixelDepth(pixel_depth);
if ((pixel_depth == PixelDepth32) && (clock_div != QuarterSpeed))
THROW_HW_ERROR(InvalidValue) << "32-bit works only on "
<< "QuarterSpeed";
m_det->setClockDivider(clock_div);
m_clock_div = clock_div;
updateTimeRanges();
......@@ -631,6 +675,22 @@ void Eiger::getClockDiv(ClockDiv& clock_div)
DEB_RETURN() << DEB_VAR1(clock_div);
}
void Eiger::setSubExpTime(double sub_exp_time)
{
DEB_MEMBER_FUNCT();
DEB_PARAM() << DEB_VAR1(sub_exp_time);
if (sub_exp_time != 0)
THROW_HW_ERROR(NotSupported) << "SubExpTime not supported";
updateTimeRanges();
}
void Eiger::getSubExpTime(double& sub_exp_time)
{
DEB_MEMBER_FUNCT();
sub_exp_time = 0;
DEB_RETURN() << DEB_VAR1(sub_exp_time);
}
void Eiger::setAllTrimBits(int sub_mod_idx, int val)
{
DEB_MEMBER_FUNCT();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment