Square and sine wave generator ranging from 0 Hz to 62.5MHz.
Free for amateur home use only
Seeing as there is very little dspic30,33 and pic24 assembler out there on the internet I thought I would publish my latest project as a help to others struggling to get going. I like assembler and that is why I program in it. I will be using the prototype of this function generator as a tool and have no need to build another more polished version. My pcb has a couple of jumpers on the back where I made mistakes ( corrected on the pcb drawing ) I will not be making a new one . The 3.3V regulator is the exception to this . Two new holes and a bit of wire. The diptrace files use a custom library , but the components and their patterns should be in the schematic file. The slot for the display is a little messy. I could not find my hole punch and milling with a pillar drill does not work well .
After seeing an AD9850 module on eBay I bought one just to play with and ended up making the function generator I needed for testing.
The AD9850 can oscillate between 0 and 62,500,000 Hz in 0.03 Hz steps with an accuracy of 15ppm.
Data sheet at www.analog.com/static/imported-files/data_sheets/AD9850.pdf
The module includes crystal and differential amp for square wave output . There are complementary out puts too, although my design does not use these. The module can out put 10 to 20 mAmps thus no output amp is needed for small signal injection of pieces of equipment being tested.
I was also in the need of a dspic project so I melded the two into one. I had also been experimenting with LCD displays , so I incorporated this too. A serial control port also seemed a good addition. The idea being to be able to adjust the function generator from the pc or be stand alone.
I used the DSPIC33fj12gp201 for the processor because that is what I had to hand.
The breadboard prototype used a max2323 for RS232 to 3v serial communication for the dspic uart input, but another spot on eBay was the Prolific PL2303HX usb to serial module . Windows 7 has drivers built in for this. This would allow the function generator to be plugged into a pc without the need for a usb to RS232 adaptor. After a bit of pondering about a suitable PSU I realised that the Prolific module supplied 5v from the usb port on its serial pins. After a quick measure it became apparent that this is a direct connection to the USB 5v rail thus capable of supplying 500mA . There is also a 3.3v supply but I don’t know what current this can supply, so I stuck to the 5V rail. The output voltage on the RX pin is 3v at maximum which fits in with the 3.3v supply to the dspic nicely, alleviating the need to limit the input voltage to the dspic. Also if I wish to use the function generator without a pc connection all I need is a USB charger that plugs in the mains. In this state I would need to be able to set the frequency so I included a couple of encoded rotary switches to facilitate this.
The LCD I have will only work off 5V but the 3.3V signals from the dspic are still high enough to drive the data and control lines. There are no outputs from the LCD module used so again no voltage clamping needed here. There is no checking of ready signals from the LCD as this takes 1 more I/O for R/W and would need voltage clamping for data in on D7. Instead the software assumes a worst case scenario with the timing and just sends the data. The write pin being tied to the 0V rail. Thus the LCD uses 4 data pins (D4-7 RA0-3), 1 RS pin (RB1) and 1 E pin (RB0). C3 is a 47uF cap across the supply.
U1 is the control signals to the LCD . H2 and H3 are the data lines to the LCD.
The 3.3V supply is derived from the 5V with the use of a LD1117 3.3v regulaor This supplies the dspic ,DDS and current source.
The DDS module runs off 3-5V . It is considerably cooler running off 3.3V so this is what I use. To save I/O this is programmed in serial mode. The DDS module needs D2 connected to 0V and D1 and D0 tied to the 3.3V rail to make the device start up in serial mode. Serial data is then loaded into D7 (RB4) (connected to the DATA pin on the module) with the use of W_CLK (RA4) and FQ_UD(RB7) control signals. FQ_UD is pulled low to say data is coming and W_CLK is strobed high to clock the data on D7 in. There are 40 bits to strobe in. 32 data bits and 8 control bits . The minimum timing of these signals is much faster than the dspic can supply so there are no timing issues as with the LCD.
The DDS can be programmed in 2^32 steps for the 0 to 62,500,000 Mhz range.
125,000,000/2^32 =34.359ish per Hz. i.e. program the module with 34359 will produce a 1KHz signal . 4294967295 will do 62.5MHz . 1 will do 0.0291 Hz.
The outputs of the DDS are via H4 (square wave . pot on DDS for M:S ratio) and H1 (sine wave)
The USB to serial is connected to the dspic uart . The Rx of the adaptor is the output to the PC . i.e.data comes from the uart (RB14) into the adaptor and out of the USB. The USB receives from the PC and sends the data out of the Tx pin into the uart(RB8) . Thus the USB adaptor is marked up viewing as the USB as the output . These signals are at 0-3V. All inputs are echoed but only valid characters are used. The function generator is programmed to respond with the value set and then “ok<CR><LF>“ at the reception of a valid frequency setting.
U2 is the USB to Serial connection which contains the PSU. Be sure to connect this to the correct pads. Due to the pins being a bit short, I removed them and used a 0.1 pitch header to solder the USB module to the board.
The quadrature encoded rotary switches are not connected to the dspic quadrature decoder as there are not enough input pins . Instead the switches are read using one pin in analogue mode (RB15). A current source and 5 resistors are used to read the switches. Each switch can short out one of the resistors and affect the voltage signal to the ADC. Each resistor is a doubling of the previous allowing all 16 possible switch positions to be read, although in reality only one switch will be in use at any one time. These switches are connected to U4 . The 3 quadrature pins are connected to pins 1-3 for the first switch and 4-6 for the second switch . Data sheet.
A supply voltage , in this case 3.3V, is fed through two diodes, D1 and D5, to 0v vai a 3.3k resistor. A small current flow is needed to generate the 1.3V voltage drop. This is fed to the base of Q1. This will cause Q1 to bring its emitter to 0.65 volts below the supply. This known fixed voltage across POT1 will give a known fixed current through Q1 and out of its collector. V=IR if POT1 is 650R and V=0.65 then 0.65/650=1mA current flow 99.5% of which will be out of the collector. This will be constant regardless of the value of the resistance from the collector to 0V ( within certain limits in this case about 2k for 1mA). If the supply voltage was higher than the supply to the dspic then it would be possible to generate a too high a voltage on the ADC input pin thus damaging the chip. Using the 3.3V supply stops this from happening.
Ideally we want with all switches open a value of 496 in the 10bit ADC . That is 0111110000. Bits 5-8 being the switches. The bottom 5 bits want to be half way between 0 and 31 thus giving +/- 2.5 bits for error. i.e. tolerance in the resistors. In this case 3%, so I use 1% tolerance resistors. You could just measure them and make sure they are 1:2:4:8:16 ratio . This is what R9 is for. With out this we would have 0-5 bits for error. At the other end of the scale all switches closed would be 0000010000 = 16.
In the software this is shifted right 5 bits to give 000000xxxx and then inverted. No switches closed = 0000 . R8 shorted =0001=1 , R6 shorted = 0010=2 , R5 shorted = 0100=4, R4 shorted = 1000 = 8. Any combination is measurable i.e. all shorted = 1111 =15. The value of POT1 will have to be adjusted to generate the correct voltage at the collector of Q1. The ADC is referenced to the supply of 3.3V. Thus 496/1024*3.3 = 1.5984375V, voltage when all 4 switches are open. 16/1024*3=0.0515625V when all closed. 1.5984375/1937.5=0.825mA thus POT1 = 0.65/0.825=788R.
The rotary switches normally sit with both contacts open , thus at rest the ADC routine will return 0. When one of the switches rotated one of its contacts will close . Which one depends on the direction. Rotary switch 1 will go from 0-1 or 0-2 as it will short out R8 or R6. 0-1=value down, 0-2=value up . Rotary switch 2 shorts R5 or R4 giving 0-4=cursor left, 0-8=cursor right. As the switch continues to rotate it will short both resistors , then release the first then both back to 0, but we only need to know the first one made. The software then just scans for 0 before looking for the next transition. Only 5 of the possible 16 values are valid. I have fitted a 270nF capacitor across the analogue input and 0V to help stop noise. Occasionally my rotary switches stop at a non 0 value , but this is my switches your's may well work better. I bought the cheapest I could find on ebay.
C2 (47uF) is a decoupling capacitor for the 3.3V supply rail. R2 (10k) is to pull the dspic Reset high. C1(10uF) is the dspic core voltage decoupling capacitor as per the datasheet.
Due to many USB supplies being less than 5V I abandoned the 3 diodes for the 3V supply as it failed to work reliably. D2,D3,D4 and R1 are now redundant. I fitted an LD1117 3.3V low dropout regulator. You can alter the board below . I used this board and fitted the regulator where D1 fits. The incoming 5V to D1 connects to the right pin of the LD1117, the middle pin the fits a new hole drilled above this into the 3.3V rail. the third pin then fits though a third hole where the centre of D1 would have been . I jumped this across the back of the board to a local 0V. Some of the links in the board below can be eliminated with a slightly better routing plan.
The software is written in DSPIC 33fj12gp201 assembly code with loads of comments.
There are two ways to set the frequency.
1) Send a string from a terminal program like "winterm" or "putty". 1,000,000 will set the frequency to 1000000Hz . 1000Hz will set it to 1000Hz . only 0-9 and <CR> are valid all other characters are ignored. ( <ESC> for special setup see later ).
2) Use the two rotary switches. One moves the cursor to the decade to be altered. The other increments/decrements that decade. If you increment 9Hz by 1 Hz the Function generator will scroll up to 10Hz etc. Decrement the same.
The main loop monitors the rotary switches . Each time one is operated either the cursor is moved or the frequency is altered. If the frequency is altered then the display is updated and the DDS frequency altered. Changing the cursor positing just updates the display.
There are 2 interrupt loops. The timer loop just flashes an LED on port RB9 as a heartbeat to let you know the system is running ( LED not fitted on V2 but the software is still there ). The uart receive interrupt collects the data from the serial port in a buffer and uses this to set the DDS frequency , the display is also updated. The set value and an “ok” is transmitted back to acknowledge a valid string received. This loop is also used for calibration of the ADC.
The current source needs to be setup for the switches to function. to do this connect the function generator to a pc via the usb port. Run up your favourite terminal program and set it to talk to the correct com port. now send an escape code to the function generator ( ASCII code 27 ) , I putty you just press the Esc key. The function generator will now start sending the value of the ADC in binary . You will now need to adjust POT1 to give a value of 0111110000 .Pressing Esc will return you to normal mode.
That's it for setup.
Above 20MHz the signal gets a bit rough and smaller too. Using a 5V supply does not seem to make this any better !
The squarewave generator causes a bit of noise on the sine wave. If you are not going to use the square wave I would suggest winding the M:S ration pot to one end this will stop the square wave and improve the sine wave greatly at high frequencies.
My LCD is quite dim as it is about 20 years old. New ones are much better and have back lights.
The Prototype. v2.2