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
* 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 <cstdio>
#include <cmath>
#include <iostream>
@ -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<state_sequent*>(&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<state_sequent *>(&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<<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());
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<<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
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);
// 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<state*>(*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<analogout*>(*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="<<PFG_aout->dac_value<<std::endl;
// check the length of the state
if (this_state->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<int> 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<state_sequent *>(*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<state *>(*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<analogout *>(*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 (i<DAC_BIT_DEPTH) {
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();
// 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_analog_out->dac_value<<std::endl;
// check the length of the state
if (this_state->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<int> 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
}

View File

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

View File

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