control for DAC AD5384 for the SOLID SM1 Slow Control

Dependents:   SPItest sscm

AD5384.cpp

Committer:
wbeaumont
Date:
2015-01-29
Revision:
5:477603ce54a0
Parent:
4:bc9ab300ab26

File content as of revision 5:477603ce54a0:

#include "AD5384.h"
#include "mbed.h"

#define  nrch 40 // nr channels 
#define  p2_14  16384
#define  p2_13  8192

#define CS_ACTIVE 1
#define CS_DEACTIVE  0

#define RST_ACTIVE 1
#define RST_DEACTIVE 0


// spi mode has to be set for each transmission as spi bus can be shared 

/*****
 * version history 
 * v1.10  initial release version
 * v1.11  added init 1 and init 2 function an ctrlreg defs 
 * v1.12  
 * v1.13  corrected channel mask from 0x1F  to 0x3F  
 * v1.20  added hw_rst , added hwrst to init1 not in init2
 * v1.24  added update shadow registers
 * v1.26  corrected mask for reading register value
 * v1.30  added get voltage
  *V1.31  corrected gain+1  to gain+2 in calculate_dac_setting
 */

#define AD5384_SRC_VERSION "1.31"

#define  M_DATA_R  0x3
#define  M_OFFS_R  0x2 
#define  M_GAIN_R  0x1
#define  M_SPEC_R  0x0

#define  NOP_INST  0x0


// control register bits 
#define  CTRL_REG_ADDR      0x0C
#define  OUT_PWD_STAT_HIMP 0x2000  
                            //0b10 0000 0000 0000 
#define  OUT_PWD_STAT_100K  0x1FFF  
                            //0b01 1111 1111 1111
#define  INT_REF_2500       0X1000  
                            //0b01000000000000 
#define  INT_REF_1250       0x2FFF  
                            //0b10111111111111        
#define  I_BOOST_ON         0x0800  
                            //0b00100000000000        
#define  I_BOOST_OFF        0x37FF  
                            //0b11011111111111
#define  REF_SRC_INT        0x0400  
                            //0b00010000000000 
#define  REF_SRC_EXT        0x3BFF  
                            //0b11 1011 1111 1111        
#define  MONITOR_MODE_EN    0x0200  
                            //0b00001000000000 
#define  MONITOR_MODE_DIS   0x3DFF  
                            //0b11 1101 1111 1111
#define  TEMP_MONITOR_EN    0x0100  
                            //0b00000100000000 
#define  TEMP_MONITOR_DIS   0x3EFF  
                            //0b11 1110 1111 1111
#define TOGGLE_DISABLE      0x3F83    
                            //0b11 1111 1000 0011




AD5384::AD5384(SWSPI *spiinterface ,DigitalOut* chipselect, DigitalOut* reset):getVersion( VERSION_AD5384_HDR,AD5384_SRC_VERSION, __TIME__, __DATE__) {
        vref=2.5; 
        spi=spiinterface; 
        cs=chipselect;
        rst=reset;
        for ( int nc=0 ; nc < nrch; nc++){ 
            gain[nc]=0x3FFE; //power up values 
            offset[nc]=0x2000;
            dacr[nc]=0x0000;
        } 
    };
    
    
void AD5384::update_gain_shadow(u8 ch ) {
    if( ch) gain[ch-1] = get_gain(ch-1);
    else 
    for (u8 chc=0;chc < 40;chc++) {
        gain[chc] = get_gain(chc);              
    }       

}
void AD5384::update_offset_shadow(u8 ch ) {
    if( ch) offset[ch-1] = get_offset(ch-1);
    else 
    for (u8 chc=0;chc < 40;chc++) {
        offset[chc] = get_offset(chc);          
    }       
 }
 
 void AD5384::update_dac_shadow(u8 ch ) {
    if( ch) dacr[ch-1] = get_dac(ch-1);
    else 
    for (u8 chc=0;chc < 40;chc++) {
        dacr[chc] = get_dac(chc);          
    }       
 }
 
    
u16  AD5384::calculate_dac_setting(u8 nr, float vout ) {  
    //Vout = 2 * Vref * x2 / 2^n  =>  x2 = Vout * 2^14 /(2 * Vref) 
    // x2 is loaded to the DAC string  
    // x1 is the 14 bit DAC wordt written to the DAC input register                 
                float x2= vout * (float)p2_14 /(2 *vref);
    //  x2 = [(gain+2)/2^n * x1] + offset-2^13               
    // x1 = 2^14/(gain+2) *  [ x2 - offset+2^13 ]
                u16 x1 = (float)p2_14/((float)gain[nr]+2) *( x2- offset[nr]+p2_13);
                x1= 0x3FFF & x1;
                dacr[nr]=x1 ;
                return x1;
             };


u32 AD5384::format_word(u8 mode,u8 ch,u8 rw,u16 data) {
      // MSB set to 0 , toggle mode not supported
            u32 shift = (u32) rw&1;            
            u32 word= shift << 22;
           
            shift= (u32)(ch &0x3F);
            shift = shift << 16;
            word = word | shift;
           
            shift= (u32)(mode & 0x3);
            shift = shift << 14;
            word = word | shift;
            
            word = word | (data & 0x3FFF);
           
            return word;
}
             
