AD579 driver 2nd revision

This commit is contained in:
Markus Rosenstihl 2016-12-19 14:03:14 +00:00
parent 5b52fb3e5a
commit 974be4ec82
3 changed files with 269 additions and 185 deletions

View File

@ -3,25 +3,12 @@
* \brief Implementation of the Driver for the AD5791 * \brief Implementation of the Driver for the AD5791
* Digital to Analog Converter Board * 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. * 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 "AD5791.h"
#include "../../core/states.h"
#include <cstdio> #include <cstdio>
#include <cmath> #include <cmath>
#include <iostream> #include <iostream>
@ -37,13 +24,44 @@ using std::vector;
#endif #endif
// The bit depth of the DAC // The bit depth of the DAC
#define DAC_BIT_DEPTH 24 #define DAC_DATA_BITS 20
#define DAC_CONTROL_BITS 4
// The channel configuration // The channel configuration
#define DATA_BIT 18//18 #define DATA_BIT 18//18
#define CLK_BIT 16//16 #define CLK_BIT 16//16
AD5791::AD5791(int myid): id(myid) {
// 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; dac_value = 0;
set_latch_bit(17); set_latch_bit(17);
} }
@ -55,174 +73,239 @@ void AD5791::set_dac(signed dw) {
dac_value = dw; dac_value = dw;
} }
void AD5791::set_latch_bit(int le_bit) void AD5791::set_latch_bit(int le_bit) {
{
latch_bit = le_bit; latch_bit = le_bit;
} }
// This sets the DAC // This sets the DAC
void AD5791::set_dac(state& experiment) { void AD5791::set_dac(state &experiment) {
state_sequent *exp_sequence = dynamic_cast<state_sequent *>(&experiment);
state_sequent* exp_sequence=dynamic_cast<state_sequent*>(&experiment);
if (exp_sequence == NULL) if (exp_sequence == NULL)
// is a very state on top level, todo: change interface // is a very state on top level, todo: change interface
throw pfg_exception( "cannot work on a single state, sorry (todo: change interface)"); throw pfg_exception("cannot work on a single state, sorry (todo: change interface)");
else { else {
for(state_sequent::iterator child_state = exp_sequence->begin(); child_state != exp_sequence->end(); ++child_state) for (state_sequent::iterator child_state = exp_sequence->begin();
child_state != exp_sequence->end(); ++child_state)
set_dac_recursive(*exp_sequence, child_state); set_dac_recursive(*exp_sequence, child_state);
// std::cout << "first state"<< std::endl; // std::cout << "first state"<< std::endl;
// Set DAC to 0 at start of experiment // Set DAC to 0 at start of experiment
set_dac_to_zero(exp_sequence, exp_sequence->begin()); set_dac_to_zero(exp_sequence, exp_sequence->begin());
// And at the end of the experiment // 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()); set_dac_to_zero(exp_sequence, exp_sequence->end());
} }
} }
void AD5791::set_dac_to_zero(state_sequent* exp_sequence, state::iterator where) void AD5791::set_dac_to_zero(state_sequent *exp_sequence, state::iterator where) {
{ // 0001 0000 0000 0000 0000 0000
state s(TIMING); state s(TIMING);
ttlout* le=new ttlout(); ttlout *ttl_state = new ttlout();
le->id=0; ttl_state->id = 0;
s.push_front(le); s.push_front(ttl_state);
state_sequent* rep_sequence=new state_sequent(); state_sequent *rep_sequence = new state_sequent();
rep_sequence->repeat=DAC_BIT_DEPTH; // 0
le->ttls = 0 + ( 1 << CLK_BIT ); ttl_state->ttls = 0 + (1 << CLK_BIT);
rep_sequence->push_back(s.copy_new()); rep_sequence->push_back(s.copy_new());
le->ttls = 0 ; 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<<DATA_BIT) + (1 << CLK_BIT);
rep_sequence->push_back(s.copy_new());
ttl_state->ttls = (1<<DATA_BIT);
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()); rep_sequence->push_back(s.copy_new());
exp_sequence->insert(where, rep_sequence); exp_sequence->insert(where, rep_sequence);
//read in the word (41st pulse) //read in the word
le->ttls=0; ttl_state->ttls = 0;
exp_sequence->insert(where, s.copy_new()); exp_sequence->insert(where, s.copy_new());
// 42nd pulse ttl_state->ttls = (1 << latch_bit);
// // the state should be 2ms long
// s.length = 2e-3-41*TIMING;
le->ttls= ( 1 << latch_bit );
exp_sequence->insert(where, s.copy_new()); 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<<DATA_BIT) + (1 << CLK_BIT);
rep_sequence->push_back(s.copy_new());
ttl_state->ttls = (1<<DATA_BIT);
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());
// 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 // 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<state_sequent *>(*the_state);
state_sequent* a_sequence = dynamic_cast<state_sequent*>(*the_state);
// Am I a sequence? Yes? Go one sequence further // Am I a sequence? Yes? Go one sequence further
if (a_sequence != NULL) { if (a_sequence != NULL) {
for(state_sequent::iterator child_state = a_sequence->begin(); child_state != a_sequence->end(); ++child_state) for (state_sequent::iterator child_state = a_sequence->begin(); child_state != a_sequence->end(); ++child_state)
set_dac_recursive(*a_sequence, child_state); set_dac_recursive(*a_sequence, child_state);
} }
// I am not a sequence, but a state // I am not a sequence, but a state
else { else {
state* this_state = dynamic_cast<state*>(*the_state); state *this_state = dynamic_cast<state *>(*the_state);
if (this_state == NULL) if (this_state == NULL)
throw pfg_exception( "state_atom in state_sequent not expected"); throw pfg_exception("state_atom in state_sequent not expected");
analogout* PFG_aout = NULL; analogout *dac_analog_out = NULL;
// find an analogout section with suitable id // find an analogout section with suitable id
state::iterator pos = this_state->begin(); state::iterator pos = this_state->begin();
while(pos!=this_state->end()) { // state members loop while (pos != this_state->end()) { // state members loop
analogout* aout = dynamic_cast<analogout*>(*pos); // initialize new analogout analogout *aout = dynamic_cast<analogout *>(*pos); // initialize new analogout
// This is for me, analogout is != NULL (there is an analogout) and has my ID // This is for me, analogout is != NULL (there is an analogout) and has my ID
if (aout!=NULL && aout->id == id) { if (aout != NULL && aout->id == id) {
if (PFG_aout == NULL) { if (dac_analog_out == NULL) {
// save the informations // save the information of this aout
PFG_aout = aout; dac_analog_out = aout;
} }
// there is no place for me here // there is no place for me here
else { else {
throw pfg_exception( "found another DAC section, ignoring"); throw pfg_exception("found another DAC section, ignoring");
delete aout; delete aout;
} }
// remove the analog out section // remove the analog out section
this_state->erase(pos++); this_state->erase(pos++);
} } else {
else {
++pos; ++pos;
} }
} // state members loop } // state members loop
if (PFG_aout != NULL) { // state modifications
//std::cout<<"found a analog out section, value="<<PFG_aout->dac_value<<std::endl; if (dac_analog_out != NULL) { // state modifications
//std::cout<<"found a analog out section, value="<<dac_analog_out->dac_value<<std::endl;
// check the length of the state // check the length of the state
if (this_state->length < TIMING*DAC_BIT_DEPTH*2 + 1) if (this_state->length < TIMING * (DAC_CONTROL_BITS + DAC_DATA_BITS) * 2 + 1)
throw pfg_exception( "time is too short to save DAC information"); throw pfg_exception("time is too short to save DAC information");
else { else {
// copy of original state // copy of original state
state* register_state = new state(*this_state); state *register_state = new state(*this_state);
ttlout* register_ttls = new ttlout(); ttlout *register_ttls = new ttlout();
register_ttls->id = 0; register_ttls->id = 0;
register_state->length = TIMING; register_state->length = TIMING;
register_state->push_back(register_ttls); register_state->push_back(register_ttls);
if (PFG_aout->dac_value > (pow(2.0, int(DAC_BIT_DEPTH-1))-1) ) if (dac_analog_out->dac_value > (pow(2.0, int(DAC_DATA_BITS - 1)) - 1))
throw pfg_exception("dac_value too high"); throw pfg_exception("dac_value too high");
if ( abs(PFG_aout->dac_value) > pow(2.0, int(DAC_BIT_DEPTH-1)) ) if (abs(dac_analog_out->dac_value) > pow(2.0, int(DAC_DATA_BITS - 1)))
throw pfg_exception("dac_value too low"); throw pfg_exception("dac_value too low");
// now, insert the ttl information
PFG_aout->dac_value += 1<<20; // set dac write register 1<<20
dac_analog_out->dac_value += WRITE_DAC;
vector<int> dac_word; vector<int> dac_word;
for (int j = 0; j < DAC_BIT_DEPTH ; j++) { // generate the bit pattern, this is MSB last
int bit = PFG_aout->dac_value & 1; for (int j = 0; j < (DAC_DATA_BITS + DAC_CONTROL_BITS); j++) {
// // invert the bit int bit = dac_analog_out->dac_value & 1;
//bit = (bit == 0);
dac_word.push_back(bit); dac_word.push_back(bit);
//cout << dac_word[j]; dac_analog_out->dac_value >>= 1;
PFG_aout->dac_value >>= 1;
} }
// reverse the bit pattern (MSB first)
reverse(dac_word.begin(), dac_word.end());
// need one clock cycle to read in bit // need one clock cycle to read in bit
// latch enable (LE) should always be high while doing so // latch enable (LE) should always be high while doing so
// except for the last bit // except for the last bit
// reverse the bit pattern
reverse(dac_word.begin(), dac_word.end());
// do run length encoding, grouping same bit values in loops // do run length encoding, grouping same bit values in loops
int last_seen_bit=dac_word[0]; int last_seen_bit = dac_word[0];
int last_seen_bit_count=1; int last_seen_bit_count = 1;
for (int i = 1; i < DAC_BIT_DEPTH+1; i++) { for (int i = 1; i < (DAC_DATA_BITS + DAC_CONTROL_BITS) + 1; i++) {
if (i==DAC_BIT_DEPTH || last_seen_bit!=dac_word[i]) { if (i == (DAC_DATA_BITS + DAC_CONTROL_BITS) || last_seen_bit != dac_word[i]) {
// so we have to write the bits // so we have to write the bits
// either because the previous were different or we are finished // either because the previous were different or we are finished
if (last_seen_bit_count>1) { if (last_seen_bit_count > 1) {
// insert a loop // insert a loop
state_sequent* rep_sequence=new state_sequent(); state_sequent *rep_sequence = new state_sequent();
rep_sequence->repeat=last_seen_bit_count; rep_sequence->repeat = last_seen_bit_count;
register_ttls->ttls = (1 << DATA_BIT)*last_seen_bit + (1 << CLK_BIT) + (1 << latch_bit); register_ttls->ttls = (1 << DATA_BIT) * last_seen_bit + (1 << CLK_BIT) + (1 << latch_bit);
rep_sequence->push_back(register_state->copy_new()); rep_sequence->push_back(register_state->copy_new());
register_ttls->ttls = (1 << DATA_BIT)*last_seen_bit + (1 << latch_bit); register_ttls->ttls = (1 << DATA_BIT) * last_seen_bit + (1 << latch_bit);
rep_sequence->push_back(register_state->copy_new()); rep_sequence->push_back(register_state->copy_new());
the_sequence.insert(the_state, rep_sequence); the_sequence.insert(the_state, rep_sequence);
} else { } else {
// no loop necessary, insert two states // no loop necessary, insert two states
register_ttls->ttls = (1 << DATA_BIT)*last_seen_bit + (1 << CLK_BIT) + (1 << latch_bit); register_ttls->ttls = (1 << DATA_BIT) * last_seen_bit + (1 << CLK_BIT) + (1 << latch_bit);
the_sequence.insert(the_state, register_state->copy_new()); the_sequence.insert(the_state, register_state->copy_new());
register_ttls->ttls = (1 << DATA_BIT)*last_seen_bit + (1 << latch_bit); register_ttls->ttls = (1 << DATA_BIT) * last_seen_bit + (1 << latch_bit);
the_sequence.insert(the_state, register_state->copy_new()); the_sequence.insert(the_state, register_state->copy_new());
} }
// reset counter and bits if we are not finished // reset counter and bits if we are not finished
if (i<DAC_BIT_DEPTH) { if (i < (DAC_DATA_BITS + DAC_CONTROL_BITS)) {
last_seen_bit=dac_word[i]; last_seen_bit = dac_word[i];
last_seen_bit_count=1; last_seen_bit_count = 1;
} }
} // finished writing } // finished writing
else else
last_seen_bit_count+=1; // same bit value, so continue last_seen_bit_count += 1; // same bit value, so continue
} // end of bit loop } // end of bit loop
register_ttls->ttls = 0; register_ttls->ttls = 0;
the_sequence.insert(the_state,register_state->copy_new()); the_sequence.insert(the_state, register_state->copy_new());
// shorten the remaining state // shorten the remaining state
// and add LE high to this state // and add LE high to this state
ttlout* ttls=new ttlout(); ttlout *ttls = new ttlout();
// 42nd pulse // 2 clocks per bit + 1 for sync
this_state->length -= TIMING*2*DAC_BIT_DEPTH + 1; this_state->length -= TIMING * 2 * (DAC_DATA_BITS + DAC_CONTROL_BITS) + 1;
ttls->ttls = 1 << latch_bit; ttls->ttls = 1 << latch_bit;
this_state->push_front(ttls); this_state->push_front(ttls);
// cleanup // cleanup
delete register_state; delete register_state;
delete PFG_aout; delete dac_analog_out;
} // state was long enough to work on } // state was long enough to work on
} } else {
else { ttlout *le_ttls = new ttlout();
ttlout* le_ttls=new ttlout();
// le_ttls->ttls = 1 << latch_bit; // le_ttls->ttls = 1 << latch_bit;
this_state->push_back(le_ttls); this_state->push_back(le_ttls);
} }

View File

@ -37,6 +37,7 @@ public:
private: private:
void set_dac_recursive(state_sequent& the_sequence, state::iterator& the_state); 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 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); void set_dac_control(state_sequent* exp_sequence, state::iterator where, int input_shift_register);
}; };

View File

@ -178,8 +178,8 @@ void SpectrumMI40xxSeries::collect_config_recursive(state_sequent& exp, Spectrum
settings.data_structure=where_to_append; settings.data_structure=where_to_append;
collect_config_recursive(*a_sequence, settings); collect_config_recursive(*a_sequence, settings);
settings.data_structure=tmp_structure; settings.data_structure=tmp_structure;
} /* end working on sequence */ //} /* end working on sequence */
else { //else {
// found a state, not a sequence // found a state, not a sequence
settings.timeout+=a_state->length; settings.timeout+=a_state->length;
#if SPC_DEBUG #if SPC_DEBUG
@ -731,7 +731,7 @@ int SpectrumMI40xxSeries::TimeoutThread() {
//pthread_attr_destroy(&timeout_pt_attrs); //pthread_attr_destroy(&timeout_pt_attrs);
free(fifo_adc_data); free(fifo_adc_data);
fifo_adc_data=NULL; fifo_adc_data=NULL;
throw SpectrumMI40xxSeries_error("timout occured while collecting data"); throw SpectrumMI40xxSeries_error("timeout occured while collecting data");
return 0; return 0;
} }
#if SPC_DEBUG #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 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 the pulseblaster immediatly. It is not possible to
synchronize the timers for now. 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; timespec sleeptime;
sleeptime.tv_nsec=10*1000*1000; // 10 ms sleeptime.tv_nsec=10*1000*1000; // 10 ms
sleeptime.tv_sec=0; sleeptime.tv_sec=0;