help requested with AD9833 DDS interface

geoff07

Senior Member
If anyone has experience of the AD9833 or AD9837 DDS chip then I should be grateful for a little help. In principal, this chip can provide sine, square wave, and sawtooth signals at any frequency below 12.5MHz, and is simple to control from a microcontroller.

But I am having problems and am running out of things to try. The attached program should display each waveform, at 400Hz, for five seconds, in rotation. In practice, it does display a square wave but it and the sine is at the wrong frequency and the sawtooth never appears.

The coding is based on the specific instructions in AN-1070 from Analogue Devices, the manufacturer. The example I am using is on a module from China, the actual chip being about 2mm square and has 10 leads, way beyond my assembly skills.

There are many products based on this chip so it should be simple to use. The sertxd output confirms that the bit stream sent to it conforms to AN-1070 but the results obviously don't.

I imagine that the problem is a simple oversight on my part but I have spent too much time on this and now seek input from this amazing forum.
Areas of uncertainty remain:

- is it really hspi mode11? Is that mode2?
- do I have the right bit patterns for the control words?

For debugging in the simulator, the program logs the commands to serttxd so they can be analysed and they seem fine to me.

Help gratefully received! Particularly, working Picaxe code!


Code:
#picaxe 28X2
#no_data
setfreq em64
#terminal 76800
symbol HO_AD9833_fsync     = B.1

symbol B_AD9833_MSB        = b1
symbol B_AD9833_LSB        = b0
symbol B_mask              = b4
symbol C_freq_mult         = 8 'default 8MHz, actual 64MHz
symbol C_2S                = C_freq_mult * 2000
symbol C_5S                = C_freq_mult * 5000

do
   call start_sine
   pause C_5S
   call start_square
   pause C_5S
   call start_saw
   pause C_5S
