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
AD9850.cpp@2:602f7589c53e, 2017-11-21 (annotated)
- Committer:
- roland_tmm
- Date:
- Tue Nov 21 19:18:25 2017 +0000
- Revision:
- 2:602f7589c53e
- Parent:
- 1:9dcccb399f0b
Edited comments/description;
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
roland_tmm | 0:6069c0f2a245 | 1 | /****************************************************************************************************************** |
roland_tmm | 2:602f7589c53e | 2 | * AD9850 library for AD9850 |
roland_tmm | 0:6069c0f2a245 | 3 | * Created 11/21/2017 |
roland_tmm | 0:6069c0f2a245 | 4 | * Roland Pelayo |
roland_tmm | 0:6069c0f2a245 | 5 | * |
roland_tmm | 0:6069c0f2a245 | 6 | * Use this library freely |
roland_tmm | 0:6069c0f2a245 | 7 | * |
roland_tmm | 0:6069c0f2a245 | 8 | * Hardware connections : |
roland_tmm | 0:6069c0f2a245 | 9 | * W_CLK -> any pin |
roland_tmm | 0:6069c0f2a245 | 10 | * FQ_UD -> any pin |
roland_tmm | 0:6069c0f2a245 | 11 | * DATA/D7 -> any pin |
roland_tmm | 0:6069c0f2a245 | 12 | * RESET -> any pin |
roland_tmm | 0:6069c0f2a245 | 13 | * |
roland_tmm | 0:6069c0f2a245 | 14 | * Functions : |
roland_tmm | 0:6069c0f2a245 | 15 | * dds.begin(W_CLK pin, FQ_UD pin, DATA pin, RESET pin); Initialize the output pins and master reset the AD9850 |
roland_tmm | 0:6069c0f2a245 | 16 | * dds.calibrate(frequency); Compensation of crystal oscillator frequency |
roland_tmm | 0:6069c0f2a245 | 17 | * dds.setfreq(frequency,phase); frequency in Hz, phase coded on 5 bits |
roland_tmm | 0:6069c0f2a245 | 18 | * dds.down(); power down mode reducing the dissipated power from 380mW to 30mW @5V |
roland_tmm | 0:6069c0f2a245 | 19 | * dds.up(); wake-up the AD9850 |
roland_tmm | 0:6069c0f2a245 | 20 | * |
roland_tmm | 0:6069c0f2a245 | 21 | * AD9850 datasheet at http://www.analog.com/static/imported-files/data_sheets/AD9850.pdf |
roland_tmm | 0:6069c0f2a245 | 22 | * |
roland_tmm | 0:6069c0f2a245 | 23 | *****************************************************************************************************************/ |
roland_tmm | 0:6069c0f2a245 | 24 | |
roland_tmm | 0:6069c0f2a245 | 25 | #include "AD9850.h" |
roland_tmm | 0:6069c0f2a245 | 26 | #include "mbed.h" |
roland_tmm | 0:6069c0f2a245 | 27 | |
roland_tmm | 0:6069c0f2a245 | 28 | #define W_CLK PB_10 |
roland_tmm | 0:6069c0f2a245 | 29 | #define FQ_UD PB_11 |
roland_tmm | 0:6069c0f2a245 | 30 | #define DATA PB_1 |
roland_tmm | 0:6069c0f2a245 | 31 | #define RESET PB_0 |
roland_tmm | 0:6069c0f2a245 | 32 | |
roland_tmm | 0:6069c0f2a245 | 33 | SPI SPI_dev2(DATA, PB_8, W_CLK); |
roland_tmm | 0:6069c0f2a245 | 34 | |
roland_tmm | 0:6069c0f2a245 | 35 | DigitalOut wclk(W_CLK); |
roland_tmm | 0:6069c0f2a245 | 36 | DigitalOut fq_ud(FQ_UD); |
roland_tmm | 0:6069c0f2a245 | 37 | DigitalOut dat(DATA); |
roland_tmm | 0:6069c0f2a245 | 38 | DigitalOut res(RESET); |
roland_tmm | 0:6069c0f2a245 | 39 | |
roland_tmm | 0:6069c0f2a245 | 40 | AD9850::AD9850() { |
roland_tmm | 0:6069c0f2a245 | 41 | |
roland_tmm | 0:6069c0f2a245 | 42 | } |
roland_tmm | 0:6069c0f2a245 | 43 | |
roland_tmm | 0:6069c0f2a245 | 44 | void AD9850::Begin() { |
roland_tmm | 1:9dcccb399f0b | 45 | SPI_dev2.format(16,0); |
roland_tmm | 0:6069c0f2a245 | 46 | deltaphase = 0; |
roland_tmm | 0:6069c0f2a245 | 47 | phase = 0; |
roland_tmm | 0:6069c0f2a245 | 48 | calibFreq = 125000000; |
roland_tmm | 0:6069c0f2a245 | 49 | begin_priv(); |
roland_tmm | 0:6069c0f2a245 | 50 | } |
roland_tmm | 0:6069c0f2a245 | 51 | |
roland_tmm | 0:6069c0f2a245 | 52 | void AD9850::begin_priv() { |
roland_tmm | 0:6069c0f2a245 | 53 | |
roland_tmm | 1:9dcccb399f0b | 54 | res = 0; |
roland_tmm | 1:9dcccb399f0b | 55 | wait_us(5); |
roland_tmm | 0:6069c0f2a245 | 56 | res = 1; |
roland_tmm | 1:9dcccb399f0b | 57 | wait_us(5); |
roland_tmm | 0:6069c0f2a245 | 58 | res = 0; |
roland_tmm | 0:6069c0f2a245 | 59 | |
roland_tmm | 1:9dcccb399f0b | 60 | wclk = 0; |
roland_tmm | 1:9dcccb399f0b | 61 | wait_us(5); |
roland_tmm | 0:6069c0f2a245 | 62 | wclk = 1; |
roland_tmm | 1:9dcccb399f0b | 63 | wait_us(5); |
roland_tmm | 0:6069c0f2a245 | 64 | wclk = 0; |
roland_tmm | 0:6069c0f2a245 | 65 | |
roland_tmm | 1:9dcccb399f0b | 66 | fq_ud = 0; |
roland_tmm | 1:9dcccb399f0b | 67 | wait_us(5); |
roland_tmm | 0:6069c0f2a245 | 68 | fq_ud = 1; |
roland_tmm | 1:9dcccb399f0b | 69 | wait_us(5); |
roland_tmm | 0:6069c0f2a245 | 70 | fq_ud = 0; |
roland_tmm | 0:6069c0f2a245 | 71 | |
roland_tmm | 0:6069c0f2a245 | 72 | } |
roland_tmm | 0:6069c0f2a245 | 73 | |
roland_tmm | 0:6069c0f2a245 | 74 | void AD9850::update() { |
roland_tmm | 0:6069c0f2a245 | 75 | uint32_t d,p; |
roland_tmm | 0:6069c0f2a245 | 76 | for (int i=0; i<4; i++, deltaphase>>=8) { |
roland_tmm | 1:9dcccb399f0b | 77 | d = ReverseBits(deltaphase); |
roland_tmm | 1:9dcccb399f0b | 78 | SPI_dev2.write((d>>16) & 0x000000FF); |
roland_tmm | 1:9dcccb399f0b | 79 | SPI_dev2.write(d & 0x000000FF); |
roland_tmm | 0:6069c0f2a245 | 80 | // shiftOut(DATA, W_CLK, LSBFIRST, deltaphase & 0xFF); |
roland_tmm | 0:6069c0f2a245 | 81 | } |
roland_tmm | 1:9dcccb399f0b | 82 | p = ReverseBits(phase); |
roland_tmm | 1:9dcccb399f0b | 83 | SPI_dev2.write((p>>16) & 0x000000FF); |
roland_tmm | 1:9dcccb399f0b | 84 | SPI_dev2.write(p & 0x000000FF); |
roland_tmm | 0:6069c0f2a245 | 85 | //shiftOut(DATA, W_CLK, LSBFIRST, phase & 0xFF); |
roland_tmm | 1:9dcccb399f0b | 86 | fq_ud = 0; |
roland_tmm | 1:9dcccb399f0b | 87 | wait_us(5); |
roland_tmm | 0:6069c0f2a245 | 88 | fq_ud = 1; |
roland_tmm | 1:9dcccb399f0b | 89 | wait_us(5); |
roland_tmm | 0:6069c0f2a245 | 90 | fq_ud = 0; |
roland_tmm | 0:6069c0f2a245 | 91 | } |
roland_tmm | 0:6069c0f2a245 | 92 | |
roland_tmm | 0:6069c0f2a245 | 93 | |
roland_tmm | 0:6069c0f2a245 | 94 | void AD9850::SetDDSFrequency(double f, uint8_t p) { |
roland_tmm | 0:6069c0f2a245 | 95 | deltaphase = f * 4294967296.0 / calibFreq; |
roland_tmm | 0:6069c0f2a245 | 96 | phase = p << 3; |
roland_tmm | 0:6069c0f2a245 | 97 | update(); |
roland_tmm | 0:6069c0f2a245 | 98 | } |
roland_tmm | 0:6069c0f2a245 | 99 | |
roland_tmm | 0:6069c0f2a245 | 100 | |
roland_tmm | 0:6069c0f2a245 | 101 | void AD9850::down() { |
roland_tmm | 1:9dcccb399f0b | 102 | fq_ud = 0; |
roland_tmm | 1:9dcccb399f0b | 103 | wait_us(5); |
roland_tmm | 0:6069c0f2a245 | 104 | fq_ud = 1; |
roland_tmm | 1:9dcccb399f0b | 105 | wait_us(5); |
roland_tmm | 0:6069c0f2a245 | 106 | fq_ud = 0; |
roland_tmm | 1:9dcccb399f0b | 107 | SPI_dev2.write((ReverseBits(0x00000004))>>16); |
roland_tmm | 1:9dcccb399f0b | 108 | SPI_dev2.write(ReverseBits(0x00000004)); |
roland_tmm | 0:6069c0f2a245 | 109 | //shiftOut(DATA, W_CLK, LSBFIRST, 0x04); |
roland_tmm | 1:9dcccb399f0b | 110 | fq_ud = 0; |
roland_tmm | 1:9dcccb399f0b | 111 | wait_us(5); |
roland_tmm | 0:6069c0f2a245 | 112 | fq_ud = 1; |
roland_tmm | 1:9dcccb399f0b | 113 | wait_us(5); |
roland_tmm | 0:6069c0f2a245 | 114 | fq_ud = 0; |
roland_tmm | 0:6069c0f2a245 | 115 | } |
roland_tmm | 0:6069c0f2a245 | 116 | |
roland_tmm | 0:6069c0f2a245 | 117 | |
roland_tmm | 0:6069c0f2a245 | 118 | void AD9850::up() { |
roland_tmm | 0:6069c0f2a245 | 119 | update(); |
roland_tmm | 0:6069c0f2a245 | 120 | } |
roland_tmm | 0:6069c0f2a245 | 121 | |
roland_tmm | 0:6069c0f2a245 | 122 | |
roland_tmm | 0:6069c0f2a245 | 123 | void AD9850::CalibrateDDS(double TrimFreq) |
roland_tmm | 0:6069c0f2a245 | 124 | { |
roland_tmm | 0:6069c0f2a245 | 125 | calibFreq = TrimFreq; |
roland_tmm | 0:6069c0f2a245 | 126 | } |
roland_tmm | 0:6069c0f2a245 | 127 | |
roland_tmm | 1:9dcccb399f0b | 128 | int AD9850::ReverseBits(int value) |
roland_tmm | 1:9dcccb399f0b | 129 | { |
roland_tmm | 1:9dcccb399f0b | 130 | // Unfortunately need to invert bit order of the desired frequency setting since MBED only allows for MSB first from SPI. We need LSB first for AD9850 |
roland_tmm | 1:9dcccb399f0b | 131 | int mask=0;; |
roland_tmm | 1:9dcccb399f0b | 132 | int i=0; |
roland_tmm | 1:9dcccb399f0b | 133 | int target=0; |
roland_tmm | 1:9dcccb399f0b | 134 | int bitTarget=0x80000000; // Hard-wired for 32-bit inversion |
roland_tmm | 1:9dcccb399f0b | 135 | |
roland_tmm | 1:9dcccb399f0b | 136 | for (i=0;i<32;i++) { // ditto |
roland_tmm | 1:9dcccb399f0b | 137 | mask=1<<i; |
roland_tmm | 1:9dcccb399f0b | 138 | bitTarget=1<<(31-i); // ditto |
roland_tmm | 1:9dcccb399f0b | 139 | |
roland_tmm | 1:9dcccb399f0b | 140 | if(value & mask) |
roland_tmm | 1:9dcccb399f0b | 141 | target=target | bitTarget; |
roland_tmm | 1:9dcccb399f0b | 142 | } |
roland_tmm | 1:9dcccb399f0b | 143 | return target; |
roland_tmm | 1:9dcccb399f0b | 144 | } |