void AD5384::set_spi_mode(){
    spi->format(24,1);
    spi->frequency(10000000);             
}
             
 u16 AD5384::set_volt(u8 ch, float vout ){
     volt[ch]=vout;
     u16 dacin=calculate_dac_setting(ch,  vout );
     set_spi_mode();
     u32 data=format_word(M_DATA_R,ch,0,dacin); 
     cs->write(CS_ACTIVE);
     spi->write(data);
     cs->write(CS_DEACTIVE);   
     dacr[ch]=dacin;
     return dacin;
}


float  AD5384::get_volt(u8 nr, bool readallreg ) {
    u16 lgain;
    u16 loffset;
    u16 ldac=get_ch_out_reg(nr);
    dacr[nr]=ldac;
    if( readallreg)  {
       lgain= get_gain(nr); gain[nr]=lgain;
       loffset=get_offset(nr); offset[nr]=loffset;
    } 
    else { lgain=gain[nr]; loffset=offset[nr];}
    //Vout = 2 * Vref * x2 / 2^n    x2= [x1*(m+2)]/2^n ]+ (c-2^(n-1))
    float x2= ((float)(lgain+2)/(float)p2_14)*(float) ldac + loffset- p2_13;
    float vout = 2 *vref * x2 / p2_14;      
    return vout;
}    



void  AD5384::init1(){
        u16 ctrlreg=0;
        hw_rst();
        ctrlreg = (INT_REF_2500 | REF_SRC_INT ) & TOGGLE_DISABLE;
       set_reg(M_SPEC_R,CTRL_REG_ADDR,ctrlreg); 
       wait_us(100);
     //  update_dac_shadow(0);
     //  update_gain_shadow(0);
     //  update_offset_shadow(0);
} 

void  AD5384::init2(){
        u16 ctrlreg=0;
        // implecite INT_REF_1250
        ctrlreg =  REF_SRC_INT  & TOGGLE_DISABLE;
       set_reg(M_SPEC_R,CTRL_REG_ADDR,ctrlreg); 
   
}



u32  AD5384::soft_clr(){
      return set_reg(M_SPEC_R,0x02,0x2000);
} 


u32  AD5384::soft_rst(){
      return set_reg(M_SPEC_R,0x0F,0x211F);
} 


u32  AD5384::clear_code(){
    return set_reg(M_SPEC_R,0x01,0x2000);
 }
 
u16  AD5384::set_gain(u8 ch, u16 gainin  ){     
     set_reg(M_GAIN_R,ch,gainin);
     gain[ch]=gainin;
     return gainin;
} 

u16  AD5384::set_offset(u8 ch, u16 gainin  ){
     set_reg(M_OFFS_R,ch,gainin);
     offset[ch]=gainin;
     return gainin;
} 


u16 AD5384::set_dac(u8 ch, u16 dac  ){
     set_reg(M_DATA_R,ch,dac);
     dacr[ch]=dac;
     return dac;
} 




 
 u32  AD5384::set_reg(u8 mode,u8 ch, u16 value  ){
     set_spi_mode();
     value=value & 0x3FFF;
     u32 data=format_word(mode,ch,0,value); 
     cs->write(CS_ACTIVE);
     spi->write(data);
     cs->write(CS_DEACTIVE);   
     return data;
 }     
 
 u16 AD5384::get_reg(u8 mode, u8 ch   ){
     set_spi_mode();
     u32 data=format_word(mode,ch,1,0);
     cs->write(CS_ACTIVE);
     spi->write(data);
     cs->write(CS_DEACTIVE);
     wait( .00001);
     cs->write(CS_ACTIVE);
     data=spi->write(NOP_INST);
     cs->write(CS_DEACTIVE);
     return (u16) data &0x3FFF;
}
 
 u16  AD5384::get_gain(u8 ch  ){
    return get_reg(M_GAIN_R,ch);
     
}    

u16 AD5384::get_dac(u8 ch){
    return get_reg(M_DATA_R,ch);
     
}   
       
       
       
       
 u16  AD5384::get_offset(u8 ch  ){
    return get_reg(M_OFFS_R,ch);
     
}        

u32  AD5384::get_ctrl(){
    
    return get_reg(M_SPEC_R, 0x0C);   
}    

  
 
   
u16 AD5384::get_ch_out_reg(u8 ch) {
     u32 data=format_word(M_DATA_R,ch,1,0);
     cs->write(CS_ACTIVE);
     spi->write(data);
     cs->write(CS_DEACTIVE);
     wait( .00001);
     cs->write(CS_ACTIVE);
     data=spi->write(NOP_INST);
     cs->write(CS_DEACTIVE);
     return (u16) data & 0x3FFF;
}    


 void AD5384::hw_rst(){
     rst->write( RST_ACTIVE); // edge sensitive 
     wait_us(30);
     rst->write( RST_DEACTIVE);
     wait_us(300); // 270 us according data sheet
     
}