loop
end
'=================================================================  
' Should cycle through sine, square and sawtooth waveforms all at
' 400Hz (with 25MHz xtal), whilst logging transfers to serial terminal 
'==================================================================
writeregister: 'sends a little-endian 16 bit register to the AD9833
   'ad9833 data states: 
   '        clock must be high when fsync goes low - implies idle high
   '        sample taken on falling edge. Thus CPOL=1, CPHA=0
   'this is wikipedia mode2, hspi mode 11 (I think)
   hspisetup spimode11, spifast 'setup each time in case changed 
   low HO_AD9833_fsync 'fsync/cs low before writing
   pauseus 10 'let it get ready
   sertxd(#bit15,#bit14,#bit13,#bit12," ",#bit11,#bit10,#bit9,#bit8,_
   " ",#bit7,#bit6,#bit5,#bit4," ",#bit3,#bit2,#bit1,#bit0,cr,lf)
   hspiout (B_AD9833_LSB, B_AD9833_MSB) 'write 16 bits LSB first
   high HO_AD9833_fsync 'deselect chip as all done
   return
'==================================================================  
start_saw: 
   sertxd("starting saw",cr,lf)
'set control register 
   sertxd("control: ")
   B_AD9833_MSB = %00100001
   B_AD9833_LSB = %00100010
   call writeregister
'set freq and phase
   call set_freq_both
   call set_zero_phase_both
'unreset
   sertxd("control: ")
   B_AD9833_MSB = %00100000
   B_AD9833_LSB = %00100010
   call writeregister 'exit reset 
   sertxd("done saw",cr,lf)
   return 
'==================================================================  
start_square: 
sertxd("starting square",cr,lf)
'set control register 
   sertxd("control: ")
   B_AD9833_MSB = %00101001
   B_AD9833_LSB = %00101000
   call writeregister
'set freq and phase
   call set_freq_both
   call set_zero_phase_both
'unreset
   sertxd("control: ")
   B_AD9833_MSB = %00101000
   B_AD9833_LSB = %00101000
   call writeregister 'exit reset 
   sertxd("done square",cr,lf)
   return 
'================================================================== 
start_sine: 
sertxd("starting sine",cr,lf)
'set control register 
   sertxd("control: ")
   B_AD9833_MSB = %00100001
   B_AD9833_LSB = %00000000
   call writeregister
'set freq and phase
   call set_freq_both
   call set_zero_phase_both
'unreset
   sertxd("control: ")
   B_AD9833_MSB = %00100000
   B_AD9833_LSB = %00000000
   call writeregister 'exit reset 
   sertxd("done sine",cr,lf)
   return 
'==========================================================
set_zero_phase_both:
   sertxd("phase0 : ")
   B_AD9833_MSB = %11000000
   B_AD9833_LSB = %00000000
   call writeregister 'set phase register
   sertxd("phase1 : ")
   B_AD9833_MSB = %11100000
   B_AD9833_LSB = %00000000
   call writeregister 'set phase register
   return
'==========================================================
set_freq_both: 'to 25kHz if clock is 25MHz
'set freq0 LSW
   sertxd("freq0  : ")
   B_AD9833_MSB = %01010000                         
   B_AD9833_LSB = %11000111
   call writeregister 'set frequency register 0 LSBs
'set freq0 MSW
   sertxd("freq0  : ")
   B_AD9833_MSB = %01000000 
   B_AD9833_LSB = %00000000
   call writeregister 'set frequency register 0 MSBs
'set freq1 LSW
   sertxd("freq1  : ")
   B_AD9833_MSB = %10010000                         
   B_AD9833_LSB = %11000111
   call writeregister 'set frequency register 1 LSBs
'set freq1 MSW
   sertxd("freq1  : ")
   B_AD9833_MSB = %10000000 
   B_AD9833_LSB = %00000000
   call writeregister 'set frequency register 1 MSBs
   return
 

max.well

New Member
geoff07 ... hi , your '33 posting caught my attention. first thing is to ask the status of your efforts ?
have you had any new ideas that moved you further along ?

now the 28x2 is one i have no experience with. so your code is not readily understood. yet.

the an-1070 is my coding example guide too. along with the '33 data sheet. the uC is the 14m2.

a nice clean sine wave was produced earlier this morning. 600mVpp. only at 1050 Hz , not 400.
the hex to decimal conversion numbers were dbl checked.

my '33 is from ebay on a pcb 2.7 x 2.2 cm . with a REF pin having Vcc/2 on it

this sine output follows changing from shiftoutMSB 1'st to shiftoutLSB 1'st. via p. 238 of the 7.9.2 manual

your code's been copied and printed. in hopes that despite it using
a 'X2' uC with a true 'spi' command it will clarify some aspects of the coding that are still troubling me.

i especially liked seeing how you used sertxd to grab the actual spi data bits sent. my idea was to use
the spi decoding ability of my rigol 1054 scope

in your symbol list is 'B_mask = b4' .. only no use of a mask or b4 is found anywhere else ???

more later

max.well
 

hippy

Technical Support
Staff member
hspiout (B_AD9833_LSB, B_AD9833_MSB) 'write 16 bits LSB first

I am not familiar with the AD9833 but the datasheet I found indicates that it is a 16-bit command, sent D15 (msb) first, D0 (lsb) last.
 
I've recently written a short program to load the frequency registers of the AD9833 for a single specific frequency. I also wrote an EXCEL spreadsheet to calculate the hexadecimal values to be loaded - the 28 bit frequency register has to be loaded as two words consisting of 2 control bits plus 14 bits of frequency register data. This program was written for the 08M2 but can be adapted for another in the PICAXE range. I bit-banged the SPI interface. This program has been used with a cheap module from China specifically for a square wave output but I did try it with the sine wave output (with an external filter) as well.

Let me know if you would like the code and also the spreadsheet.

Richard

If anyone has experience of the AD9833 or AD9837 DDS chip then I should be grateful for a little help. In principal, this chip can provide sine, square wave, and sawtooth signals at any frequency below 12.5MHz, and is simple to control from a microcontroller.

But I am having problems and am running out of things to try. The attached program should display each waveform, at 400Hz, for five seconds, in rotation. In practice, it does display a square wave but it and the sine is at the wrong frequency and the sawtooth never appears.

The coding is based on the specific instructions in AN-1070 from Analogue Devices, the manufacturer. The example I am using is on a module from China, the actual chip being about 2mm square and has 10 leads, way beyond my assembly skills.

There are many products based on this chip so it should be simple to use. The sertxd output confirms that the bit stream sent to it conforms to AN-1070 but the results obviously don't.

I imagine that the problem is a simple oversight on my part but I have spent too much time on this and now seek input from this amazing forum.
Areas of uncertainty remain:

- is it really hspi mode11? Is that mode2?
- do I have the right bit patterns for the control words?

For debugging in the simulator, the program logs the commands to serttxd so they can be analysed and they seem fine to me.

Help gratefully received! Particularly, working Picaxe code!


Code:
#picaxe 28X2
#no_data
setfreq em64
#terminal 76800
symbol HO_AD9833_fsync     = B.1

symbol B_AD9833_MSB        = b1
symbol B_AD9833_LSB        = b0
symbol B_mask              = b4
symbol C_freq_mult         = 8 'default 8MHz, actual 64MHz
symbol C_2S                = C_freq_mult * 2000
symbol C_5S                = C_freq_mult * 5000

do
   call start_sine
   pause C_5S
   call start_square
   pause C_5S
   call start_saw
   pause C_5S
loop
end
'=================================================================  
' Should cycle through sine, square and sawtooth waveforms all at
' 400Hz (with 25MHz xtal), whilst logging transfers to serial terminal 
'==================================================================
writeregister: 'sends a little-endian 16 bit register to the AD9833
   'ad9833 data states: 
   '        clock must be high when fsync goes low - implies idle high
   '        sample taken on falling edge. Thus CPOL=1, CPHA=0
   'this is wikipedia mode2, hspi mode 11 (I think)
   hspisetup spimode11, spifast 'setup each time in case changed 
   low HO_AD9833_fsync 'fsync/cs low before writing
   pauseus 10 'let it get ready
   sertxd(#bit15,#bit14,#bit13,#bit12," ",#bit11,#bit10,#bit9,#bit8,_
   " ",#bit7,#bit6,#bit5,#bit4," ",#bit3,#bit2,#bit1,#bit0,cr,lf)
   hspiout (B_AD9833_LSB, B_AD9833_MSB) 'write 16 bits LSB first
   high HO_AD9833_fsync 'deselect chip as all done
   return
'==================================================================  
start_saw: 
   sertxd("starting saw",cr,lf)
'set control register 
   sertxd("control: ")
   B_AD9833_MSB = %00100001
   B_AD9833_LSB = %00100010
   call writeregister
'set freq and phase
   call set_freq_both
   call set_zero_phase_both
'unreset
   sertxd("control: ")
   B_AD9833_MSB = %00100000
   B_AD9833_LSB = %00100010
   call writeregister 'exit reset 
   sertxd("done saw",cr,lf)
   return 
'==================================================================  
start_square: 
sertxd("starting square",cr,lf)
'set control register 
   sertxd("control: ")
   B_AD9833_MSB = %00101001
   B_AD9833_LSB = %00101000
   call writeregister
'set freq and phase
   call set_freq_both
   call set_zero_phase_both
'unreset
   sertxd("control: ")
   B_AD9833_MSB = %00101000
   B_AD9833_LSB = %00101000
   call writeregister 'exit reset 
   sertxd("done square",cr,lf)
   return 
'================================================================== 
start_sine: 
sertxd("starting sine",cr,lf)
'set control register 
   sertxd("control: ")
   B_AD9833_MSB = %00100001
   B_AD9833_LSB = %00000000
   call writeregister
'set freq and phase
   call set_freq_both
   call set_zero_phase_both
'unreset
   sertxd("control: ")
   B_AD9833_MSB = %00100000
   B_AD9833_LSB = %00000000
   call writeregister 'exit reset 
   sertxd("done sine",cr,lf)
   return 
'==========================================================
set_zero_phase_both:
   sertxd("phase0 : ")
   B_AD9833_MSB = %11000000
   B_AD9833_LSB = %00000000
   call writeregister 'set phase register
   sertxd("phase1 : ")
   B_AD9833_MSB = %11100000
   B_AD9833_LSB = %00000000
   call writeregister 'set phase register
   return
'==========================================================
set_freq_both: 'to 25kHz if clock is 25MHz
'set freq0 LSW
   sertxd("freq0  : ")
   B_AD9833_MSB = %01010000                         
   B_AD9833_LSB = %11000111
   call writeregister 'set frequency register 0 LSBs
'set freq0 MSW
   sertxd("freq0  : ")
   B_AD9833_MSB = %01000000 
   B_AD9833_LSB = %00000000
   call writeregister 'set frequency register 0 MSBs
'set freq1 LSW
   sertxd("freq1  : ")
   B_AD9833_MSB = %10010000                         
   B_AD9833_LSB = %11000111
   call writeregister 'set frequency register 1 LSBs
'set freq1 MSW
   sertxd("freq1  : ")
   B_AD9833_MSB = %10000000 
   B_AD9833_LSB = %00000000
   call writeregister 'set frequency register 1 MSBs
   return
 

geoff07

Senior Member
Thank you for the suggestions. I did try reversing the hspiout byte order, but that did not solve it. I had agonised over bit and byte order and tried various alternatives, which is what led to the rather thorough test program, as I could hardly believe that this thing was not responding. With my byte order (lsb first 'littleendian') I get a 680mV pp sine wave at about 52KHz with a short flash of a Vcc square wave at half frequency (when the square is programmed in the code, but only for enough cycles for the 'scope to lock and then it is gone again). With the order reversed I get the sine wave but no square wave. So whatever the correct order, that isn't the only issue. Hence my perplexity.

So yes please, I would appreciate any code known to work so I can check mine against it. And the spreadsheet too, it is a fiddly calculation so that would be a good check.

I will report any progress.

Given this effort, does anyone have a simple means of making a nice audio sine wave with few components? I'm aware of the ICL8038 analogue option but that needs a bunch of parts.
 

premelec

Senior Member
Please be more specific... Do you need just one frequency or variable? Harmonic distortion level acceptable? How many is 'few' and do the parts have to be small?
 

geoff07

Senior Member
Generating a line level (-10dBV/0.9v pp) at 400Hz or 1k would be a good start. It is for an audio tester. I toyed with a dac output (needs a buffer); 555 - needs a filter; Wein bridge - too many parts - and a dds seemed like the easy option.

If I had known how hard the DDS would be to drive I would have done something simple. But now I don't want to give in. However, I may not succeed. The attraction of the ad9833 is the way the tiny daughterboard (modules) just plug into a header and it can do so much (allegedly). The fear I have is that the modules are both dud (I bought two). How likely is that!
 

hippy

Technical Support
Staff member
If I had known how hard the DDS would be to drive I would have done something simple. But now I don't want to give in. However, I may not succeed. The attraction of the ad9833 is the way the tiny daughterboard (modules) just plug into a header and it can do so much (allegedly). The fear I have is that the modules are both dud (I bought two). How likely is that!
It seems unlikely they are dud seeing as something does work. The chips should be as easy to use as you expect, even if there may be some complexity with settings to get exactly what you want.

It looks to me that you are doing things in a far more complicated way than needs to be and you should start simpler.

It seems there are three reasons it might not be working as expected -

The AD9833 is not connected correctly.
The commands and data being sent are not correct.
The SPI interface is not configured for the correct protocol.

So let's see a circuit diagram and photos of the board so we can rule the first out. It seems it is right because something is working, but let's check. It's no good investing time and effort into making something work when it never can work.

Then start with simpler code using default 8MHz operating speed rather than 64MHz, and let's just get one operational mode going at a time, probably best to start with the one which doesn't work now so you tell when it is working.

Explain what the commands and data sent means so people can check that what you claim matches what the datasheet says because they probably cannot come from the 'this is what you should be using' direction.

You can say 'I am setting this bit or value, to achieve this' and that can be verified as 'sounds right or wrong' and you'll inch forward to something which has a consensus it should be working and, if it isn't, the cause for that can then be investigated. It's always easier to focus on one thing than a bigger whole.

And I would recommend starting with bit-banged code for SPI. If that doesn't work then post your code and people can check that.

Once we have one thing working you can change commands and data to verify the other things work, if not get those working.

And with everything working you can move to using HSPI, increasing operating speed if desired.

One needs to work through it methodically, build upon what is working, overcome hurdles one at a time. At present we know you have fallen in the race but have little idea where or why.
 
I've adapted the software that I wrote so that it generates a 1kHz sine wave - I have checked that it works on a PCB fitted with an AD9833.

I have sent a PE asking for your email address and I will send the program and EXCEL spreadsheet when I receive it.

Richard

Thank you for the suggestions. I did try reversing the hspiout byte order, but that did not solve it. I had agonised over bit and byte order and tried various alternatives, which is what led to the rather thorough test program, as I could hardly believe that this thing was not responding. With my byte order (lsb first 'littleendian') I get a 680mV pp sine wave at about 52KHz with a short flash of a Vcc square wave at half frequency (when the square is programmed in the code, but only for enough cycles for the 'scope to lock and then it is gone again). With the order reversed I get the sine wave but no square wave. So whatever the correct order, that isn't the only issue. Hence my perplexity.

So yes please, I would appreciate any code known to work so I can check mine against it. And the spreadsheet too, it is a fiddly calculation so that would be a good check.

I will report any progress.

Given this effort, does anyone have a simple means of making a nice audio sine wave with few components? I'm aware of the ICL8038 analogue option but that needs a bunch of parts.
 

techElder

Well-known member
Richard, is there something proprietary about the code that you are offering privately? Is it possible to post code here or publicly elsewhere? There are some of us that are monitoring this thread without participating. Sorry to put you on the spot! :D
 

geoff07

Senior Member
Hippy is right of course. The simplest (only) example is in AN-1070, and is essentially:

hspisetup spimode11, spislow
low HO_AD9833_fsync
hspiout($21,$00)
hspiout($50,$C7)
hspiout($40,$00)
hspiout($C0,$00)
hspiout($20,$00)
pause C_100mS
high HO_AD9833_fsync

It should create a 400Hz sine wave.

This doesn't have any effect (I get a sine wave at 59kHz which seems to be a default). Changing the LSByte frequency register incrementally has no effect. So my conclusion is it is not acting on the input. But I think MSByte and msbit first are correct and what this code does.

I just rechecked the wiring, and confirmed that fsync is on B.1 as per code, and sclk is c.3 and sdata (i.e. mosi) is c.5 both as per hspi hardware. There is no miso needed. The signals all seem credible on the scope. I'm not sure a photo would help due to the patch wiring but I will take some. I don't have a schematic for these tests as I am using a project board and only these few lines are relevant so far. There is an overall Eagle schematic in development but it wouldn't help here.

The main area that remains uncertain for me is the spi mode and how to set it with hspi (the spi and hspi terminology are different in the manual). There is much relevant code around in versions of Basic and in C and so far as I can tell are compatible with my code, though some stuff is hidden in libraries.

I will go back to 8MHz first and try that and then use the x2 bit-bang commands instead of hspi.
 
Hi Tex,

No, nothing proprietary about it - it's a variation of some code that I wrote several months ago for another member of this forum who was having trouble with the AD9833 DDS. There is also a spreadsheet that I want to send to geoff07 and just emailing the lot seemed easier. Although I check this forum most days, I seldom post (any question to which I know the answer has usually been answered), so I'll have a go at posting my code.

Richard

Richard, is there something proprietary about the code that you are offering privately? Is it possible to post code here or publicly elsewhere? There are some of us that are monitoring this thread without participating. Sorry to put you on the spot! :D
 

hippy

Technical Support
Staff member
The simplest (only) example is in AN-1070, and is essentially:
I would agree the commands and data match what AN-1070 show and would take them to be right. The byte/bit order looks correct so that suggests a wiring issue or an HSPISETUP issue as you suggest.

Wiring seems correct -

B.1 -> FSYNC
C.3 HSPI SCK -> SCLK
C.5 HSPI SDO -> SDATA

Which suggest HPISETUP. The SCK should be high before FSYNC is brought low to start things off, SCK should be a low going pulse when the SDA data is being output. SPIMODE11 or SPIMODE10 would seem to fit the bill. So that also seems right.

The only things I can think of is the code may need a HIGH B.1 (FSYNC) at the start, a STOP or DO:LOOP at the end if there isn't one, and it may be that FSYNC needs to be taken low at the start of each command sent, taken high after, rather than being low during the entire data transmission.

Untested but I would try this -

Code:
#Picaxe 28X2
#No_Data
#No_Table

#Define BITBANGED

Symbol FSYNC = B.1
Symbol SCK   = C.3
Symbol SDO   = C.5

; Bit-Banged SPI
 
#Macro SpiIni_BitBang
  High SCK
  Low  SDO
#EndMacro

#Macro SpiOut_BitBang(wVal)
  w0 = wVal : Gosub Do_SpiOut
#EndMacro

; Hardwre SPI

#Macro SpiIni_Hardware
  HSpiSetup SPIMODE11, SPISLOW
#EndMacro

#Macro SpiOut_Hardware(wVal)
  Low  FSYNC
  w0 = wVal : HSpiOut( b1, b0 )
  High FSYNC
#EndMacro

; Select mode used

#IfDef BITBANGED
  #Define SpiIni       SpiIni_BitBang
  #Define SpiOut(wVal) SpiOut_BitBang(wVal)
#Else
  #Define SpiIni       SpiIni_Hardware
  #Define SpiOut(wVal) SpiOut_Hardware(wVal)
#EndIf

; Main test program

MainLoop:
  High FSYNC
  SpiIni
  Do
    SpiOut($2100)
    SpiOut($50C7)
    SpiOut($4000)
    SpiOut($C000)
    SpiOut($2000)
    Pause 5000
  Loop

#IfDef BITBANGED

Do_SpiOut:
  Low FSYNC
  For b2 = 0 To 15
    If w0 >= $8000 Then
      High SDO
    Else
      Low  SDO
    End If
    Low  SCK
    w0 = w0 * 2
    High SCK
  Next
  High FSYNC
  Return

#EndIf
That's a bit-banged version of AN-1070. If it works, comment out the "#Define BITBANGED" and it will use HSPI hardware. Make sure you power cycle after downloading to test it really does initialise properly rather than is just retaining the old settings. Maybe tweak the frequency just to prove the HSPI code is changing things.

If things still don't work, or bit-banged works but HSPI doesn't, it will require a bit more thought.
 
As requested, here is my code for an 08M2 to set the AD9833 to give a sine wave output at 1.000kHz.

The 28 bit frequency register of the AD9833 is loaded as two 14 bit + 2 control bit words. I wrote an EXCEL spreadsheet to do the sums but EXCEL extensions are not allowed as attachments.

I hope that the comments within the program are helpful.

Richard
 

Attachments

geoff07

Senior Member
8MHz seems to make no difference to hspi.
spiout instead of hspiout fails due to the X2 firmware bug (no Idle High/MSB first mode in the firmware).
using the subroutine in manual 2 executes and the signals are evident but there seems to be no response at all from the chip (flat-line).
Hmmm. Scratches head.
 

geoff07

Senior Member
Both, thanks for the code and the ideas, just seen. I will contemplate.

You can change the suffix on a file to fool the vBulletin thing.
 

premelec

Senior Member
FWIW I saw a circuit recently that simply ran a square wave through an IC chip filter co-ordinating the clock to the filter with the square wave generator... personally I tend toward traditional analog twin T or phase shift... There were also circuits using weighted resistors in Don Lancaster's book that produced an easily filtered step approximation of the SW... good luck with it! So many circuits so little time!
 

geoff07

Senior Member
I took szd51pilot's code, modified it for a 28x2 (clock, timing, pin allocation) and loaded it as is and it worked. Thank you greatly for that. The hardware must be correct so that is a big step forward.. So I will now progressively convert it to suit my needs (faster clock, use of hspi, different freq and waveforms), and see at which point it dies, and then I will report back. This chip seems like a most useful thing to generate waveforms up to 12.5MHz, so it surprises me that not so many people have commented as I was expecting to hear many had used it.

I can now have a waveform generator with precise frequency control and a low impedance output with only 0.5in x 0.7in real estate.

Thank you all for various contributions. I will publish a working picaxe test program for an X2 at high speed with all the waveforms in due course. Remind me if you would like it and I don't do it quickly. I will also try hippy's code and see what happens. Thanks for putting in the time.
 

geoff07

Senior Member
Moving on .. I took hippy's code (which is also a tutorial on how to use macros in the pre-processor) and ran it. In its native state it produced a 400Hz sine, as expected. With the switch made to hspi, it produced a flat-line at 528mV. After power cycling, the flat-line became a sine at 53kHz

So the issue is the use of hspi. Deep thought required.

Is there any chance that the long-standing bug re spiout could be addressed? Though that would need a new chip of course.
 
Last edited:

hippy

Technical Support
Staff member
In my original code I forgot a "w0 = wVal" assignment in the HSPI macro which I then added. Check that's not missing in your code -

Code:
#Macro SpiOut_Hardware(wVal)
  Low  FSYNC
  [b]w0 = wVal : [/b]HSpiOut( b1, b0 )
  High FSYNC
#EndMacro
 

geoff07

Senior Member
No I got that thanks.

But I have just tried playing with modes and I seem to get it working with

HSpiSetup SPIMODE10, SPISLOW

But I'm not sure I can reconcile the picaxe manual with the ad9833 datasheet. It doesn't help that every doc on spi seems to use different nomenclature.

The manual says that hspi mode10 is (CKP=1, CKE=1, SMP=0) Mode (1,0)

I read this as clock idle high (CPE=1) transmit in rising/trailing edge of clock (CPE=1) sample at middle of data time (SMP=0)

This does not seem compatible with the datasheet: "After FSYNC goes low, serial
data is shifted into the input shift register of the device on the falling edges of SCLK"

But a detailed understanding of spi variations should not be needed by a Picaxe user!

I will now see how robust this setting is at higher speeds.
 

hippy

Technical Support
Staff member
I seem to get it working with

HSpiSetup SPIMODE10, SPISLOW

But I'm not sure I can reconcile the picaxe manual with the ad9833 datasheet. It doesn't help that every doc on spi seems to use different nomenclature.
I was going to suggest trying different modes next because there are all only four possible modes, and only two which start with SCL high..

It can all get complicated with different terminology. I usually look at what the device datasheet asks for and then look to see which ones vsiaully match that. If one does it by bit-banging first that proves the bit-banging mechanism and sequence reflects what the datasheet says. It's then usually just a case of which of the four modes matches the bit-banged sequence.

In this case it's SCK high when it starts, pulsing low per data bit, with data latched on the falling edge of SCK.

PICAXE Manual 2 'Basic Commands' has logic analyser traces of the actual output for each mode and SPIMODE11 and SPIMODE10 match the datasheet and bit-banging code.

The difference between SPIMODE11 and SPIMODE10 is SPIMODE11 has the falling edge soon after the data is changed, SPIMODE10 has it falling later. Both should work but perhaps the falling edge of SPIMODE11 is too soon after the data changes for the chip in question, SPIMODE10 therefore the better option.

Looking at it; SPIMODE11 would probably be best for data latched on rising edge, SPIMODE10 best suited to falling edge as has been found.

Code:
SPIMODE11
         _____       _____
SDO  ___|:    |_____|:    |______
     ____:  ___:  ___:  ___:  ___
SCK      |_|   |_|   |_|   |_|
Code:
SPIMODE10
         _____       _____
SDO  ___|  :  |_____|  :  |______
     ______:  ___:  ___:  ___:  _
SCK        |_|   |_|   |_|   |_|
 

hippy

Technical Support
Staff member
Looking at it; SPIMODE11 would probably be best for data latched on rising edge, SPIMODE10 best suited to falling edge as has been found.
Looking at it from the perspective of which mode puts the latching point most optimally in the centre of the data, one can arrive at -

SPIMODE00 : SCK starts low, pulses high, latching on rising edge
SPIMODE01 : SCK starts low, pulses high, latching on falling edge
SPIMODE10 : SCK starts high, pulses low, latching on falling edge
SPIMODE11 : SCK starts high, pulses low, latching on rising edge

That might not be perfect but would seem a good place to start from.
 

geoff07

Senior Member
This is a working test program to drive an AD9833 DDS waveform generator. You can use it to precisely create signals from 0Hz to 12.5MHz. Although I used a 28X2, there is nothing to stop it being used with any Picaxe chip, though you might need to change the spi interface.
Code:
#picaxe 28X2
#no_data
#no_table
#rem
--------------------------------------------------------------------
Test program to control direct digital synthesiser AD9833 using
a Picaxe. It produces sine, square and sawtooth waveforms in succession
at 400Hz using hardware spi, 64MHz clock speed, and fast spi speed.
Sine and sawtooth outputs are at approx 660mV pp, the square wave is 
0-Vcc (3.3v).  Sent bit patterns are displayed on sertxd.
The hspisetup mode:spimode10 is critical.
Both frequency and phase registers are set but only one is used.
Free to all to use.
Stuart Gillies 2018 (geoff07)
Thanks to massive help from the forum in tracking down a problem.
The AD9833 is a microscopic chip and is best used in the form of
a 0.5in x 0.7in module available online for about £3.50
--------------------------------------------------------------------
#endrem
setfreq em64
#terminal 76800
symbol HO_AD9833_fsync     = B.1

symbol B_AD9833_MSB        = b1
symbol B_AD9833_LSB        = b0

symbol C_freq_mult         = 8 'default 8MHz, actual 64MHz
symbol C_2S                = C_freq_mult * 2000
symbol C_5S                = C_freq_mult * 5000

do
   call start_sine
   pause C_5S
   call start_square
   pause C_5S
   call start_saw
   pause C_5S
loop
end

'=================================================================  
writeregister: 'sends a 16 bit register to the AN9833
'after much trauma it was determined that hspi mode 10 was required.
   hspisetup spimode10, spifast 'setup each time in case changed 
   low HO_AD9833_fsync 'fsync/cs low before writing
   pauseus 10 'let it get ready
   sertxd(#bit15,#bit14,#bit13,#bit12," ",#bit11,#bit10,#bit9,#bit8,_
   " ",#bit7,#bit6,#bit5,#bit4," ",#bit3,#bit2,#bit1,#bit0,cr,lf)
   hspiout (B_AD9833_MSB, B_AD9833_LSB) 'write 16 bits MSB first
   high HO_AD9833_fsync 'deselect chip as all done
   return
'==================================================================  
start_saw: 
   sertxd("starting saw",cr,lf)
'set control register 
   sertxd("control: ")
   B_AD9833_MSB = %00100001
   B_AD9833_LSB = %00000010
   call writeregister
'set freq and phase
   call set_freq_both
   call set_zero_phase_both
'unreset
   sertxd("control: ")
   B_AD9833_MSB = %00100000
   B_AD9833_LSB = %00000010
   call writeregister 'exit reset state
   sertxd("done saw",cr,lf)
   return 
'==================================================================  
start_square: 
sertxd("starting square",cr,lf)
'set control register 
   sertxd("control: ")
   B_AD9833_MSB = %00101001
   B_AD9833_LSB = %00101000
   call writeregister
'set freq and phase
   call set_freq_both
   call set_zero_phase_both
'unreset
   sertxd("control: ")
   B_AD9833_MSB = %00101000
   B_AD9833_LSB = %00101000
   call writeregister 'exit reset state
   sertxd("done square",cr,lf)
   return 
'================================================================== 
start_sine: 
sertxd("starting sine",cr,lf)
'set control register 
   sertxd("control: ")
   B_AD9833_MSB = %00100001
   B_AD9833_LSB = %00000000
   call writeregister
'set freq and phase
   call set_freq_both
   call set_zero_phase_both
'unreset
   sertxd("control: ")
   B_AD9833_MSB = %00100000
   B_AD9833_LSB = %00000000
   call writeregister 'exit reset state
   sertxd("done sine",cr,lf)
   return 
'==========================================================
set_zero_phase_both:
   sertxd("phase0 : ")
   B_AD9833_MSB = %11000000
   B_AD9833_LSB = %00000000
   call writeregister 'set phase register
   sertxd("phase1 : ")
   B_AD9833_MSB = %11100000
   B_AD9833_LSB = %00000000
   call writeregister 'set phase register
   return
'==========================================================
set_freq_both: 'to 400Hz if clock is 25MHz
'set freq0 LSW
   sertxd("freq0  : ")
   B_AD9833_MSB = %01010000 '$10                       
   B_AD9833_LSB = %11000110 '$C6  
   call writeregister 'set frequency register 0 LSBs
'set freq0 MSW
   sertxd("freq0  : ")
   B_AD9833_MSB = %01000000 
   B_AD9833_LSB = %00000000
   call writeregister 'set frequency register 0 MSBs
'set freq1 LSW
   sertxd("freq1  : ")
   B_AD9833_MSB = %10010000 '$10           #picaxe 28X2
#no_data
#no_table
#rem
--------------------------------------------------------------------
Test program to control direct digital synthesiser AD9833 using
a Picaxe. It produces sine, square and sawtooth waveforms in succession
at 400Hz using hardware spi, 64MHz clock speed, and fast spi speed.
Sine and sawtooth outputs are at approx 660mV pp, the square wave is 
0-Vcc (3.3v).  Sent bit patterns are displayed on sertxd.
The hspisetup mode:spimode10 is critical.
Both frequency and phase registers are set but only one is used.
Free to all to use.
Stuart Gillies 2018 (geoff07)
Thanks to massive help from the forum in tracking down a problem.
The AD9833 is a microscopic chip and is best used in the form of
a 0.5in x 0.7in module available online for about £3.50
--------------------------------------------------------------------
#endrem
setfreq em64
#terminal 76800
symbol HO_AD9833_fsync     = B.1

symbol B_AD9833_MSB        = b1
symbol B_AD9833_LSB        = b0

symbol C_freq_mult         = 8 'default 8MHz, actual 64MHz
symbol C_2S                = C_freq_mult * 2000
symbol C_5S                = C_freq_mult * 5000

do
   call start_sine
   pause C_5S
   call start_square
   pause C_5S
   call start_saw
   pause C_5S
loop
end

'=================================================================  
writeregister: 'sends a 16 bit register to the AN9833
'after much trauma it was determined that hspi mode 10 was required.
   hspisetup spimode10, spifast 'setup each time in case changed 
   low HO_AD9833_fsync 'fsync/cs low before writing
   pauseus 10 'let it get ready
   sertxd(#bit15,#bit14,#bit13,#bit12," ",#bit11,#bit10,#bit9,#bit8,_
   " ",#bit7,#bit6,#bit5,#bit4," ",#bit3,#bit2,#bit1,#bit0,cr,lf)
   hspiout (B_AD9833_MSB, B_AD9833_LSB) 'write 16 bits MSB first
   high HO_AD9833_fsync 'deselect chip as all done
   return
'==================================================================  
start_saw: 
   sertxd("starting saw",cr,lf)
'set control register 
   sertxd("control: ")
   B_AD9833_MSB = %00100001
   B_AD9833_LSB = %00000010
   call writeregister
'set freq and phase
   call set_freq_both
   call set_zero_phase_both
'unreset
   sertxd("control: ")
   B_AD9833_MSB = %00100000
   B_AD9833_LSB = %00000010
   call writeregister 'exit reset state
   sertxd("done saw",cr,lf)
   return 
'==================================================================  
start_square: 
sertxd("starting square",cr,lf)
'set control register 
   sertxd("control: ")
   B_AD9833_MSB = %00101001
   B_AD9833_LSB = %00101000
   call writeregister
'set freq and phase
   call set_freq_both
   call set_zero_phase_both
'unreset
   sertxd("control: ")
   B_AD9833_MSB = %00101000
   B_AD9833_LSB = %00101000
   call writeregister 'exit reset state
   sertxd("done square",cr,lf)
   return 
'================================================================== 
start_sine: 
sertxd("starting sine",cr,lf)
'set control register 
   sertxd("control: ")
   B_AD9833_MSB = %00100001
   B_AD9833_LSB = %00000000
   call writeregister
'set freq and phase
   call set_freq_both
   call set_zero_phase_both
'unreset
   sertxd("control: ")
   B_AD9833_MSB = %00100000
   B_AD9833_LSB = %00000000
   call writeregister 'exit reset state
   sertxd("done sine",cr,lf)
   return 
'==========================================================
set_zero_phase_both:
   sertxd("phase0 : ")
   B_AD9833_MSB = %11000000
   B_AD9833_LSB = %00000000
   call writeregister 'set phase register
   sertxd("phase1 : ")
   B_AD9833_MSB = %11100000
   B_AD9833_LSB = %00000000
   call writeregister 'set phase register
   return
'==========================================================
set_freq_both: 'to 400Hz if clock is 25MHz
'set freq0 LSW
   sertxd("freq0  : ")
   B_AD9833_MSB = %01010000 '$10                       
   B_AD9833_LSB = %11000110 '$C6  
   call writeregister 'set frequency register 0 LSBs
'set freq0 MSW
   sertxd("freq0  : ")
   B_AD9833_MSB = %01000000 
   B_AD9833_LSB = %00000000
   call writeregister 'set frequency register 0 MSBs
'set freq1 LSW
   sertxd("freq1  : ")
   B_AD9833_MSB = %10010000 '$10                       
   B_AD9833_LSB = %11000110 '$C6  
   call writeregister 'set frequency register 1 LSBs
'set freq1 MSW
   sertxd("freq1  : ")
   B_AD9833_MSB = %10000000 
   B_AD9833_LSB = %00000000
   call writeregister 'set frequency register 1 MSBs
   return            
   B_AD9833_LSB = %11000110 '$C6  
   call writeregister 'set frequency register 1 LSBs
'set freq1 MSW
   sertxd("freq1  : ")
   B_AD9833_MSB = %10000000 
   B_AD9833_LSB = %00000000
   call writeregister 'set frequency register 1 MSBs
   return
 
Top