Simple driver for programming the Analogue Devices AD8951 Direct Digital Synthesizer using the cheap KL25Z board
main.cpp@0:21d4a8e3d6be, 2013-10-26 (annotated)
- Committer:
- ptamike
- Date:
- Sat Oct 26 18:22:46 2013 +0000
- Revision:
- 0:21d4a8e3d6be
Tidied up code and comments
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
ptamike | 0:21d4a8e3d6be | 1 | // MBED driver for AD9851 digital synthesizer using hacked SPI interface |
ptamike | 0:21d4a8e3d6be | 2 | // Original code for AD9850 by Liam Goudge Sept 2013 |
ptamike | 0:21d4a8e3d6be | 3 | // Modified for AD9851 and KL25Z by Mike Richards Oct 2013 |
ptamike | 0:21d4a8e3d6be | 4 | |
ptamike | 0:21d4a8e3d6be | 5 | #include "mbed.h" |
ptamike | 0:21d4a8e3d6be | 6 | |
ptamike | 0:21d4a8e3d6be | 7 | |
ptamike | 0:21d4a8e3d6be | 8 | SPI device (PTD2, PTD3, PTD1); // Set the KL25Z SPI pins |
ptamike | 0:21d4a8e3d6be | 9 | DigitalOut CS(PTD0); // Use pin PTD0 as a fake Chip select (AD9851's FQ_UD line) |
ptamike | 0:21d4a8e3d6be | 10 | DigitalOut ADReset(PTA13); // Use Pin PTA13 as the reset line for AD9851 |
ptamike | 0:21d4a8e3d6be | 11 | int targetFrq; // 32-bit frequency word for the AD9851 |
ptamike | 0:21d4a8e3d6be | 12 | int phase; // Phase and multiplier word for AD9851 |
ptamike | 0:21d4a8e3d6be | 13 | |
ptamike | 0:21d4a8e3d6be | 14 | Serial pc(USBTX, USBRX); // tx, rx for debug terminal |
ptamike | 0:21d4a8e3d6be | 15 | |
ptamike | 0:21d4a8e3d6be | 16 | int reverseBits (int source) |
ptamike | 0:21d4a8e3d6be | 17 | { |
ptamike | 0:21d4a8e3d6be | 18 | // 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 AD9851 |
ptamike | 0:21d4a8e3d6be | 19 | int mask=0;; |
ptamike | 0:21d4a8e3d6be | 20 | int i=0; |
ptamike | 0:21d4a8e3d6be | 21 | int target=0; |
ptamike | 0:21d4a8e3d6be | 22 | int bitTarget=0x80000000; // Hard-wired for 32-bit inversion |
ptamike | 0:21d4a8e3d6be | 23 | |
ptamike | 0:21d4a8e3d6be | 24 | for (i=0;i<32;i++) { // ditto |
ptamike | 0:21d4a8e3d6be | 25 | mask=1<<i; |
ptamike | 0:21d4a8e3d6be | 26 | bitTarget=1<<(31-i); // ditto |
ptamike | 0:21d4a8e3d6be | 27 | |
ptamike | 0:21d4a8e3d6be | 28 | if (source & mask) |
ptamike | 0:21d4a8e3d6be | 29 | target=target | bitTarget; |
ptamike | 0:21d4a8e3d6be | 30 | } |
ptamike | 0:21d4a8e3d6be | 31 | return target; |
ptamike | 0:21d4a8e3d6be | 32 | } |
ptamike | 0:21d4a8e3d6be | 33 | |
ptamike | 0:21d4a8e3d6be | 34 | void writeSPI(int frq, int phase) |
ptamike | 0:21d4a8e3d6be | 35 | { |
ptamike | 0:21d4a8e3d6be | 36 | // Send the 40-bit packet. NB: KL25Z only supports 8-bit SPI so send five 8-bit packets |
ptamike | 0:21d4a8e3d6be | 37 | |
ptamike | 0:21d4a8e3d6be | 38 | device.format(8,0); // 8-bits per packet, mode 0 (CPOL=0 CPHA=0) |
ptamike | 0:21d4a8e3d6be | 39 | device.frequency(1000000); //SPI clock set to 1MHz |
ptamike | 0:21d4a8e3d6be | 40 | |
ptamike | 0:21d4a8e3d6be | 41 | wait_ms(1); |
ptamike | 0:21d4a8e3d6be | 42 | |
ptamike | 0:21d4a8e3d6be | 43 | // First do chip select. Need to use a GPIO to fake the chip select since MBED doesn't allow to set positive logic CS signal |
ptamike | 0:21d4a8e3d6be | 44 | CS=1; // assert chip select (a.k.a FQ_UD frequency update input to AD9851) |
ptamike | 0:21d4a8e3d6be | 45 | wait_ms(1); |
ptamike | 0:21d4a8e3d6be | 46 | CS=0; |
ptamike | 0:21d4a8e3d6be | 47 | |
ptamike | 0:21d4a8e3d6be | 48 | // Write 5 x 8-bit packets for the frequency word |
ptamike | 0:21d4a8e3d6be | 49 | device.write(frq>>24); // Packet 1 |
ptamike | 0:21d4a8e3d6be | 50 | device.write(frq>>16); // Packet 2 |
ptamike | 0:21d4a8e3d6be | 51 | device.write(frq>>8); // Packet 3 |
ptamike | 0:21d4a8e3d6be | 52 | device.write(frq); // Packet 4 |
ptamike | 0:21d4a8e3d6be | 53 | device.write(phase); // Packet 5 - Finish with the phase, multiplier and factory settings byte |
ptamike | 0:21d4a8e3d6be | 54 | |
ptamike | 0:21d4a8e3d6be | 55 | // Now pulse FQ_UD again to load the word into the DDS |
ptamike | 0:21d4a8e3d6be | 56 | CS=0; |
ptamike | 0:21d4a8e3d6be | 57 | wait_ms(1); |
ptamike | 0:21d4a8e3d6be | 58 | CS=1; |
ptamike | 0:21d4a8e3d6be | 59 | wait_ms(1); |
ptamike | 0:21d4a8e3d6be | 60 | CS=0; |
ptamike | 0:21d4a8e3d6be | 61 | } |
ptamike | 0:21d4a8e3d6be | 62 | |
ptamike | 0:21d4a8e3d6be | 63 | |
ptamike | 0:21d4a8e3d6be | 64 | int main() |
ptamike | 0:21d4a8e3d6be | 65 | { |
ptamike | 0:21d4a8e3d6be | 66 | |
ptamike | 0:21d4a8e3d6be | 67 | |
ptamike | 0:21d4a8e3d6be | 68 | int DesFrq = 5000000; // Set the desired output frequency in Hz |
ptamike | 0:21d4a8e3d6be | 69 | float Mult = 23.86093; // Multiplier for boards using a 30MHz clock oscillator and 6x multiplier |
ptamike | 0:21d4a8e3d6be | 70 | targetFrq= DesFrq * Mult ; // targetFrq is the 32-bit frequency word for the AD9851 |
ptamike | 0:21d4a8e3d6be | 71 | phase = 0x80; // Set the 6x clock multiplier for systems with 30MHz reference oscillator. |
ptamike | 0:21d4a8e3d6be | 72 | |
ptamike | 0:21d4a8e3d6be | 73 | // Reset the AD9851. Active high logic. Minimum reset period 5 clock cycles |
ptamike | 0:21d4a8e3d6be | 74 | ADReset=0; |
ptamike | 0:21d4a8e3d6be | 75 | wait_ms(5); |
ptamike | 0:21d4a8e3d6be | 76 | ADReset=1; |
ptamike | 0:21d4a8e3d6be | 77 | wait_ms(5); |
ptamike | 0:21d4a8e3d6be | 78 | ADReset=0; |
ptamike | 0:21d4a8e3d6be | 79 | |
ptamike | 0:21d4a8e3d6be | 80 | |
ptamike | 0:21d4a8e3d6be | 81 | while(1) |
ptamike | 0:21d4a8e3d6be | 82 | { |
ptamike | 0:21d4a8e3d6be | 83 | |
ptamike | 0:21d4a8e3d6be | 84 | writeSPI(reverseBits(targetFrq),phase); // Transfer the frequency settings to the AD9851 |
ptamike | 0:21d4a8e3d6be | 85 | |
ptamike | 0:21d4a8e3d6be | 86 | |
ptamike | 0:21d4a8e3d6be | 87 | |
ptamike | 0:21d4a8e3d6be | 88 | } |
ptamike | 0:21d4a8e3d6be | 89 | |
ptamike | 0:21d4a8e3d6be | 90 | |
ptamike | 0:21d4a8e3d6be | 91 | } |