From 974be4ec828449f09a8dab89e4a8cbb22dc8eff9 Mon Sep 17 00:00:00 2001 From: Markus Rosenstihl Date: Mon, 19 Dec 2016 14:03:14 +0000 Subject: [PATCH] AD579 driver 2nd revision --- drivers/DAC-AD5791/AD5791.cpp | 443 +++++++++++------- drivers/DAC-AD5791/AD5791.h | 1 + .../Spectrum-MI40xxSeries.cpp | 10 +- 3 files changed, 269 insertions(+), 185 deletions(-) diff --git a/drivers/DAC-AD5791/AD5791.cpp b/drivers/DAC-AD5791/AD5791.cpp index 1dc40b0..f485edc 100644 --- a/drivers/DAC-AD5791/AD5791.cpp +++ b/drivers/DAC-AD5791/AD5791.cpp @@ -3,25 +3,12 @@ * \brief Implementation of the Driver for the AD5791 * Digital to Analog Converter Board * - * This board was first used in the PFG, and gets now - * adopted by the Field-Cycling spectrometers. * * The board inverts all digital inputs. - * This driver partially honors this. - * Especially the data input is not yet inverted. - * -# Inverting the data line is equivalent to inverting - * the value and add/substracting one. - * -# There are different versions of the board around, - * where one board "undoes" the inversion by having an - * inverting op-amp after the DAC. - * -# The digital units have to be calibrated to physical - * units anyway. A sign doesn't hurt much. - * - * This is still a current discussion topic and might - * change. */ #include "AD5791.h" +#include "../../core/states.h" #include #include #include @@ -37,195 +24,291 @@ using std::vector; #endif // The bit depth of the DAC -#define DAC_BIT_DEPTH 24 +#define DAC_DATA_BITS 20 +#define DAC_CONTROL_BITS 4 // The channel configuration #define DATA_BIT 18//18 #define CLK_BIT 16//16 -AD5791::AD5791(int myid): id(myid) { - dac_value = 0; - set_latch_bit(17); + +// this bit needs to be set to write the DAC register +#define WRITE_DAC 1<<20 + + +// software control register +#define RESET 1 +#define CLR 2 +#define LDAC 4 + +// control register +// Linearity error compensation for varying reference input spans. +#define LINCOMP_10V 0*1<<9 + 0*1<<8 + 0*1<<7 + 0*1<<6 +#define LINCOMP_12V 1*1<<9 + 0*1<<8 + 0*1<<7 + 1*1<<6 +#define LINCOMP_16V 1*1<<9 + 0*1<<8 + 1*1<<7 + 0*1<<6 +#define LINCOMP_19V 1*1<<9 + 0*1<<8 + 1*1<<7 + 1*1<<6 +#define LINCOMP_20V 1*1<<9 + 1*1<<8 + 0*1<<7 + 0*1<<6 + +// SDO pin enable/disable control. +#define SDODIS 32 +// DAC register coding select. +#define DAC_CODING_SELECT 16 +// DAC tristate control. +#define DACTRI 8 +// Output ground clamp control. (set by default) +#define OPGND 4 +// Output amplifier configuration control. (set by default) +#define RBUF 2 + + +AD5791::AD5791(int myid) : id(myid) { + dac_value = 0; + set_latch_bit(17); } AD5791::~AD5791() {} // This sets the dac_value void AD5791::set_dac(signed dw) { - dac_value = dw; + dac_value = dw; } -void AD5791::set_latch_bit(int le_bit) -{ - latch_bit = le_bit; +void AD5791::set_latch_bit(int le_bit) { + latch_bit = le_bit; } // This sets the DAC -void AD5791::set_dac(state& experiment) { - - state_sequent* exp_sequence=dynamic_cast(&experiment); - if (exp_sequence == NULL) - // is a very state on top level, todo: change interface - throw pfg_exception( "cannot work on a single state, sorry (todo: change interface)"); - else { - for(state_sequent::iterator child_state = exp_sequence->begin(); child_state != exp_sequence->end(); ++child_state) - set_dac_recursive(*exp_sequence, child_state); +void AD5791::set_dac(state &experiment) { + state_sequent *exp_sequence = dynamic_cast(&experiment); + if (exp_sequence == NULL) + // is a very state on top level, todo: change interface + throw pfg_exception("cannot work on a single state, sorry (todo: change interface)"); + else { + for (state_sequent::iterator child_state = exp_sequence->begin(); + child_state != exp_sequence->end(); ++child_state) + set_dac_recursive(*exp_sequence, child_state); // std::cout << "first state"<< std::endl; - // Set DAC to 0 at start of experiment - set_dac_to_zero(exp_sequence, exp_sequence->begin()); - // And at the end of the experiment - set_dac_to_zero(exp_sequence, exp_sequence->end()); - } + + // Set DAC to 0 at start of experiment + set_dac_to_zero(exp_sequence, exp_sequence->begin()); + // but first initialize DAC + init_dac(exp_sequence, exp_sequence->begin()); + // And at the end of the experiment set DAC to zero + set_dac_to_zero(exp_sequence, exp_sequence->end()); + } } -void AD5791::set_dac_to_zero(state_sequent* exp_sequence, state::iterator where) -{ - state s(TIMING); - ttlout* le=new ttlout(); - le->id=0; - s.push_front(le); - state_sequent* rep_sequence=new state_sequent(); - rep_sequence->repeat=DAC_BIT_DEPTH; - le->ttls = 0 + ( 1 << CLK_BIT ); - rep_sequence->push_back(s.copy_new()); - le->ttls = 0 ; - rep_sequence->push_back(s.copy_new()); - exp_sequence->insert(where, rep_sequence); - //read in the word (41st pulse) - le->ttls=0; - exp_sequence->insert(where, s.copy_new()); - // 42nd pulse - // // the state should be 2ms long - // s.length = 2e-3-41*TIMING; - le->ttls= ( 1 << latch_bit ); - exp_sequence->insert(where, s.copy_new()); +void AD5791::set_dac_to_zero(state_sequent *exp_sequence, state::iterator where) { + // 0001 0000 0000 0000 0000 0000 + state s(TIMING); + ttlout *ttl_state = new ttlout(); + ttl_state->id = 0; + s.push_front(ttl_state); + state_sequent *rep_sequence = new state_sequent(); + // 0 + ttl_state->ttls = 0 + (1 << CLK_BIT); + rep_sequence->push_back(s.copy_new()); + ttl_state->ttls = 0; + rep_sequence->push_back(s.copy_new()); + // 0 + ttl_state->ttls = 0 + (1 << CLK_BIT); + rep_sequence->push_back(s.copy_new()); + ttl_state->ttls = 0; + rep_sequence->push_back(s.copy_new()); + // 0 + ttl_state->ttls = 0 + (1 << CLK_BIT); + rep_sequence->push_back(s.copy_new()); + ttl_state->ttls = 0; + rep_sequence->push_back(s.copy_new()); + // 1 + ttl_state->ttls = (1<push_back(s.copy_new()); + ttl_state->ttls = (1<push_back(s.copy_new()); + + // the rest + rep_sequence->repeat = DAC_DATA_BITS; + ttl_state->ttls = 0 + (1 << CLK_BIT); + rep_sequence->push_back(s.copy_new()); + ttl_state->ttls = 0; + rep_sequence->push_back(s.copy_new()); + exp_sequence->insert(where, rep_sequence); + //read in the word + ttl_state->ttls = 0; + exp_sequence->insert(where, s.copy_new()); + ttl_state->ttls = (1 << latch_bit); + exp_sequence->insert(where, s.copy_new()); } +void AD5791::init_dac(state_sequent *exp_sequence, state::iterator where) { + state s(TIMING); + ttlout *ttl_state = new ttlout(); + ttl_state->id = 0; + s.push_front(ttl_state); + state_sequent *rep_sequence = new state_sequent(); + // 0010 0000 0000 0000 0000 0000 + // 0 + ttl_state->ttls = 0 + (1 << CLK_BIT); + rep_sequence->push_back(s.copy_new()); + ttl_state->ttls = 0; + rep_sequence->push_back(s.copy_new()); + // 0 + ttl_state->ttls = 0 + (1 << CLK_BIT); + rep_sequence->push_back(s.copy_new()); + ttl_state->ttls = 0; + rep_sequence->push_back(s.copy_new()); + // 1 + ttl_state->ttls = (1<push_back(s.copy_new()); + ttl_state->ttls = (1<push_back(s.copy_new()); + // 0 + ttl_state->ttls = 0 + (1 << CLK_BIT); + rep_sequence->push_back(s.copy_new()); + ttl_state->ttls = 0; + rep_sequence->push_back(s.copy_new()); + + // the rest + rep_sequence->repeat = DAC_DATA_BITS; + ttl_state->ttls = 0 + (1 << CLK_BIT); + rep_sequence->push_back(s.copy_new()); + ttl_state->ttls = 0; + rep_sequence->push_back(s.copy_new()); + exp_sequence->insert(where, rep_sequence); + + //read in the word + ttl_state->ttls = 0; + exp_sequence->insert(where, s.copy_new()); + ttl_state->ttls = (1 << latch_bit); + exp_sequence->insert(where, s.copy_new()); +} + + + + // This loops recursive through the state tree +void AD5791::set_dac_recursive(state_sequent &the_sequence, state::iterator &the_state) { -void AD5791::set_dac_recursive(state_sequent& the_sequence, state::iterator& the_state) { - - state_sequent* a_sequence = dynamic_cast(*the_state); - // Am I a sequence? Yes? Go one sequence further - if (a_sequence != NULL) { - for(state_sequent::iterator child_state = a_sequence->begin(); child_state != a_sequence->end(); ++child_state) - set_dac_recursive(*a_sequence, child_state); - } - // I am not a sequence, but a state - else { - state* this_state = dynamic_cast(*the_state); - if (this_state == NULL) - throw pfg_exception( "state_atom in state_sequent not expected"); - analogout* PFG_aout = NULL; - // find an analogout section with suitable id - state::iterator pos = this_state->begin(); - while(pos!=this_state->end()) { // state members loop - analogout* aout = dynamic_cast(*pos); // initialize new analogout - // This is for me, analogout is != NULL (there is an analogout) and has my ID - if (aout!=NULL && aout->id == id) { - if (PFG_aout == NULL) { - // save the informations - PFG_aout = aout; - } - // there is no place for me here - else { - throw pfg_exception( "found another DAC section, ignoring"); - delete aout; - } - // remove the analog out section - this_state->erase(pos++); - } - else { - ++pos; - } - } // state members loop - - if (PFG_aout != NULL) { // state modifications - //std::cout<<"found a analog out section, value="<dac_value<length < TIMING*DAC_BIT_DEPTH*2 + 1) - throw pfg_exception( "time is too short to save DAC information"); - else { - // copy of original state - state* register_state = new state(*this_state); - ttlout* register_ttls = new ttlout(); - register_ttls->id = 0; - register_state->length = TIMING; - register_state->push_back(register_ttls); - if (PFG_aout->dac_value > (pow(2.0, int(DAC_BIT_DEPTH-1))-1) ) - throw pfg_exception("dac_value too high"); - if ( abs(PFG_aout->dac_value) > pow(2.0, int(DAC_BIT_DEPTH-1)) ) - throw pfg_exception("dac_value too low"); - // now, insert the ttl information - PFG_aout->dac_value += 1<<20; - vector dac_word; - for (int j = 0; j < DAC_BIT_DEPTH ; j++) { - int bit = PFG_aout->dac_value & 1; - // // invert the bit - //bit = (bit == 0); - dac_word.push_back(bit); - //cout << dac_word[j]; - PFG_aout->dac_value >>= 1; - } - // need one clock cycle to read in bit - // latch enable (LE) should always be high while doing so - // except for the last bit - // reverse the bit pattern - reverse(dac_word.begin(), dac_word.end()); + state_sequent *a_sequence = dynamic_cast(*the_state); + // Am I a sequence? Yes? Go one sequence further + if (a_sequence != NULL) { + for (state_sequent::iterator child_state = a_sequence->begin(); child_state != a_sequence->end(); ++child_state) + set_dac_recursive(*a_sequence, child_state); + } + // I am not a sequence, but a state + else { + state *this_state = dynamic_cast(*the_state); + if (this_state == NULL) + throw pfg_exception("state_atom in state_sequent not expected"); + analogout *dac_analog_out = NULL; + // find an analogout section with suitable id + state::iterator pos = this_state->begin(); + while (pos != this_state->end()) { // state members loop + analogout *aout = dynamic_cast(*pos); // initialize new analogout + // This is for me, analogout is != NULL (there is an analogout) and has my ID + if (aout != NULL && aout->id == id) { + if (dac_analog_out == NULL) { + // save the information of this aout + dac_analog_out = aout; + } + // there is no place for me here + else { + throw pfg_exception("found another DAC section, ignoring"); + delete aout; + } + // remove the analog out section + this_state->erase(pos++); + } else { + ++pos; + } + } // state members loop - // do run length encoding, grouping same bit values in loops - int last_seen_bit=dac_word[0]; - int last_seen_bit_count=1; - for (int i = 1; i < DAC_BIT_DEPTH+1; i++) { - if (i==DAC_BIT_DEPTH || last_seen_bit!=dac_word[i]) { - // so we have to write the bits - // either because the previous were different or we are finished - if (last_seen_bit_count>1) { - // insert a loop - state_sequent* rep_sequence=new state_sequent(); - rep_sequence->repeat=last_seen_bit_count; - register_ttls->ttls = (1 << DATA_BIT)*last_seen_bit + (1 << CLK_BIT) + (1 << latch_bit); - rep_sequence->push_back(register_state->copy_new()); - register_ttls->ttls = (1 << DATA_BIT)*last_seen_bit + (1 << latch_bit); - rep_sequence->push_back(register_state->copy_new()); - the_sequence.insert(the_state, rep_sequence); - } else { - // no loop necessary, insert two states - register_ttls->ttls = (1 << DATA_BIT)*last_seen_bit + (1 << CLK_BIT) + (1 << latch_bit); - the_sequence.insert(the_state, register_state->copy_new()); - register_ttls->ttls = (1 << DATA_BIT)*last_seen_bit + (1 << latch_bit); - the_sequence.insert(the_state, register_state->copy_new()); - } - // reset counter and bits if we are not finished - if (ittls = 0; - the_sequence.insert(the_state,register_state->copy_new()); - - // shorten the remaining state - // and add LE high to this state - ttlout* ttls=new ttlout(); - // 42nd pulse - this_state->length -= TIMING*2*DAC_BIT_DEPTH + 1; - ttls->ttls = 1 << latch_bit; - this_state->push_front(ttls); - // cleanup - delete register_state; - delete PFG_aout; - } // state was long enough to work on - } - else { - ttlout* le_ttls=new ttlout(); - // le_ttls->ttls = 1 << latch_bit; - this_state->push_back(le_ttls); - } - // end of state modifications - } // I was a state + if (dac_analog_out != NULL) { // state modifications + //std::cout<<"found a analog out section, value="<dac_value<length < TIMING * (DAC_CONTROL_BITS + DAC_DATA_BITS) * 2 + 1) + throw pfg_exception("time is too short to save DAC information"); + else { + // copy of original state + state *register_state = new state(*this_state); + ttlout *register_ttls = new ttlout(); + register_ttls->id = 0; + register_state->length = TIMING; + register_state->push_back(register_ttls); + if (dac_analog_out->dac_value > (pow(2.0, int(DAC_DATA_BITS - 1)) - 1)) + throw pfg_exception("dac_value too high"); + if (abs(dac_analog_out->dac_value) > pow(2.0, int(DAC_DATA_BITS - 1))) + throw pfg_exception("dac_value too low"); + + // set dac write register 1<<20 + dac_analog_out->dac_value += WRITE_DAC; + vector dac_word; + // generate the bit pattern, this is MSB last + for (int j = 0; j < (DAC_DATA_BITS + DAC_CONTROL_BITS); j++) { + int bit = dac_analog_out->dac_value & 1; + dac_word.push_back(bit); + dac_analog_out->dac_value >>= 1; + } + // reverse the bit pattern (MSB first) + reverse(dac_word.begin(), dac_word.end()); + + // need one clock cycle to read in bit + // latch enable (LE) should always be high while doing so + // except for the last bit + + // do run length encoding, grouping same bit values in loops + int last_seen_bit = dac_word[0]; + int last_seen_bit_count = 1; + for (int i = 1; i < (DAC_DATA_BITS + DAC_CONTROL_BITS) + 1; i++) { + if (i == (DAC_DATA_BITS + DAC_CONTROL_BITS) || last_seen_bit != dac_word[i]) { + // so we have to write the bits + // either because the previous were different or we are finished + if (last_seen_bit_count > 1) { + // insert a loop + state_sequent *rep_sequence = new state_sequent(); + rep_sequence->repeat = last_seen_bit_count; + register_ttls->ttls = (1 << DATA_BIT) * last_seen_bit + (1 << CLK_BIT) + (1 << latch_bit); + rep_sequence->push_back(register_state->copy_new()); + register_ttls->ttls = (1 << DATA_BIT) * last_seen_bit + (1 << latch_bit); + rep_sequence->push_back(register_state->copy_new()); + the_sequence.insert(the_state, rep_sequence); + } else { + // no loop necessary, insert two states + register_ttls->ttls = (1 << DATA_BIT) * last_seen_bit + (1 << CLK_BIT) + (1 << latch_bit); + the_sequence.insert(the_state, register_state->copy_new()); + register_ttls->ttls = (1 << DATA_BIT) * last_seen_bit + (1 << latch_bit); + the_sequence.insert(the_state, register_state->copy_new()); + } + // reset counter and bits if we are not finished + if (i < (DAC_DATA_BITS + DAC_CONTROL_BITS)) { + last_seen_bit = dac_word[i]; + last_seen_bit_count = 1; + } + } // finished writing + else + last_seen_bit_count += 1; // same bit value, so continue + } // end of bit loop + register_ttls->ttls = 0; + the_sequence.insert(the_state, register_state->copy_new()); + + // shorten the remaining state + // and add LE high to this state + ttlout *ttls = new ttlout(); + // 2 clocks per bit + 1 for sync + this_state->length -= TIMING * 2 * (DAC_DATA_BITS + DAC_CONTROL_BITS) + 1; + ttls->ttls = 1 << latch_bit; + this_state->push_front(ttls); + + // cleanup + delete register_state; + delete dac_analog_out; + } // state was long enough to work on + } else { + ttlout *le_ttls = new ttlout(); + // le_ttls->ttls = 1 << latch_bit; + this_state->push_back(le_ttls); + } + // end of state modifications + } // I was a state } diff --git a/drivers/DAC-AD5791/AD5791.h b/drivers/DAC-AD5791/AD5791.h index aa9290c..c243d23 100644 --- a/drivers/DAC-AD5791/AD5791.h +++ b/drivers/DAC-AD5791/AD5791.h @@ -37,6 +37,7 @@ public: private: void set_dac_recursive(state_sequent& the_sequence, state::iterator& the_state); void set_dac_to_zero(state_sequent* exp_sequence, state::iterator where); + void init_dac(state_sequent* exp_sequence, state::iterator where); void set_dac_control(state_sequent* exp_sequence, state::iterator where, int input_shift_register); }; diff --git a/drivers/Spectrum-MI40xxSeries/Spectrum-MI40xxSeries.cpp b/drivers/Spectrum-MI40xxSeries/Spectrum-MI40xxSeries.cpp index fdb8cd1..202ea43 100644 --- a/drivers/Spectrum-MI40xxSeries/Spectrum-MI40xxSeries.cpp +++ b/drivers/Spectrum-MI40xxSeries/Spectrum-MI40xxSeries.cpp @@ -178,8 +178,8 @@ void SpectrumMI40xxSeries::collect_config_recursive(state_sequent& exp, Spectrum settings.data_structure=where_to_append; collect_config_recursive(*a_sequence, settings); settings.data_structure=tmp_structure; - } /* end working on sequence */ - else { + //} /* end working on sequence */ + //else { // found a state, not a sequence settings.timeout+=a_state->length; #if SPC_DEBUG @@ -731,7 +731,7 @@ int SpectrumMI40xxSeries::TimeoutThread() { //pthread_attr_destroy(&timeout_pt_attrs); free(fifo_adc_data); fifo_adc_data=NULL; - throw SpectrumMI40xxSeries_error("timout occured while collecting data"); + throw SpectrumMI40xxSeries_error("timeout occured while collecting data"); return 0; } #if SPC_DEBUG @@ -821,9 +821,9 @@ result* SpectrumMI40xxSeries::get_samples(double _timeout) { starts running before the actual start of the pulse program because the OS is not loading and starting the pulseblaster immediatly. It is not possible to synchronize the timers for now. - Thus, we add a generous 2s to the timeout to be on the safe side. + Thus, we add a generous 1s to the timeout to be on the safe side. */ - while (core::term_signal==0 && adc_status!=SPC_READY && elapsed_time<=(effective_settings->timeout + post_gate_maxtime + 2) ) { + while (core::term_signal==0 && adc_status!=SPC_READY && elapsed_time<=(effective_settings->timeout + post_gate_maxtime + 1) ) { timespec sleeptime; sleeptime.tv_nsec=10*1000*1000; // 10 ms sleeptime.tv_sec=0;