{"id":853,"date":"2015-12-10T11:51:30","date_gmt":"2015-12-10T11:51:30","guid":{"rendered":"http:\/\/stompville.co.uk\/?p=853"},"modified":"2020-10-11T13:44:24","modified_gmt":"2020-10-11T13:44:24","slug":"bit-banging-the-ad9833-dds-module","status":"publish","type":"post","link":"https:\/\/stompville.co.uk\/?p=853","title":{"rendered":"Bit-banging the AD9833 DDS module"},"content":{"rendered":"<p>I bought an AD9833 DDS module from China &#8211; you know the one:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"  wp-image-854 aligncenter\" src=\"http:\/\/stompville.co.uk\/wp-content\/uploads\/2015\/12\/P162SV.jpg\" alt=\"P162SV\" width=\"222\" height=\"228\" srcset=\"https:\/\/stompville.co.uk\/wp-content\/uploads\/2015\/12\/P162SV.jpg 320w, https:\/\/stompville.co.uk\/wp-content\/uploads\/2015\/12\/P162SV-292x300.jpg 292w\" sizes=\"(max-width: 222px) 100vw, 222px\" \/><\/p>\n<p>I wanted to control it from an Atmel ATtiny and my weapon of choice was the ATtiny44. Now I could just have easily used an ATtiny2313 (both devices are 14-pin), but I didn&#8217;t &#8211; and I went on and built a PCB.<\/p>\n<p>So when I came to program the ATtiny44, I realised it does not have a proper USART-SPI-mode (which the &#8216;2313 does). The ATtiny44 (along with the &#8217;24 and &#8217;84 variants and the ATtiny85) just have the USI hardware module which can be crow-barred into service as an SPI master with some heavy lifting.<\/p>\n<p>Well I tried three different software libraries to try and talk to the AD9833 and failed miserably on all three counts. Getting desperate, I decided to bit-bang the AD9833 to see if it was actually working. The bit-bang worked perfectly first time and &#8211; as I do not need to write to the AD9833 at any great speed &#8211; I decided to implement the bit-bang code and forget trying to get a library to work for now &#8211; although no doubt I will need to revisit the library again at some point.<\/p>\n<p>This code should work on pretty much any Atmel Tiny or Mega processor.<\/p>\n<p>Basically, we need a processor which is running at a decent speed (8MHz in my case) and any three pins: chip-select, data and clock. We manipulate these pins in accordance with the timing\u00a0 and level requirements of the AD9833 datasheet. Level requirements are: chip-select is active low, clock is normally high and data is clocked on the falling edge of the clock. Data is clocked out MSB first.<\/p>\n<p>We are following the software protocol in application note <a title=\"www.analog.com\/media\/en\/technical-documentation\/application-notes\/AN-1070.pdf\" href=\"https:\/\/www.analog.com\/media\/en\/technical-documentation\/application-notes\/AN-1070.pdf\" target=\"_blank\" rel=\"noopener noreferrer\">AN-1070;<\/a> so to get the AD9833 to output a sinewave we need to send:<\/p>\n<ul>\n<li>0x2100 &#8211; put the AD9833 into reset and tell it to accept 14bit words<\/li>\n<li>0xnnnn &#8211; Lo word of the set-frequency-instruction<\/li>\n<li>0xnnnn &#8211; Hi word of the set-frequency-instruction<\/li>\n<li>0xC000 &#8211; set the phase angle to zero<\/li>\n<li>0x2000 &#8211; take the AD9833 out of reset and output sinewave<\/li>\n<\/ul>\n<p>There is a formula on the application note to calculate the frequency Lo word and Hi word for any given frequency. I wrote a spreadsheet to work these numbers out for you. You can download the <a title=\"stompville.co.uk\/downloads\/AD9833-freq-conv.xls\" href=\"http:\/\/stompville.co.uk\/downloads\/AD9833-freq-conv.xls\" target=\"_blank\" rel=\"noopener noreferrer\">spreadsheet<\/a> or use the <a title=\"stompville.co.uk\/AD9833.php\" href=\"https:\/\/stompville.co.uk\/AD9833.php\" target=\"_blank\" rel=\"noopener noreferrer\">php calculator<\/a> wot I wrote.<\/p>\n<p>So, let&#8217;s say we want to output a sinewave at 1000Hz. We use one of the resources above to find the register values, which are low = 0x69F1 and high = 0x4000 (assuming your module has a 25MHz crystal\/oscillator fitted!).<\/p>\n<p>You can download the code below as a .c <a title=\"stompville.co.uk\/downloads\/AD9833.c\" href=\"https:\/\/stompville.co.uk\/downloads\/AD9833.c\" target=\"_blank\" rel=\"noopener noreferrer\">text file<\/a>.<\/p>\n<p>If you are using Arduino, you can change SET(DDRA,ddsDataPin) to pinMode(ddsDataPin,OUTPUT) and SET(PORTA,ddsDataPin) to digitalWrite(ddsDataPin,HIGH), etc.<\/p>\n<p>The ASM_NOP() function gives a single processor cycle delay (no-operation).<\/p>\n<p>Have fun.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/stompville.co.uk\/wp-content\/uploads\/2012\/02\/svfavicon.png\" alt=\"svfavicon.png\" width=\"16\" height=\"16\" \/><\/p>\n<pre><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\n\n#define F_CPU 8000000UL\n\n#include &lt;avr\/io&gt;\n#include &lt;inttypes.h&gt;\n\n#define ddsSelectPin PA0\n#define ddsClockPin PA2\n#define ddsDataPin PA3\n\n#define ASM_NOP() asm volatile (\"nop\" :: )\n#define SET(x,y) (x|=(1&lt;&lt;y))\n#define CLEAR(x,y) (x&amp;=(~(1&lt;&lt;y)))\n#define CHECK(x,y) (x&amp;(1&lt;&lt;y))\n#define TOGGLE(x,y) (x^=(1&lt;&lt;y))\n\nuint16_t freqLoWord = 0x69F1; \/\/what sample frequency is this? 1kHz!\nuint16_t freqHiWord = 0x4000;\n\nvoid setDDR(void) {\n  \/\/set data direction (1 = output)\n  SET(DDRA, ddsSelectPin); \/\/output\n  SET(DDRA, ddsDataPin); \/\/output\n  SET(DDRA, ddsClockPin); \/\/output\n  \/\/pullups and initial states\n  SET(PORTA, ddsSelectPin); \/\/high = unselected\n  SET(PORTA, ddsClockPin); \/\/high = idle\n}\n\nvoid writeSPI(uint16_t word) {\n  for (uint8_t i = 0; i &lt; 16 ; i++) {\n    if(word &amp; 0x8000) SET(PORTA,ddsDataPin); \/\/bit is 1, set high\n    else CLEAR(PORTA,ddsDataPin); \/\/bit is 0, set low\n    ASM_NOP();\n    CLEAR(PORTA,ddsClockPin); \/\/data is valid on falling edge\n    ASM_NOP();\n    SET(PORTA,ddsClockPin);\n    word = word&lt;&lt;1; \/\/shift left by 1 bit\n  }\nCLEAR(PORTA,ddsDataPin); \/\/idle low\nASM_NOP();\n}\n\nvoid writeDDS() {\n  CLEAR(PORTA, ddsSelectPin); \/\/low = selected\n  ASM_NOP();\n  writeSPI(0x2100); \/\/ enable 16bit words and set reset bit\n  writeSPI(freqLoWord);\n  writeSPI(freqHiWord);\n  writeSPI(0xC000); \/\/ set phase register to zero\n  writeSPI(0x2000); \/\/ clear reset bit =&amp;gt; audio on\n  ASM_NOP();\n  SET(PORTA, ddsSelectPin); \/\/high = deselected\n}\n\nvoid setup(void) {\n  setDDR();\n  writeDDS();\n}\n\nint main(void) {\n  setup();\n  while(1);\n  return 0;\n}\n\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>I bought an AD9833 DDS module from China &#8211; you know the one: I wanted to control it from an Atmel ATtiny and my weapon of choice was the ATtiny44. Now I could just have easily used an ATtiny2313 (both devices are 14-pin), but I didn&#8217;t &#8211; and I went on and built a PCB.\u2026 <span class=\"read-more\"><a href=\"https:\/\/stompville.co.uk\/?p=853\">Read More &raquo;<\/a><\/span><\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,5,6],"tags":[],"_links":{"self":[{"href":"https:\/\/stompville.co.uk\/index.php?rest_route=\/wp\/v2\/posts\/853"}],"collection":[{"href":"https:\/\/stompville.co.uk\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/stompville.co.uk\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/stompville.co.uk\/index.php?rest_route=\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/stompville.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=853"}],"version-history":[{"count":23,"href":"https:\/\/stompville.co.uk\/index.php?rest_route=\/wp\/v2\/posts\/853\/revisions"}],"predecessor-version":[{"id":1402,"href":"https:\/\/stompville.co.uk\/index.php?rest_route=\/wp\/v2\/posts\/853\/revisions\/1402"}],"wp:attachment":[{"href":"https:\/\/stompville.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=853"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/stompville.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=853"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/stompville.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=853"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}