A sine wave generator using AD9833 and AD9850 using STM32F103RB
This is a sine wave generator using DDS IC' AD9833 and AD9850. The STM32F1 microcontroller produces the SPI commands for the two DDS.
Learn more about STM32F1 in my blog: https://www.teachmemicro.com
AD9833.cpp@0:6069c0f2a245, 2017-11-21 (annotated)
- Committer:
- roland_tmm
- Date:
- Tue Nov 21 11:24:25 2017 +0000
- Revision:
- 0:6069c0f2a245
- Child:
- 2:602f7589c53e
Version 1.0
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
roland_tmm | 0:6069c0f2a245 | 1 | /* |
roland_tmm | 0:6069c0f2a245 | 2 | * AD9833.cpp |
roland_tmm | 0:6069c0f2a245 | 3 | * |
roland_tmm | 0:6069c0f2a245 | 4 | * Copyright 2016 Bill Williams <wlwilliams1952@gmail.com, github/BillWilliams1952> |
roland_tmm | 0:6069c0f2a245 | 5 | * |
roland_tmm | 0:6069c0f2a245 | 6 | * Thanks to john@vwlowen.co.uk for his work on the AD9833. His web page |
roland_tmm | 0:6069c0f2a245 | 7 | * is: http://www.vwlowen.co.uk/arduino/AD9833-waveform-generator/AD9833-waveform-generator.htm |
roland_tmm | 0:6069c0f2a245 | 8 | * |
roland_tmm | 0:6069c0f2a245 | 9 | * This program is free software; you can redistribute it and/or modify |
roland_tmm | 0:6069c0f2a245 | 10 | * it under the terms of the GNU General Public License as published by |
roland_tmm | 0:6069c0f2a245 | 11 | * the Free Software Foundation; either version 2 of the License, or |
roland_tmm | 0:6069c0f2a245 | 12 | * (at your option) any later version. |
roland_tmm | 0:6069c0f2a245 | 13 | * |
roland_tmm | 0:6069c0f2a245 | 14 | * This program is distributed in the hope that it will be useful, |
roland_tmm | 0:6069c0f2a245 | 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
roland_tmm | 0:6069c0f2a245 | 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
roland_tmm | 0:6069c0f2a245 | 17 | * GNU General Public License for more details. |
roland_tmm | 0:6069c0f2a245 | 18 | * |
roland_tmm | 0:6069c0f2a245 | 19 | * You should have received a copy of the GNU General Public License |
roland_tmm | 0:6069c0f2a245 | 20 | * along with this program; if not, write to the Free Software |
roland_tmm | 0:6069c0f2a245 | 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
roland_tmm | 0:6069c0f2a245 | 22 | * MA 02110-1301, USA. |
roland_tmm | 0:6069c0f2a245 | 23 | * |
roland_tmm | 0:6069c0f2a245 | 24 | */ |
roland_tmm | 0:6069c0f2a245 | 25 | #include "mbed.h" |
roland_tmm | 0:6069c0f2a245 | 26 | #include "AD9833.h" |
roland_tmm | 0:6069c0f2a245 | 27 | |
roland_tmm | 0:6069c0f2a245 | 28 | #define SPI_MOSI PA_7 |
roland_tmm | 0:6069c0f2a245 | 29 | #define SPI_MISO PA_6 |
roland_tmm | 0:6069c0f2a245 | 30 | #define SPI_SCK PA_5 |
roland_tmm | 0:6069c0f2a245 | 31 | #define FNCpin PA_4 |
roland_tmm | 0:6069c0f2a245 | 32 | |
roland_tmm | 0:6069c0f2a245 | 33 | DigitalOut fnc_pin(FNCpin); |
roland_tmm | 0:6069c0f2a245 | 34 | SPI SPI_dev(SPI_MOSI, SPI_MISO, SPI_SCK); |
roland_tmm | 0:6069c0f2a245 | 35 | |
roland_tmm | 0:6069c0f2a245 | 36 | /* |
roland_tmm | 0:6069c0f2a245 | 37 | * Create an AD9833 object |
roland_tmm | 0:6069c0f2a245 | 38 | */ |
roland_tmm | 0:6069c0f2a245 | 39 | AD9833 :: AD9833 (uint32_t referenceFrequency ) { |
roland_tmm | 0:6069c0f2a245 | 40 | // Pin used to enable SPI communication (active LOW) |
roland_tmm | 0:6069c0f2a245 | 41 | |
roland_tmm | 0:6069c0f2a245 | 42 | FNCWrite(1); |
roland_tmm | 0:6069c0f2a245 | 43 | |
roland_tmm | 0:6069c0f2a245 | 44 | /* TODO: The minimum resolution and max frequency are determined by |
roland_tmm | 0:6069c0f2a245 | 45 | * by referenceFrequency. We should calculate these values and use |
roland_tmm | 0:6069c0f2a245 | 46 | * them during setFrequency. The problem is if the user programs a |
roland_tmm | 0:6069c0f2a245 | 47 | * square wave at refFrequency/2, then changes the waveform to sine. |
roland_tmm | 0:6069c0f2a245 | 48 | * The sine wave will not have enough points? |
roland_tmm | 0:6069c0f2a245 | 49 | */ |
roland_tmm | 0:6069c0f2a245 | 50 | refFrequency = referenceFrequency; |
roland_tmm | 0:6069c0f2a245 | 51 | |
roland_tmm | 0:6069c0f2a245 | 52 | // Setup some defaults |
roland_tmm | 0:6069c0f2a245 | 53 | DacDisabled = false; |
roland_tmm | 0:6069c0f2a245 | 54 | IntClkDisabled = false; |
roland_tmm | 0:6069c0f2a245 | 55 | outputEnabled = false; |
roland_tmm | 0:6069c0f2a245 | 56 | waveForm0 = waveForm1 = SINE_WAVE; |
roland_tmm | 0:6069c0f2a245 | 57 | frequency0 = frequency1 = 1000; // 1 KHz sine wave to start |
roland_tmm | 0:6069c0f2a245 | 58 | phase0 = phase1 = 0.0; // 0 phase |
roland_tmm | 0:6069c0f2a245 | 59 | activeFreq = REG0; activePhase = REG0; |
roland_tmm | 0:6069c0f2a245 | 60 | } |
roland_tmm | 0:6069c0f2a245 | 61 | |
roland_tmm | 0:6069c0f2a245 | 62 | /* |
roland_tmm | 0:6069c0f2a245 | 63 | * This MUST be the first command after declaring the AD9833 object |
roland_tmm | 0:6069c0f2a245 | 64 | * Start SPI and place the AD9833 in the RESET state |
roland_tmm | 0:6069c0f2a245 | 65 | */ |
roland_tmm | 0:6069c0f2a245 | 66 | void AD9833 :: Begin ( void ) { |
roland_tmm | 0:6069c0f2a245 | 67 | wait(0.1); |
roland_tmm | 0:6069c0f2a245 | 68 | Reset(); // Hold in RESET until first WriteRegister command |
roland_tmm | 0:6069c0f2a245 | 69 | } |
roland_tmm | 0:6069c0f2a245 | 70 | |
roland_tmm | 0:6069c0f2a245 | 71 | /* |
roland_tmm | 0:6069c0f2a245 | 72 | * Setup and apply a signal. phaseInDeg defaults to 0.0 if not supplied. |
roland_tmm | 0:6069c0f2a245 | 73 | * phaseReg defaults to value of freqReg if not supplied. |
roland_tmm | 0:6069c0f2a245 | 74 | * Note that any previous calls to EnableOut, |
roland_tmm | 0:6069c0f2a245 | 75 | * SleepMode, DisableDAC, or DisableInternalClock remain in effect. |
roland_tmm | 0:6069c0f2a245 | 76 | */ |
roland_tmm | 0:6069c0f2a245 | 77 | void AD9833 :: ApplySignal ( WaveformType waveType, |
roland_tmm | 0:6069c0f2a245 | 78 | Registers freqReg, float frequencyInHz, |
roland_tmm | 0:6069c0f2a245 | 79 | Registers phaseReg, float phaseInDeg ) { |
roland_tmm | 0:6069c0f2a245 | 80 | SetGENFrequency ( freqReg, frequencyInHz ); |
roland_tmm | 0:6069c0f2a245 | 81 | SetPhase ( phaseReg, phaseInDeg ); |
roland_tmm | 0:6069c0f2a245 | 82 | SetWaveform ( freqReg, waveType ); |
roland_tmm | 0:6069c0f2a245 | 83 | SetOutputSource ( freqReg, phaseReg ); |
roland_tmm | 0:6069c0f2a245 | 84 | } |
roland_tmm | 0:6069c0f2a245 | 85 | |
roland_tmm | 0:6069c0f2a245 | 86 | /*********************************************************************** |
roland_tmm | 0:6069c0f2a245 | 87 | Control Register |
roland_tmm | 0:6069c0f2a245 | 88 | ------------------------------------------------------------------------ |
roland_tmm | 0:6069c0f2a245 | 89 | D15,D14(MSB) 10 = FREQ1 write, 01 = FREQ0 write, |
roland_tmm | 0:6069c0f2a245 | 90 | 11 = PHASE write, 00 = control write |
roland_tmm | 0:6069c0f2a245 | 91 | D13 If D15,D14 = 00, 0 = individual LSB and MSB FREQ write, |
roland_tmm | 0:6069c0f2a245 | 92 | 1 = both LSB and MSB FREQ writes consecutively |
roland_tmm | 0:6069c0f2a245 | 93 | If D15,D14 = 11, 0 = PHASE0 write, 1 = PHASE1 write |
roland_tmm | 0:6069c0f2a245 | 94 | D12 0 = writing LSB independently |
roland_tmm | 0:6069c0f2a245 | 95 | 1 = writing MSB independently |
roland_tmm | 0:6069c0f2a245 | 96 | D11 0 = output FREQ0, |
roland_tmm | 0:6069c0f2a245 | 97 | 1 = output FREQ1 |
roland_tmm | 0:6069c0f2a245 | 98 | D10 0 = output PHASE0 |
roland_tmm | 0:6069c0f2a245 | 99 | 1 = output PHASE1 |
roland_tmm | 0:6069c0f2a245 | 100 | D9 Reserved. Must be 0. |
roland_tmm | 0:6069c0f2a245 | 101 | D8 0 = RESET disabled |
roland_tmm | 0:6069c0f2a245 | 102 | 1 = RESET enabled |
roland_tmm | 0:6069c0f2a245 | 103 | D7 0 = internal clock is enabled |
roland_tmm | 0:6069c0f2a245 | 104 | 1 = internal clock is disabled |
roland_tmm | 0:6069c0f2a245 | 105 | D6 0 = onboard DAC is active for sine and triangle wave output, |
roland_tmm | 0:6069c0f2a245 | 106 | 1 = put DAC to sleep for square wave output |
roland_tmm | 0:6069c0f2a245 | 107 | D5 0 = output depends on D1 |
roland_tmm | 0:6069c0f2a245 | 108 | 1 = output is a square wave |
roland_tmm | 0:6069c0f2a245 | 109 | D4 Reserved. Must be 0. |
roland_tmm | 0:6069c0f2a245 | 110 | D3 0 = square wave of half frequency output |
roland_tmm | 0:6069c0f2a245 | 111 | 1 = square wave output |
roland_tmm | 0:6069c0f2a245 | 112 | D2 Reserved. Must be 0. |
roland_tmm | 0:6069c0f2a245 | 113 | D1 If D5 = 1, D1 = 0. |
roland_tmm | 0:6069c0f2a245 | 114 | Otherwise 0 = sine output, 1 = triangle output |
roland_tmm | 0:6069c0f2a245 | 115 | D0 Reserved. Must be 0. |
roland_tmm | 0:6069c0f2a245 | 116 | ***********************************************************************/ |
roland_tmm | 0:6069c0f2a245 | 117 | |
roland_tmm | 0:6069c0f2a245 | 118 | /* |
roland_tmm | 0:6069c0f2a245 | 119 | * Hold the AD9833 in RESET state. |
roland_tmm | 0:6069c0f2a245 | 120 | * Resets internal registers to 0, which corresponds to an output of |
roland_tmm | 0:6069c0f2a245 | 121 | * midscale - digital output at 0. |
roland_tmm | 0:6069c0f2a245 | 122 | * |
roland_tmm | 0:6069c0f2a245 | 123 | * The difference between Reset() and EnableOutput(false) is that |
roland_tmm | 0:6069c0f2a245 | 124 | * EnableOutput(false) keeps the AD9833 in the RESET state until you |
roland_tmm | 0:6069c0f2a245 | 125 | * specifically remove the RESET state using EnableOutput(true). |
roland_tmm | 0:6069c0f2a245 | 126 | * With a call to Reset(), ANY subsequent call to ANY function (other |
roland_tmm | 0:6069c0f2a245 | 127 | * than Reset itself and Set/IncrementPhase) will also remove the RESET |
roland_tmm | 0:6069c0f2a245 | 128 | * state. |
roland_tmm | 0:6069c0f2a245 | 129 | */ |
roland_tmm | 0:6069c0f2a245 | 130 | void AD9833 :: Reset ( void ) { |
roland_tmm | 0:6069c0f2a245 | 131 | WriteRegister(RESET_CMD); |
roland_tmm | 0:6069c0f2a245 | 132 | wait(0.015); |
roland_tmm | 0:6069c0f2a245 | 133 | } |
roland_tmm | 0:6069c0f2a245 | 134 | |
roland_tmm | 0:6069c0f2a245 | 135 | /* |
roland_tmm | 0:6069c0f2a245 | 136 | * Set the specified frequency register with the frequency (in Hz) |
roland_tmm | 0:6069c0f2a245 | 137 | */ |
roland_tmm | 0:6069c0f2a245 | 138 | void AD9833 :: SetGENFrequency ( Registers freqReg, float frequency ) { |
roland_tmm | 0:6069c0f2a245 | 139 | // TODO: calculate max frequency based on refFrequency. |
roland_tmm | 0:6069c0f2a245 | 140 | // Use the calculations for sanity checks on numbers. |
roland_tmm | 0:6069c0f2a245 | 141 | // Sanity check on frequency: Square - refFrequency / 2 |
roland_tmm | 0:6069c0f2a245 | 142 | // Sine/Triangle - refFrequency / 4 |
roland_tmm | 0:6069c0f2a245 | 143 | if ( frequency > 12.5e6 ) // TODO: Fix this based on refFreq |
roland_tmm | 0:6069c0f2a245 | 144 | frequency = 12.5e6; |
roland_tmm | 0:6069c0f2a245 | 145 | if ( frequency < 0.0 ) frequency = 0.0; |
roland_tmm | 0:6069c0f2a245 | 146 | |
roland_tmm | 0:6069c0f2a245 | 147 | // Save frequency for use by IncrementFrequency function |
roland_tmm | 0:6069c0f2a245 | 148 | if ( freqReg == REG0 ) frequency0 = frequency; |
roland_tmm | 0:6069c0f2a245 | 149 | else frequency1 = frequency; |
roland_tmm | 0:6069c0f2a245 | 150 | |
roland_tmm | 0:6069c0f2a245 | 151 | int32_t freqWord = (frequency * pow2_28) / (float)refFrequency; |
roland_tmm | 0:6069c0f2a245 | 152 | int16_t upper14 = (int16_t)((freqWord & 0xFFFC000) >> 14), |
roland_tmm | 0:6069c0f2a245 | 153 | lower14 = (int16_t)(freqWord & 0x3FFF); |
roland_tmm | 0:6069c0f2a245 | 154 | |
roland_tmm | 0:6069c0f2a245 | 155 | // Which frequency register are we updating? |
roland_tmm | 0:6069c0f2a245 | 156 | uint16_t reg = freqReg == REG0 ? FREQ0_WRITE_REG : FREQ1_WRITE_REG; |
roland_tmm | 0:6069c0f2a245 | 157 | lower14 |= reg; |
roland_tmm | 0:6069c0f2a245 | 158 | upper14 |= reg; |
roland_tmm | 0:6069c0f2a245 | 159 | |
roland_tmm | 0:6069c0f2a245 | 160 | // I do not reset the registers during write. It seems to remove |
roland_tmm | 0:6069c0f2a245 | 161 | // 'glitching' on the outputs. |
roland_tmm | 0:6069c0f2a245 | 162 | WriteControlRegister(); |
roland_tmm | 0:6069c0f2a245 | 163 | // Control register has already been setup to accept two frequency |
roland_tmm | 0:6069c0f2a245 | 164 | // writes, one for each 14 bit part of the 28 bit frequency word |
roland_tmm | 0:6069c0f2a245 | 165 | WriteRegister(lower14); // Write lower 14 bits to AD9833 |
roland_tmm | 0:6069c0f2a245 | 166 | WriteRegister(upper14); // Write upper 14 bits to AD9833 |
roland_tmm | 0:6069c0f2a245 | 167 | } |
roland_tmm | 0:6069c0f2a245 | 168 | |
roland_tmm | 0:6069c0f2a245 | 169 | /* |
roland_tmm | 0:6069c0f2a245 | 170 | * Increment the specified frequency register with the frequency (in Hz) |
roland_tmm | 0:6069c0f2a245 | 171 | */ |
roland_tmm | 0:6069c0f2a245 | 172 | void AD9833 :: IncrementFrequency ( Registers freqReg, float freqIncHz ) { |
roland_tmm | 0:6069c0f2a245 | 173 | // Add/subtract a value from the current frequency programmed in |
roland_tmm | 0:6069c0f2a245 | 174 | // freqReg by the amount given |
roland_tmm | 0:6069c0f2a245 | 175 | float frequency = (freqReg == REG0) ? frequency0 : frequency1; |
roland_tmm | 0:6069c0f2a245 | 176 | SetGENFrequency(freqReg,frequency+freqIncHz); |
roland_tmm | 0:6069c0f2a245 | 177 | } |
roland_tmm | 0:6069c0f2a245 | 178 | |
roland_tmm | 0:6069c0f2a245 | 179 | /* |
roland_tmm | 0:6069c0f2a245 | 180 | * Set the specified phase register with the phase (in degrees) |
roland_tmm | 0:6069c0f2a245 | 181 | * The output signal will be phase shifted by 2π/4096 x PHASEREG |
roland_tmm | 0:6069c0f2a245 | 182 | */ |
roland_tmm | 0:6069c0f2a245 | 183 | void AD9833 :: SetPhase ( Registers phaseReg, float phaseInDeg ) { |
roland_tmm | 0:6069c0f2a245 | 184 | // Sanity checks on input |
roland_tmm | 0:6069c0f2a245 | 185 | phaseInDeg = fmod(phaseInDeg,360); |
roland_tmm | 0:6069c0f2a245 | 186 | if ( phaseInDeg < 0 ) phaseInDeg += 360; |
roland_tmm | 0:6069c0f2a245 | 187 | |
roland_tmm | 0:6069c0f2a245 | 188 | // Phase is in float degrees ( 0.0 - 360.0 ) |
roland_tmm | 0:6069c0f2a245 | 189 | // Convert to a number 0 to 4096 where 4096 = 0 by masking |
roland_tmm | 0:6069c0f2a245 | 190 | uint16_t phaseVal = (uint16_t)(BITS_PER_DEG * phaseInDeg) & 0x0FFF; |
roland_tmm | 0:6069c0f2a245 | 191 | phaseVal |= PHASE_WRITE_CMD; |
roland_tmm | 0:6069c0f2a245 | 192 | |
roland_tmm | 0:6069c0f2a245 | 193 | // Save phase for use by IncrementPhase function |
roland_tmm | 0:6069c0f2a245 | 194 | if ( phaseReg == REG0 ) { |
roland_tmm | 0:6069c0f2a245 | 195 | phase0 = phaseInDeg; |
roland_tmm | 0:6069c0f2a245 | 196 | } |
roland_tmm | 0:6069c0f2a245 | 197 | else { |
roland_tmm | 0:6069c0f2a245 | 198 | phase1 = phaseInDeg; |
roland_tmm | 0:6069c0f2a245 | 199 | phaseVal |= PHASE1_WRITE_REG; |
roland_tmm | 0:6069c0f2a245 | 200 | } |
roland_tmm | 0:6069c0f2a245 | 201 | WriteRegister(phaseVal); |
roland_tmm | 0:6069c0f2a245 | 202 | } |
roland_tmm | 0:6069c0f2a245 | 203 | |
roland_tmm | 0:6069c0f2a245 | 204 | /* |
roland_tmm | 0:6069c0f2a245 | 205 | * Increment the specified phase register by the phase (in degrees) |
roland_tmm | 0:6069c0f2a245 | 206 | */ |
roland_tmm | 0:6069c0f2a245 | 207 | void AD9833 :: IncrementPhase ( Registers phaseReg, float phaseIncDeg ) { |
roland_tmm | 0:6069c0f2a245 | 208 | // Add/subtract a value from the current phase programmed in |
roland_tmm | 0:6069c0f2a245 | 209 | // phaseReg by the amount given |
roland_tmm | 0:6069c0f2a245 | 210 | float phase = (phaseReg == REG0) ? phase0 : phase1; |
roland_tmm | 0:6069c0f2a245 | 211 | SetPhase(phaseReg,phase + phaseIncDeg); |
roland_tmm | 0:6069c0f2a245 | 212 | } |
roland_tmm | 0:6069c0f2a245 | 213 | |
roland_tmm | 0:6069c0f2a245 | 214 | /* |
roland_tmm | 0:6069c0f2a245 | 215 | * Set the type of waveform that is output for a frequency register |
roland_tmm | 0:6069c0f2a245 | 216 | * SINE_WAVE, TRIANGLE_WAVE, SQUARE_WAVE, HALF_SQUARE_WAVE |
roland_tmm | 0:6069c0f2a245 | 217 | */ |
roland_tmm | 0:6069c0f2a245 | 218 | void AD9833 :: SetWaveform ( Registers waveFormReg, WaveformType waveType ) { |
roland_tmm | 0:6069c0f2a245 | 219 | // TODO: Add more error checking? |
roland_tmm | 0:6069c0f2a245 | 220 | if ( waveFormReg == REG0 ) |
roland_tmm | 0:6069c0f2a245 | 221 | waveForm0 = waveType; |
roland_tmm | 0:6069c0f2a245 | 222 | else |
roland_tmm | 0:6069c0f2a245 | 223 | waveForm1 = waveType; |
roland_tmm | 0:6069c0f2a245 | 224 | WriteControlRegister(); |
roland_tmm | 0:6069c0f2a245 | 225 | } |
roland_tmm | 0:6069c0f2a245 | 226 | |
roland_tmm | 0:6069c0f2a245 | 227 | /* |
roland_tmm | 0:6069c0f2a245 | 228 | * EnableOutput(false) keeps the AD9833 is RESET state until a call to |
roland_tmm | 0:6069c0f2a245 | 229 | * EnableOutput(true). See the Reset function description. |
roland_tmm | 0:6069c0f2a245 | 230 | */ |
roland_tmm | 0:6069c0f2a245 | 231 | void AD9833 :: EnableOutput ( bool enable ) { |
roland_tmm | 0:6069c0f2a245 | 232 | outputEnabled = enable; |
roland_tmm | 0:6069c0f2a245 | 233 | WriteControlRegister(); |
roland_tmm | 0:6069c0f2a245 | 234 | } |
roland_tmm | 0:6069c0f2a245 | 235 | |
roland_tmm | 0:6069c0f2a245 | 236 | /* |
roland_tmm | 0:6069c0f2a245 | 237 | * Set which frequency and phase register is being used to output the |
roland_tmm | 0:6069c0f2a245 | 238 | * waveform. If phaseReg is not supplied, it defaults to the same |
roland_tmm | 0:6069c0f2a245 | 239 | * register as freqReg. |
roland_tmm | 0:6069c0f2a245 | 240 | */ |
roland_tmm | 0:6069c0f2a245 | 241 | void AD9833 :: SetOutputSource ( Registers freqReg, Registers phaseReg ) { |
roland_tmm | 0:6069c0f2a245 | 242 | // TODO: Add more error checking? |
roland_tmm | 0:6069c0f2a245 | 243 | activeFreq = freqReg; |
roland_tmm | 0:6069c0f2a245 | 244 | if ( phaseReg == SAME_AS_REG0 ) activePhase = activeFreq; |
roland_tmm | 0:6069c0f2a245 | 245 | else activePhase = phaseReg; |
roland_tmm | 0:6069c0f2a245 | 246 | WriteControlRegister(); |
roland_tmm | 0:6069c0f2a245 | 247 | } |
roland_tmm | 0:6069c0f2a245 | 248 | |
roland_tmm | 0:6069c0f2a245 | 249 | //---------- LOWER LEVEL FUNCTIONS NOT NORMALLY NEEDED ------------- |
roland_tmm | 0:6069c0f2a245 | 250 | |
roland_tmm | 0:6069c0f2a245 | 251 | /* |
roland_tmm | 0:6069c0f2a245 | 252 | * Disable/enable both the internal clock and the DAC. Note that square |
roland_tmm | 0:6069c0f2a245 | 253 | * wave outputs are avaiable if using an external Reference. |
roland_tmm | 0:6069c0f2a245 | 254 | * TODO: ?? IS THIS TRUE ?? |
roland_tmm | 0:6069c0f2a245 | 255 | */ |
roland_tmm | 0:6069c0f2a245 | 256 | void AD9833 :: SleepMode ( bool enable ) { |
roland_tmm | 0:6069c0f2a245 | 257 | DacDisabled = enable; |
roland_tmm | 0:6069c0f2a245 | 258 | IntClkDisabled = enable; |
roland_tmm | 0:6069c0f2a245 | 259 | WriteControlRegister(); |
roland_tmm | 0:6069c0f2a245 | 260 | } |
roland_tmm | 0:6069c0f2a245 | 261 | |
roland_tmm | 0:6069c0f2a245 | 262 | /* |
roland_tmm | 0:6069c0f2a245 | 263 | * Enables / disables the DAC. It will override any previous DAC |
roland_tmm | 0:6069c0f2a245 | 264 | * setting by Waveform type, or via the SleepMode function |
roland_tmm | 0:6069c0f2a245 | 265 | */ |
roland_tmm | 0:6069c0f2a245 | 266 | void AD9833 :: DisableDAC ( bool enable ) { |
roland_tmm | 0:6069c0f2a245 | 267 | DacDisabled = enable; |
roland_tmm | 0:6069c0f2a245 | 268 | WriteControlRegister(); |
roland_tmm | 0:6069c0f2a245 | 269 | } |
roland_tmm | 0:6069c0f2a245 | 270 | |
roland_tmm | 0:6069c0f2a245 | 271 | /* |
roland_tmm | 0:6069c0f2a245 | 272 | * Enables / disables the internal clock. It will override any |
roland_tmm | 0:6069c0f2a245 | 273 | * previous clock setting by the SleepMode function |
roland_tmm | 0:6069c0f2a245 | 274 | */ |
roland_tmm | 0:6069c0f2a245 | 275 | void AD9833 :: DisableInternalClock ( bool enable ) { |
roland_tmm | 0:6069c0f2a245 | 276 | IntClkDisabled = enable; |
roland_tmm | 0:6069c0f2a245 | 277 | WriteControlRegister(); |
roland_tmm | 0:6069c0f2a245 | 278 | } |
roland_tmm | 0:6069c0f2a245 | 279 | |
roland_tmm | 0:6069c0f2a245 | 280 | // ------------ STATUS / INFORMATION FUNCTIONS ------------------- |
roland_tmm | 0:6069c0f2a245 | 281 | /* |
roland_tmm | 0:6069c0f2a245 | 282 | * Return actual frequency programmed |
roland_tmm | 0:6069c0f2a245 | 283 | */ |
roland_tmm | 0:6069c0f2a245 | 284 | float AD9833 :: GetActualProgrammedFrequency ( Registers reg ) { |
roland_tmm | 0:6069c0f2a245 | 285 | float frequency = reg == REG0 ? frequency0 : frequency1; |
roland_tmm | 0:6069c0f2a245 | 286 | int32_t freqWord = (uint32_t)((frequency * pow2_28) / (float)refFrequency) & 0x0FFFFFFFUL; |
roland_tmm | 0:6069c0f2a245 | 287 | return (float)freqWord * (float)refFrequency / (float)pow2_28; |
roland_tmm | 0:6069c0f2a245 | 288 | } |
roland_tmm | 0:6069c0f2a245 | 289 | |
roland_tmm | 0:6069c0f2a245 | 290 | /* |
roland_tmm | 0:6069c0f2a245 | 291 | * Return actual phase programmed |
roland_tmm | 0:6069c0f2a245 | 292 | */ |
roland_tmm | 0:6069c0f2a245 | 293 | float AD9833 :: GetActualProgrammedPhase ( Registers reg ) { |
roland_tmm | 0:6069c0f2a245 | 294 | float phase = reg == REG0 ? phase0 : phase1; |
roland_tmm | 0:6069c0f2a245 | 295 | uint16_t phaseVal = (uint16_t)(BITS_PER_DEG * phase) & 0x0FFF; |
roland_tmm | 0:6069c0f2a245 | 296 | return (float)phaseVal / BITS_PER_DEG; |
roland_tmm | 0:6069c0f2a245 | 297 | } |
roland_tmm | 0:6069c0f2a245 | 298 | |
roland_tmm | 0:6069c0f2a245 | 299 | /* |
roland_tmm | 0:6069c0f2a245 | 300 | * Return frequency resolution |
roland_tmm | 0:6069c0f2a245 | 301 | */ |
roland_tmm | 0:6069c0f2a245 | 302 | float AD9833 :: GetResolution ( void ) { |
roland_tmm | 0:6069c0f2a245 | 303 | return (float)refFrequency / (float)pow2_28; |
roland_tmm | 0:6069c0f2a245 | 304 | } |
roland_tmm | 0:6069c0f2a245 | 305 | |
roland_tmm | 0:6069c0f2a245 | 306 | // --------------------- PRIVATE FUNCTIONS -------------------------- |
roland_tmm | 0:6069c0f2a245 | 307 | |
roland_tmm | 0:6069c0f2a245 | 308 | /* |
roland_tmm | 0:6069c0f2a245 | 309 | * Write control register. Setup register based on defined states |
roland_tmm | 0:6069c0f2a245 | 310 | */ |
roland_tmm | 0:6069c0f2a245 | 311 | void AD9833 :: WriteControlRegister ( void ) { |
roland_tmm | 0:6069c0f2a245 | 312 | uint16_t waveForm; |
roland_tmm | 0:6069c0f2a245 | 313 | // TODO: can speed things up by keeping a writeReg0 and writeReg1 |
roland_tmm | 0:6069c0f2a245 | 314 | // that presets all bits during the various setup function calls |
roland_tmm | 0:6069c0f2a245 | 315 | // rather than setting flags. Then we could just call WriteRegister |
roland_tmm | 0:6069c0f2a245 | 316 | // directly. |
roland_tmm | 0:6069c0f2a245 | 317 | if ( activeFreq == REG0 ) { |
roland_tmm | 0:6069c0f2a245 | 318 | waveForm = waveForm0; |
roland_tmm | 0:6069c0f2a245 | 319 | waveForm &= ~FREQ1_OUTPUT_REG; |
roland_tmm | 0:6069c0f2a245 | 320 | } |
roland_tmm | 0:6069c0f2a245 | 321 | else { |
roland_tmm | 0:6069c0f2a245 | 322 | waveForm = waveForm1; |
roland_tmm | 0:6069c0f2a245 | 323 | waveForm |= FREQ1_OUTPUT_REG; |
roland_tmm | 0:6069c0f2a245 | 324 | } |
roland_tmm | 0:6069c0f2a245 | 325 | if ( activePhase == REG0 ) |
roland_tmm | 0:6069c0f2a245 | 326 | waveForm &= ~PHASE1_OUTPUT_REG; |
roland_tmm | 0:6069c0f2a245 | 327 | else |
roland_tmm | 0:6069c0f2a245 | 328 | waveForm |= PHASE1_OUTPUT_REG; |
roland_tmm | 0:6069c0f2a245 | 329 | if ( outputEnabled ) |
roland_tmm | 0:6069c0f2a245 | 330 | waveForm &= ~RESET_CMD; |
roland_tmm | 0:6069c0f2a245 | 331 | else |
roland_tmm | 0:6069c0f2a245 | 332 | waveForm |= RESET_CMD; |
roland_tmm | 0:6069c0f2a245 | 333 | if ( DacDisabled ) |
roland_tmm | 0:6069c0f2a245 | 334 | waveForm |= DISABLE_DAC; |
roland_tmm | 0:6069c0f2a245 | 335 | else |
roland_tmm | 0:6069c0f2a245 | 336 | waveForm &= ~DISABLE_DAC; |
roland_tmm | 0:6069c0f2a245 | 337 | if ( IntClkDisabled ) |
roland_tmm | 0:6069c0f2a245 | 338 | waveForm |= DISABLE_INT_CLK; |
roland_tmm | 0:6069c0f2a245 | 339 | else |
roland_tmm | 0:6069c0f2a245 | 340 | waveForm &= ~DISABLE_INT_CLK; |
roland_tmm | 0:6069c0f2a245 | 341 | |
roland_tmm | 0:6069c0f2a245 | 342 | WriteRegister ( waveForm ); |
roland_tmm | 0:6069c0f2a245 | 343 | } |
roland_tmm | 0:6069c0f2a245 | 344 | |
roland_tmm | 0:6069c0f2a245 | 345 | void AD9833 :: FNCWrite(int val){ |
roland_tmm | 0:6069c0f2a245 | 346 | fnc_pin = val; |
roland_tmm | 0:6069c0f2a245 | 347 | } |
roland_tmm | 0:6069c0f2a245 | 348 | |
roland_tmm | 0:6069c0f2a245 | 349 | void AD9833 :: WriteRegister ( int16_t dat ) { |
roland_tmm | 0:6069c0f2a245 | 350 | /* |
roland_tmm | 0:6069c0f2a245 | 351 | * We set the mode here, because other hardware may be doing SPI also |
roland_tmm | 0:6069c0f2a245 | 352 | */ |
roland_tmm | 0:6069c0f2a245 | 353 | SPI_dev.format(8, 2); |
roland_tmm | 0:6069c0f2a245 | 354 | |
roland_tmm | 0:6069c0f2a245 | 355 | /* Improve overall switching speed |
roland_tmm | 0:6069c0f2a245 | 356 | * Note, the times are for this function call, not the write. |
roland_tmm | 0:6069c0f2a245 | 357 | * digitalWrite(FNCpin) ~ 17.6 usec |
roland_tmm | 0:6069c0f2a245 | 358 | * digitalWriteFast2(FNC_PIN) ~ 8.8 usec |
roland_tmm | 0:6069c0f2a245 | 359 | */ |
roland_tmm | 0:6069c0f2a245 | 360 | FNCWrite(0); // FNCpin low to write to AD9833 |
roland_tmm | 0:6069c0f2a245 | 361 | |
roland_tmm | 0:6069c0f2a245 | 362 | //delayMicroseconds(2); // Some delay may be needed |
roland_tmm | 0:6069c0f2a245 | 363 | |
roland_tmm | 0:6069c0f2a245 | 364 | // TODO: Are we running at the highest clock rate? |
roland_tmm | 0:6069c0f2a245 | 365 | SPI_dev.write(dat & 0xF0); // Transmit 16 bits 8 bits at a time |
roland_tmm | 0:6069c0f2a245 | 366 | SPI_dev.write(dat & 0x0F); |
roland_tmm | 0:6069c0f2a245 | 367 | |
roland_tmm | 0:6069c0f2a245 | 368 | FNCWrite(1); // Write done |
roland_tmm | 0:6069c0f2a245 | 369 | } |