Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: MCP4822_demo MCP4822_SinewaveV2
MCP4822A.cpp
00001 /* 00002 * MCP4822A - DAC array library. 00003 * 00004 * Copyright (c) 2011 Steven Beard, UK Astronomy Technology Centre. 00005 * 00006 * Permission is hereby granted, free of charge, to any person obtaining a copy 00007 * of this software and associated documentation files (the "Software"), to deal 00008 * in the Software without restriction, including without limitation the rights 00009 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00010 * copies of the Software, and to permit persons to whom the Software is 00011 * furnished to do so, subject to the following conditions: 00012 * 00013 * The above copyright notice and this permission notice shall be included in 00014 * all copies or substantial portions of the Software. 00015 * 00016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00017 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00018 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00019 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00020 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00021 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00022 * THE SOFTWARE. 00023 */ 00024 00025 #include "mbed.h" 00026 #include "MCP4822A.h" 00027 00028 using namespace mbed; 00029 00030 /*+ 00031 * Interface to an array of MCP4822 12-bit dual-output DACs daisy chained 00032 * on an SPI bus and selected using DigitalOut pins. 00033 * 00034 * For a detailed API description see MCP4822.h. 00035 *- 00036 */ 00037 // Constructor 00038 MCP4822A::MCP4822A(int ndacs, PinName mosi, PinName sclk, PinName ncslist[], PinName nldac) : _spi(mosi, NC, sclk) { 00039 00040 // Create an array of DigitalOut objects connected to each NCS pin. 00041 int i; 00042 _ndacs = (ndacs > 0) ? ndacs : 1; 00043 _ncs_array = new DigitalOut*[ _ndacs ]; 00044 for (i=0; i<_ndacs; i++) { 00045 _ncs_array[i] = new DigitalOut( ncslist[i] ); 00046 } 00047 00048 // The LDAC pin is optional. 00049 if (nldac == NC) { 00050 // LDAC is not connected for this DAC. 00051 _latched = 0; 00052 _nldac = NULL; 00053 } else { 00054 // LDAC is connected - create a DigitalOut object connected to it. 00055 _latched = 1; 00056 _nldac = new DigitalOut( nldac ); 00057 } 00058 00059 // Initialise the DAC SPI interface. 00060 _init(); 00061 } 00062 00063 // Destructor 00064 MCP4822A::~MCP4822A() { 00065 00066 // Before destroying the object, shut down all the chips. 00067 shdn_all(); 00068 00069 // Delete all the NCS DigitalOut objects and the array pointing to 00070 // them. 00071 int i; 00072 for (i=0; i<_ndacs; i++) { 00073 delete _ncs_array[i]; 00074 } 00075 delete [] _ncs_array; 00076 00077 // Delete the LDAC DigitalOut object if it exists. 00078 if (_latched ) delete _nldac; 00079 } 00080 00081 // Initialise SPI interface. 00082 void MCP4822A::_init() { 00083 00084 // Set up the SPI for 16-bit values (12-bit + 4 command bits) and mode 0. 00085 _spi.format(16, 0); 00086 00087 // Start with all the CS and LDAC signals high (disabled) 00088 int i; 00089 for (i=0; i<_ndacs; i++) { 00090 _ncs_array[i]->write(1); 00091 } 00092 00093 if (_latched ) _nldac->write(1); 00094 return; 00095 } 00096 00097 // Set SPI clock frequency. 00098 void MCP4822A::frequency( int freq ) { 00099 00100 // Set the SPI interface clock frequency in Hz. 00101 _spi.frequency( freq ); 00102 return; 00103 } 00104 00105 /* 00106 * Note: There is a lot of code in common between the following 4 functions. 00107 * The code is kept in line to keep it efficient. Could the functions have 00108 * been written as templates? 00109 */ 00110 // Write to DAC channel A with gain 1. 00111 void MCP4822A::writeA1(int dac, int value) { 00112 00113 // Set up the command register with the appropriate value. 00114 // For efficiency, the caller is assumed to have checked dac. 00115 int reg; 00116 reg = (value & 0x0FFF) | MCP4822_REG_A1; 00117 00118 // Select the DAC chip, write to its command register and 00119 // then unselect the DAC chip. 00120 _ncs_array[dac]->write(0); 00121 _spi.write(reg); 00122 _ncs_array[dac]->write(1); 00123 return; 00124 } 00125 00126 // Write to DAC channel A with gain 2. 00127 void MCP4822A::writeA2(int dac, int value) { 00128 00129 // Set up the command register with the appropriate value. 00130 // For efficiency, the caller is assumed to have checked dac. 00131 int reg; 00132 reg = (value & 0x0FFF) | MCP4822_REG_A2; 00133 00134 // Select the DAC chip, write to its command register and then 00135 // unselect the DAC chip. 00136 _ncs_array[dac]->write(0); 00137 _spi.write(reg); 00138 _ncs_array[dac]->write(1); 00139 return; 00140 } 00141 00142 // Write to DAC channel B with gain 1. 00143 void MCP4822A::writeB1(int dac, int value) { 00144 00145 // Set up the command register with the appropriate value. 00146 // For efficiency, the caller is assumed to have checked dac. 00147 int reg; 00148 reg = (value & 0x0FFF) | MCP4822_REG_B1; 00149 00150 // Select the DAC chip, write to its command register and then 00151 // unselect the DAC chip. 00152 _ncs_array[dac]->write(0); 00153 _spi.write(reg); 00154 _ncs_array[dac]->write(1); 00155 return; 00156 } 00157 00158 // Write to DAC channel B with gain 2. 00159 void MCP4822A::writeB2(int dac, int value) { 00160 00161 // Set up the command register with the appropriate value. 00162 // For efficiency, the caller is assumed to have checked dac. 00163 int reg; 00164 reg = (value & 0x0FFF) | MCP4822_REG_B2; 00165 00166 // Select the DAC chip, write to its command register and then 00167 // unselect the DAC chip. 00168 _ncs_array[dac]->write(0); 00169 _spi.write(reg); 00170 _ncs_array[dac]->write(1); 00171 return; 00172 } 00173 00174 // Write an array of values to the DACs. 00175 void MCP4822A::write(int nchans, int values[], int gain, int latch) { 00176 00177 // nchans must be at least 1 but less than or equal to ndacs x 2. 00178 if (nchans < 1) nchans = 1; 00179 const int maxchans = _ndacs * 2; 00180 if (nchans > maxchans) nchans = maxchans; 00181 00182 if (latch && _latched) 00183 latch_disable(); 00184 00185 int i, dac; 00186 if ( gain == 2 ) { 00187 00188 for (i=0; i<nchans;) { 00189 dac = i/2; 00190 writeA2(dac, values[i]); 00191 i++; 00192 if (i < nchans) { 00193 writeB2(dac, values[i]); 00194 i++; 00195 } else break; 00196 } 00197 } else { 00198 00199 for (i=0; i<nchans;) { 00200 dac = i/2; 00201 writeA1(dac, values[i]); 00202 i++; 00203 if (i < nchans) { 00204 writeB1(dac, values[i]); 00205 i++; 00206 } else break; 00207 } 00208 } 00209 00210 // Automatically latch the new voltages if the latch flag is 1. 00211 if (latch && _latched) 00212 latch_enable(); 00213 return; 00214 } 00215 00216 // Convert a voltage into a 12-bit value. 00217 int MCP4822A::voltage2value( float voltage, int gain ) { 00218 00219 int value = int(4096000.0 * abs(voltage) / float(MCP4822_VREF * gain)); 00220 if ( value > 0x0FFF ) value = 0x0FFF; 00221 return value; 00222 } 00223 00224 // Convert a 12-bit value into a voltage. 00225 float MCP4822A::value2voltage( int value, int gain ) { 00226 00227 float voltage = value * MCP4822_VREF * gain / 4096000.0; 00228 return voltage; 00229 } 00230 00231 // Set latch signal to "enable". 00232 void MCP4822A::latch_enable() { 00233 00234 // Latch all chips. There should be a delay of at least T_LS=40 00235 // nanoseconds between the last CS rising edge and the LDAC falling 00236 // edge. The software function calls seem to be sufficient to 00237 // introduce that delay. A delay may be inserted here if this 00238 // software is ported to a faster processor. 00239 if (_latched) _nldac->write(0); 00240 // The LDAC pulse width must be at least T_LD=100 nanoseconds long. 00241 // A delay can be inserted here if necessary, but so far this has 00242 // not been needed (see above). 00243 return; 00244 } 00245 00246 // Set latch signal to "disable". 00247 void MCP4822A::latch_disable() { 00248 00249 // Disable latch for all chips. 00250 if (_latched) _nldac->write(1); 00251 return; 00252 } 00253 00254 // Shut down one chip. 00255 void MCP4822A::shdn( int dac ) { 00256 00257 // Shut down one particular chip 00258 _ncs_array[dac]->write(0); 00259 _spi.write(MCP4822_REG_SHDN); 00260 _ncs_array[dac]->write(1); 00261 return; 00262 } 00263 00264 // Shut down all chips. 00265 void MCP4822A::shdn_all( ) { 00266 00267 // Shut down all chips 00268 int dac; 00269 for (dac=0; dac<_ndacs; dac++) { 00270 shdn( dac ); 00271 } 00272 latch_disable(); 00273 return; 00274 }
Generated on Mon Jul 18 2022 01:10:52 by
1.7.2