Function generator code modified to work on the Freescale KL25Z
Fork of AD9850 function generator SPI driver by
This is an update to the original AD9850 SPI driver produced by Liam Goudge.
The main changes are to assign the appropriate pins and to send the 40-bit AD9850 programming word as five 8-bit packets. This is necessary because the KL25Z only supports 8-bit SPI transfers.
main.cpp@3:a643b6a454aa, 2013-10-24 (annotated)
- Committer:
- ptamike
- Date:
- Thu Oct 24 12:35:18 2013 +0000
- Revision:
- 3:a643b6a454aa
- Parent:
- 2:e9d2346ea1bb
Corrected pin numbers in comments
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
liamg | 0:b5fb7b3adfe2 | 1 | // MBED driver for AD9850 digital synthesizer using hacked SPI interface |
ptamike | 2:e9d2346ea1bb | 2 | // Original code by Liam Goudge Sept 2013 |
ptamike | 2:e9d2346ea1bb | 3 | // Modified for KL25Z by Mike Richards Oct 2013 |
liamg | 0:b5fb7b3adfe2 | 4 | |
liamg | 0:b5fb7b3adfe2 | 5 | #include "mbed.h" |
liamg | 0:b5fb7b3adfe2 | 6 | |
ptamike | 2:e9d2346ea1bb | 7 | |
ptamike | 2:e9d2346ea1bb | 8 | SPI device (PTD2, PTD3, PTD1); // Set the KL25Z SPI pins |
ptamike | 3:a643b6a454aa | 9 | DigitalOut CS(PTD0); // Use pin PTD0 as a fake Chip select |
ptamike | 3:a643b6a454aa | 10 | DigitalOut ADReset(PTA13); // Use Pin PTA13 as the reset line for AD9850 |
ptamike | 2:e9d2346ea1bb | 11 | |
liamg | 0:b5fb7b3adfe2 | 12 | |
liamg | 0:b5fb7b3adfe2 | 13 | Serial pc(USBTX, USBRX); // tx, rx for debug terminal |
liamg | 0:b5fb7b3adfe2 | 14 | |
liamg | 0:b5fb7b3adfe2 | 15 | int reverseBits (int source) |
liamg | 0:b5fb7b3adfe2 | 16 | { |
liamg | 0:b5fb7b3adfe2 | 17 | // 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 |
liamg | 0:b5fb7b3adfe2 | 18 | int mask=0;; |
liamg | 0:b5fb7b3adfe2 | 19 | int i=0; |
liamg | 0:b5fb7b3adfe2 | 20 | int target=0; |
liamg | 0:b5fb7b3adfe2 | 21 | int bitTarget=0x80000000; // Hard-wired for 32-bit inversion |
liamg | 0:b5fb7b3adfe2 | 22 | |
liamg | 0:b5fb7b3adfe2 | 23 | for (i=0;i<32;i++) { // ditto |
liamg | 0:b5fb7b3adfe2 | 24 | mask=1<<i; |
liamg | 0:b5fb7b3adfe2 | 25 | bitTarget=1<<(31-i); // ditto |
liamg | 0:b5fb7b3adfe2 | 26 | |
liamg | 0:b5fb7b3adfe2 | 27 | if (source & mask) |
liamg | 0:b5fb7b3adfe2 | 28 | target=target | bitTarget; |
liamg | 0:b5fb7b3adfe2 | 29 | } |
liamg | 0:b5fb7b3adfe2 | 30 | return target; |
liamg | 0:b5fb7b3adfe2 | 31 | } |
liamg | 0:b5fb7b3adfe2 | 32 | |
liamg | 0:b5fb7b3adfe2 | 33 | void writeSPI(int frq, int phase) |
liamg | 0:b5fb7b3adfe2 | 34 | { |
ptamike | 2:e9d2346ea1bb | 35 | // Send the 40-bit packet. NB: KL25Z only supports 8-bit SPI so send five 8-bit packets |
ptamike | 2:e9d2346ea1bb | 36 | |
ptamike | 2:e9d2346ea1bb | 37 | device.format(8,0); // 8-bits per packet, mode 0 (CPOL=0 CPHA=0) |
liamg | 0:b5fb7b3adfe2 | 38 | device.frequency(1000000); //SPI clock set to 1MHz |
liamg | 0:b5fb7b3adfe2 | 39 | |
ptamike | 2:e9d2346ea1bb | 40 | wait_ms(1); |
liamg | 0:b5fb7b3adfe2 | 41 | |
liamg | 0:b5fb7b3adfe2 | 42 | // 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 |
liamg | 0:b5fb7b3adfe2 | 43 | CS=1; // assert chip select (a.k.a FQ_UD frequency update input to AD9850) |
ptamike | 2:e9d2346ea1bb | 44 | wait_ms(1); |
liamg | 0:b5fb7b3adfe2 | 45 | CS=0; |
liamg | 0:b5fb7b3adfe2 | 46 | |
ptamike | 2:e9d2346ea1bb | 47 | device.write(frq>>24); // Write upper 8-bits |
ptamike | 2:e9d2346ea1bb | 48 | device.write(frq>>16); |
ptamike | 2:e9d2346ea1bb | 49 | device.write(frq>>8); |
ptamike | 2:e9d2346ea1bb | 50 | device.write(frq); // Now the last 8 bits |
liamg | 0:b5fb7b3adfe2 | 51 | device.write(phase); // This is phase and factory settings byte |
liamg | 0:b5fb7b3adfe2 | 52 | |
ptamike | 2:e9d2346ea1bb | 53 | // Now pulse FQ_UD again to load the word into the DDS |
liamg | 0:b5fb7b3adfe2 | 54 | CS=0; |
ptamike | 2:e9d2346ea1bb | 55 | wait_ms(1); |
liamg | 0:b5fb7b3adfe2 | 56 | CS=1; |
ptamike | 2:e9d2346ea1bb | 57 | wait_ms(1); |
liamg | 0:b5fb7b3adfe2 | 58 | CS=0; |
liamg | 0:b5fb7b3adfe2 | 59 | } |
liamg | 0:b5fb7b3adfe2 | 60 | |
liamg | 0:b5fb7b3adfe2 | 61 | |
liamg | 0:b5fb7b3adfe2 | 62 | int main() |
liamg | 0:b5fb7b3adfe2 | 63 | { |
ptamike | 2:e9d2346ea1bb | 64 | // This routine produces a continuous frequency sweep |
ptamike | 2:e9d2346ea1bb | 65 | int targetFrq=0x147AE148; // Frequency word = ([Desired freq in MHz] * 34.3597384) |
ptamike | 2:e9d2346ea1bb | 66 | int increment=0xD6B; //100Hz step |
ptamike | 2:e9d2346ea1bb | 67 | |
liamg | 0:b5fb7b3adfe2 | 68 | // Reset the AD9850. Active high logic. Minimum reset period 5 clock cycles (5/125MHz) |
liamg | 0:b5fb7b3adfe2 | 69 | ADReset=0; |
liamg | 0:b5fb7b3adfe2 | 70 | wait_ms(5); |
liamg | 0:b5fb7b3adfe2 | 71 | ADReset=1; |
liamg | 0:b5fb7b3adfe2 | 72 | wait_ms(5); |
liamg | 0:b5fb7b3adfe2 | 73 | ADReset=0; |
liamg | 0:b5fb7b3adfe2 | 74 | |
liamg | 0:b5fb7b3adfe2 | 75 | while(1) |
liamg | 0:b5fb7b3adfe2 | 76 | { |
liamg | 0:b5fb7b3adfe2 | 77 | |
ptamike | 2:e9d2346ea1bb | 78 | |
ptamike | 2:e9d2346ea1bb | 79 | |
ptamike | 2:e9d2346ea1bb | 80 | while (targetFrq<0x148bFFFF) // up to 10.001MHz |
liamg | 0:b5fb7b3adfe2 | 81 | { |
liamg | 1:b0e6c82af2ef | 82 | writeSPI(reverseBits(targetFrq),0); // Don't use phase so set to zero. |
liamg | 0:b5fb7b3adfe2 | 83 | targetFrq=targetFrq+increment; |
ptamike | 2:e9d2346ea1bb | 84 | //wait_ms(200); |
liamg | 0:b5fb7b3adfe2 | 85 | } |
liamg | 0:b5fb7b3adfe2 | 86 | |
liamg | 1:b0e6c82af2ef | 87 | while (targetFrq>0x147AE148) // down to 10MHz |
liamg | 0:b5fb7b3adfe2 | 88 | { |
liamg | 0:b5fb7b3adfe2 | 89 | writeSPI(reverseBits(targetFrq),0); |
liamg | 0:b5fb7b3adfe2 | 90 | targetFrq=targetFrq-increment; |
ptamike | 2:e9d2346ea1bb | 91 | //wait_ms(200); |
liamg | 0:b5fb7b3adfe2 | 92 | } |
liamg | 0:b5fb7b3adfe2 | 93 | |
liamg | 0:b5fb7b3adfe2 | 94 | } |
liamg | 0:b5fb7b3adfe2 | 95 | |
liamg | 0:b5fb7b3adfe2 | 96 | |
liamg | 0:b5fb7b3adfe2 | 97 | } |