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@1:b0e6c82af2ef, 2013-09-28 (annotated)
- Committer:
- liamg
- Date:
- Sat Sep 28 06:44:57 2013 +0000
- Revision:
- 1:b0e6c82af2ef
- Parent:
- 0:b5fb7b3adfe2
- Child:
- 2:e9d2346ea1bb
Version 2 with updated commentary
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 |
liamg | 0:b5fb7b3adfe2 | 2 | // Liam Goudge Sept 2013 |
liamg | 0:b5fb7b3adfe2 | 3 | |
liamg | 0:b5fb7b3adfe2 | 4 | #include "mbed.h" |
liamg | 0:b5fb7b3adfe2 | 5 | |
liamg | 0:b5fb7b3adfe2 | 6 | SPI device (p5,p6,p7); // MOSI, MISO (not used), SCLK |
liamg | 0:b5fb7b3adfe2 | 7 | DigitalOut CS(p8); // Use pin 8 as a fake Chip select |
liamg | 0:b5fb7b3adfe2 | 8 | DigitalOut ADReset(p15); // Pin 15 is reset line for AD9850 |
liamg | 0:b5fb7b3adfe2 | 9 | |
liamg | 0:b5fb7b3adfe2 | 10 | Serial pc(USBTX, USBRX); // tx, rx for debug terminal |
liamg | 0:b5fb7b3adfe2 | 11 | |
liamg | 0:b5fb7b3adfe2 | 12 | int reverseBits (int source) |
liamg | 0:b5fb7b3adfe2 | 13 | { |
liamg | 0:b5fb7b3adfe2 | 14 | // 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 | 15 | int mask=0;; |
liamg | 0:b5fb7b3adfe2 | 16 | int i=0; |
liamg | 0:b5fb7b3adfe2 | 17 | int target=0; |
liamg | 0:b5fb7b3adfe2 | 18 | int bitTarget=0x80000000; // Hard-wired for 32-bit inversion |
liamg | 0:b5fb7b3adfe2 | 19 | |
liamg | 0:b5fb7b3adfe2 | 20 | for (i=0;i<32;i++) { // ditto |
liamg | 0:b5fb7b3adfe2 | 21 | mask=1<<i; |
liamg | 0:b5fb7b3adfe2 | 22 | bitTarget=1<<(31-i); // ditto |
liamg | 0:b5fb7b3adfe2 | 23 | |
liamg | 0:b5fb7b3adfe2 | 24 | if (source & mask) |
liamg | 0:b5fb7b3adfe2 | 25 | target=target | bitTarget; |
liamg | 0:b5fb7b3adfe2 | 26 | } |
liamg | 0:b5fb7b3adfe2 | 27 | return target; |
liamg | 0:b5fb7b3adfe2 | 28 | } |
liamg | 0:b5fb7b3adfe2 | 29 | |
liamg | 0:b5fb7b3adfe2 | 30 | void writeSPI(int frq, int phase) |
liamg | 0:b5fb7b3adfe2 | 31 | { |
liamg | 0:b5fb7b3adfe2 | 32 | // Send the 40-bit packet. MBED only allows max 16-bit packets so we send 40-bits as 16, 16, 8 |
liamg | 0:b5fb7b3adfe2 | 33 | device.format(16,0); // 16-bits per packet, mode 0 (CPOL=0 CPHA=0) |
liamg | 0:b5fb7b3adfe2 | 34 | device.frequency(1000000); //SPI clock set to 1MHz |
liamg | 0:b5fb7b3adfe2 | 35 | |
liamg | 0:b5fb7b3adfe2 | 36 | wait_ms(5); |
liamg | 0:b5fb7b3adfe2 | 37 | |
liamg | 0:b5fb7b3adfe2 | 38 | // 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 | 39 | CS=1; // assert chip select (a.k.a FQ_UD frequency update input to AD9850) |
liamg | 0:b5fb7b3adfe2 | 40 | wait_ms(5); |
liamg | 0:b5fb7b3adfe2 | 41 | CS=0; |
liamg | 0:b5fb7b3adfe2 | 42 | |
liamg | 0:b5fb7b3adfe2 | 43 | device.write(frq>>16); // Write upper 16-bits first starting with bit 31 |
liamg | 0:b5fb7b3adfe2 | 44 | device.write(frq); // Now lower 16 bits starting with bit 15 |
liamg | 0:b5fb7b3adfe2 | 45 | |
liamg | 0:b5fb7b3adfe2 | 46 | device.format(8,0); // Need to reset to 8-bit data since MBED only allows max 16-bit packets. For 40-bits we do 16, 16, 8 |
liamg | 0:b5fb7b3adfe2 | 47 | device.write(phase); // This is phase and factory settings byte |
liamg | 0:b5fb7b3adfe2 | 48 | |
liamg | 0:b5fb7b3adfe2 | 49 | // Now pulse FQ_UD again to signal the end of the packet |
liamg | 0:b5fb7b3adfe2 | 50 | CS=0; |
liamg | 0:b5fb7b3adfe2 | 51 | wait_ms(5); |
liamg | 0:b5fb7b3adfe2 | 52 | CS=1; |
liamg | 0:b5fb7b3adfe2 | 53 | wait_ms(5); |
liamg | 0:b5fb7b3adfe2 | 54 | CS=0; |
liamg | 0:b5fb7b3adfe2 | 55 | } |
liamg | 0:b5fb7b3adfe2 | 56 | |
liamg | 0:b5fb7b3adfe2 | 57 | |
liamg | 0:b5fb7b3adfe2 | 58 | int main() |
liamg | 0:b5fb7b3adfe2 | 59 | { |
liamg | 0:b5fb7b3adfe2 | 60 | int targetFrq=0x147AE148; // This is desired sine wave frequency for the AD9850, here set to 10MHz |
liamg | 0:b5fb7b3adfe2 | 61 | int increment=0x346DC6; // This is a 100KHz frequency increment |
liamg | 0:b5fb7b3adfe2 | 62 | |
liamg | 0:b5fb7b3adfe2 | 63 | // Reset the AD9850. Active high logic. Minimum reset period 5 clock cycles (5/125MHz) |
liamg | 0:b5fb7b3adfe2 | 64 | ADReset=0; |
liamg | 0:b5fb7b3adfe2 | 65 | wait_ms(5); |
liamg | 0:b5fb7b3adfe2 | 66 | ADReset=1; |
liamg | 0:b5fb7b3adfe2 | 67 | wait_ms(5); |
liamg | 0:b5fb7b3adfe2 | 68 | ADReset=0; |
liamg | 0:b5fb7b3adfe2 | 69 | |
liamg | 0:b5fb7b3adfe2 | 70 | while(1) |
liamg | 0:b5fb7b3adfe2 | 71 | { |
liamg | 0:b5fb7b3adfe2 | 72 | |
liamg | 1:b0e6c82af2ef | 73 | while (targetFrq<0x28F5C28F) // up to 20MHz |
liamg | 0:b5fb7b3adfe2 | 74 | { |
liamg | 1:b0e6c82af2ef | 75 | writeSPI(reverseBits(targetFrq),0); // Don't use phase so set to zero. |
liamg | 0:b5fb7b3adfe2 | 76 | targetFrq=targetFrq+increment; |
liamg | 0:b5fb7b3adfe2 | 77 | //wait_ms(100); |
liamg | 0:b5fb7b3adfe2 | 78 | } |
liamg | 0:b5fb7b3adfe2 | 79 | |
liamg | 1:b0e6c82af2ef | 80 | while (targetFrq>0x147AE148) // down to 10MHz |
liamg | 0:b5fb7b3adfe2 | 81 | { |
liamg | 0:b5fb7b3adfe2 | 82 | writeSPI(reverseBits(targetFrq),0); |
liamg | 0:b5fb7b3adfe2 | 83 | targetFrq=targetFrq-increment; |
liamg | 0:b5fb7b3adfe2 | 84 | //wait_ms(100); |
liamg | 0:b5fb7b3adfe2 | 85 | } |
liamg | 0:b5fb7b3adfe2 | 86 | |
liamg | 0:b5fb7b3adfe2 | 87 | } |
liamg | 0:b5fb7b3adfe2 | 88 | |
liamg | 0:b5fb7b3adfe2 | 89 | |
liamg | 0:b5fb7b3adfe2 | 90 | } |