001 /*----------------------------------------------------------------------------*/ 002 /* Copyright (c) FIRST 2008-2012. All Rights Reserved. */ 003 /* Open Source Software - may be modified and shared by FRC teams. The code */ 004 /* must be accompanied by the FIRST BSD license file in the root directory of */ 005 /* the project. */ 006 /*----------------------------------------------------------------------------*/ 007 008 package edu.wpi.first.wpilibj; 009 010 import edu.wpi.first.wpilibj.fpga.tAI; 011 import edu.wpi.first.wpilibj.communication.AICalibration; 012 import edu.wpi.first.wpilibj.communication.ModulePresence; 013 014 /** 015 * Analog Module class. 016 * Each module can independently sample its channels at a configurable rate. 017 * There is a 64-bit hardware accumulator associated with channel 1 on each module. 018 * The accumulator is attached to the output of the oversample and average engine so that the center 019 * value can be specified in higher resolution resulting in less error. 020 */ 021 public class AnalogModule extends Module { 022 023 /** 024 * The time base used by the module 025 */ 026 public static final int kTimebase = 40000000; 027 /** 028 * The default number of Oversample bits to use 029 */ 030 public static final int kDefaultOversampleBits = 0; 031 /** 032 * The default number of averaging bits to use 033 */ 034 public static final int kDefaultAverageBits = 7; 035 /** 036 * The default sample rate 037 */ 038 public static final double kDefaultSampleRate = 50000.0; 039 private tAI m_module; 040 private boolean m_sampleRateSet; 041 private long m_accumulatorOffset; 042 private int m_numChannelsToActivate; 043 private final Object syncRoot = new Object(); 044 045 /** 046 * Get an instance of an Analog Module. 047 * 048 * Singleton analog module creation where a module is allocated on the first use 049 * and the same module is returned on subsequent uses. 050 * 051 * @param moduleNumber The index of the analog module to get (1 or 2). 052 * @return The AnalogModule. 053 */ 054 public static synchronized AnalogModule getInstance(final int moduleNumber) { 055 checkAnalogModule(moduleNumber); 056 return (AnalogModule) getModule(ModulePresence.ModuleType.kAnalog, moduleNumber); 057 } 058 059 /** 060 * Create a new instance of an analog module. 061 * 062 * Create an instance of the analog module object. Initialize all the parameters 063 * to reasonable values on start. 064 * Setting a global value on an analog module can be done only once unless subsequent 065 * values are set the previously set value. 066 * Analog modules are a singleton, so the constructor is never called outside of this class. 067 * 068 * @param moduleNumber The index of the analog module to create (1 or 2). 069 */ 070 protected AnalogModule(final int moduleNumber) { 071 super(ModulePresence.ModuleType.kAnalog, moduleNumber); 072 073 m_module = new tAI(moduleNumber - 1); 074 setNumChannelsToActivate(SensorBase.kAnalogChannels); 075 setSampleRate(AnalogModule.kDefaultSampleRate); 076 077 for (int i = 0; i < SensorBase.kAnalogChannels; i++) { 078 m_module.writeScanList(i, i); 079 setAverageBits(i + 1, kDefaultAverageBits); 080 setOversampleBits(i + 1, kDefaultOversampleBits); 081 } 082 } 083 084 /** 085 * Set the sample rate on the module. 086 * 087 * This is a global setting for the module and effects all channels. 088 * 089 * @param samplesPerSecond 090 * The number of samples per channel per second. 091 */ 092 public void setSampleRate(final double samplesPerSecond) { 093 // TODO: This will change when variable size scan lists are implemented. 094 // TODO: Need float comparison with epsilon. 095 // wpi_assert(!sampleRateSet || GetSampleRate() == samplesPerSecond); 096 m_sampleRateSet = true; 097 098 // Compute the convert rate 099 final int ticksPerSample = (int) ((double)AnalogModule.kTimebase / samplesPerSecond); 100 int ticksPerConversion = ticksPerSample / getNumChannelsToActivate(); 101 // ticksPerConversion must be at least 80 102 // wpi_assert(ticksPerConversion >= 80); 103 if (ticksPerConversion < 80) { 104 ticksPerConversion = 80; 105 } 106 107 // Atomically set the scan size and the convert rate so that the sample 108 // rate is constant 109 m_module.writeConfig_ScanSize(getNumChannelsToActivate()); 110 m_module.writeConfig_ConvertRate(ticksPerConversion); 111 112 // Indicate that the scan size has been committed to hardware. 113 setNumChannelsToActivate(0); 114 } 115 116 /** 117 * Get the current sample rate on the module. 118 * 119 * This assumes one entry in the scan list. This is a global setting for the 120 * module and effects all channels. 121 * 122 * @return Sample rate. 123 */ 124 public double getSampleRate() { 125 final long ticksPerConversion = m_module.readLoopTiming(); 126 final long ticksPerSample = ticksPerConversion * getNumActiveChannels(); 127 128 return (double)AnalogModule.kTimebase / (double)ticksPerSample; 129 } 130 131 /** 132 * Return the number of channels on the module in use. 133 * 134 * @return Active channels. 135 */ 136 private int getNumActiveChannels() { 137 final int scanSize = m_module.readConfig_ScanSize(); 138 return scanSize == 0 ? 8 : scanSize; 139 } 140 141 /** 142 * Get the number of active channels. 143 * 144 * This is an internal function to allow the atomic update of both the 145 * number of active channels and the sample rate. 146 * 147 * When the number of channels changes, use the new value. Otherwise, 148 * return the curent value. 149 * 150 * @return Value to write to the active channels field. 151 */ 152 private int getNumChannelsToActivate() { 153 if (m_numChannelsToActivate == 0) { 154 return getNumActiveChannels(); 155 } 156 return m_numChannelsToActivate; 157 } 158 159 /** 160 * Set the number of active channels. 161 * 162 * Store the number of active channels to set. Don't actually commit to hardware 163 * until SetSampleRate(). 164 * 165 * @param channels Number of active channels. 166 */ 167 private void setNumChannelsToActivate(final int channels) { 168 m_numChannelsToActivate = channels; 169 } 170 171 /** 172 * Set the number of averaging bits. 173 * 174 * This sets the number of averaging bits. The actual number of averaged 175 * samples is 2**bits. The averaging is done automatically in the FPGA. 176 * 177 * @param channel 178 * Analog channel to configure. 179 * @param bits 180 * Number of bits to average. 181 */ 182 public void setAverageBits(final int channel, final int bits) { 183 m_module.writeAverageBits(channel - 1, bits); 184 } 185 186 /** 187 * Get the number of averaging bits. 188 * 189 * This gets the number of averaging bits from the FPGA. The actual number 190 * of averaged samples is 2**bits. The averaging is done automatically in 191 * the FPGA. 192 * 193 * @param channel Channel to address. 194 * @return Bits to average. 195 */ 196 public int getAverageBits(final int channel) { 197 return m_module.readAverageBits(channel - 1); 198 } 199 200 /** 201 * Set the number of oversample bits. 202 * 203 * This sets the number of oversample bits. The actual number of oversampled values is 2**bits. 204 * Use oversampling to improve the resolution of your measurements at the expense of sampling rate. 205 * The oversampling is done automatically in the FPGA. 206 * 207 * @param channel Analog channel to configure. 208 * @param bits Number of bits to oversample. 209 */ 210 public void setOversampleBits(final int channel, final int bits) { 211 m_module.writeOversampleBits(channel - 1, bits); 212 } 213 214 /** 215 * Get the number of oversample bits. 216 * 217 * This gets the number of oversample bits from the FPGA. The actual number 218 * of oversampled values is 2**bits. The oversampling is done automatically 219 * in the FPGA. 220 * 221 * @param channel Channel to address. 222 * @return Bits to oversample. 223 */ 224 public int getOversampleBits(final int channel) { 225 return m_module.readOversampleBits(channel - 1); 226 } 227 228 /** 229 * Get the raw analog value. 230 * 231 * Get the analog value as it is returned from the D/A converter. 232 * 233 * @param channel Channel number to read. 234 * @return Raw value. 235 */ 236 public int getValue(final int channel) { 237 int value; 238 SensorBase.checkAnalogChannel(channel); 239 240 synchronized (syncRoot) { 241 tAI.writeReadSelect_Channel(channel - 1); 242 tAI.writeReadSelect_Module(m_moduleNumber - 1); 243 tAI.writeReadSelect_Averaged(false); 244 245 tAI.strobeLatchOutput(); 246 value = tAI.readOutput(); 247 } 248 249 return (short) value; 250 } 251 252 /** 253 * Get the raw averaged and oversampled value. 254 * 255 * @param channel Channel number to read. 256 * @return The averaged and oversampled raw value. 257 */ 258 public int getAverageValue(final int channel) { 259 int value; 260 SensorBase.checkAnalogChannel(channel); 261 262 synchronized (syncRoot) { 263 tAI.writeReadSelect_Channel(channel - 1); 264 tAI.writeReadSelect_Module(m_moduleNumber - 1); 265 tAI.writeReadSelect_Averaged(true); 266 267 tAI.strobeLatchOutput(); 268 value = tAI.readOutput(); 269 } 270 271 return value; 272 } 273 274 /** 275 * Convert a voltage to a raw value for a specified channel. 276 * 277 * This process depends on the calibration of each channel, so the channel 278 * must be specified. 279 * 280 * @todo This assumes raw values. Oversampling not supported as is. 281 * 282 * @param channel 283 * The channel to convert for. 284 * @param voltage 285 * The voltage to convert. 286 * @return The raw value for the channel. 287 */ 288 public int voltsToValue(final int channel, final double voltage) { 289 // wpi_assert(voltage >= -10.0 && voltage <= 10.0); 290 final long LSBWeight = getLSBWeight(channel); 291 final int offset = getOffset(channel); 292 final int value = (int) ((voltage + offset * 1.0e-9) / (LSBWeight * 1.0e-9)); 293 294 return value; 295 } 296 297 /** 298 * Get the voltage. 299 * 300 * Return the voltage from the A/D converter. 301 * 302 * @param channel The channel to read. 303 * @return The scaled voltage from the channel. 304 */ 305 public double getVoltage(final int channel) { 306 final int value = getValue(channel); 307 final long LSBWeight = getLSBWeight(channel); 308 final int offset = getOffset(channel); 309 final double voltage = (LSBWeight * 1.0e-9 * value) - (offset * 1.0e-9); 310 311 return voltage; 312 } 313 314 /** 315 * Get the averaged voltage. 316 * 317 * Return the averaged voltage from the A/D converter. 318 * 319 * @param channel The channel to read. 320 * @return The scaled averaged and oversampled voltage from the channel. 321 */ 322 public double getAverageVoltage(final int channel) { 323 final int value = getAverageValue(channel); 324 final long LSBWeight = getLSBWeight(channel); 325 final int offset = getOffset(channel); 326 final int oversampleBits = getOversampleBits(channel); 327 final double voltage = ((LSBWeight * 1.0e-9 * value) / (double)(1 << oversampleBits)) - (offset * 1.0e-9); 328 329 return voltage; 330 } 331 332 /** 333 * Get the LSB Weight portion of the calibration for a channel. 334 * 335 * @param channel The channel to get calibration data for. 336 * @return LSB Weight calibration point. 337 */ 338 public long getLSBWeight(final int channel) { 339 // TODO: add scaling to make this worth while. 340 return AICalibration.getLSBWeight(m_module.getSystemIndex(), channel - 1); 341 } 342 343 /** 344 * Get the Offset portion of the calibration for a channel. 345 * 346 * @param channel The channel to get calibration data for. 347 * @return Offset calibration point. 348 */ 349 public int getOffset(final int channel) { 350 // TODO: add scaling to make this worth while. 351 // TODO: actually use this function. 352 return AICalibration.getOffset(m_module.getSystemIndex(), channel - 1); 353 } 354 }