Maths calculation for creating Hex values to control a DDS AD9835 Sine Wave Generator

Hi all, i follow the forum most days, and have learned a huge amount from all the contributors. thank you all.
I have a Sparkfun DDS module from a few years back , , however there are others types/ styles available from multiple sources.
The AD9835 module is working on an arduino with a few different sketches i have found/modified and i also have it working with an IMP001 on a breadboard. My question relates to the Maths conversion required to send from the IMP to the Module to create the desired frequency output.
I an currently calculating the required Hex values on a PC, and then passing them into the code manually, ( it can be done using the windows calculator, i have also written a small EXCEL file), whereby i enter the desired output frequency, and the spreadsheet gives the required values.
For example, if i wanted a sine wave output frequency of say 32768hz, the required Hex value required is 0x00, 0x2A, 0x2A,1E.
The conversion is as follows,
multiply the frequency by (2 to the power of 32), or frequency by 4294967296.
this then becomes 32768 X 4294967296 = 140,737,488,355,328
Divide the above number by the Master clock frequency of the module, in this case on the AD9835 module is 50,000,000 hz.
This then becomes 140,737,488,355,328/50,000,000 which produces 2814749.76710656
Round this number to 28147450, and then convert to a Hex value becomes 2AF31E.
The module requires 4 hex values to program correctly, so the values are padded with 0 if required, so the above hex number becomes 002AF31E, and the 4 values that i require become 0x00, 0x2A, 0xF3,0x1E. If i load the 4 hex values into the imp code i have, i get a 32768 sine wave output from the module, so i know it works.
Please note that i have not posted any imp code, but can do so if anyone wants to see it or use it, my question relates to whether or not i may be able to do the maths conversion on the imp,such that i will somehow be able to enter on the imp, via ( keypad, Phone APP, ?) the required frequency, and the imp will calculate the correct Hex values i need and then load them into code.
Thank you all if anyone has any suggestions, TOM.

This shouldn’t be hard, but you likely want to tweak the multiplication to ensure accuracy, as floats are 32 bits on the imp and multiplying up the dividing down could lose precision.

As you are dividing by 50,000,000 then multiplying by 4,294,967,296 we can simplify this to a multiplication of (4,294,967,296 / 50,000,000) = 85.89934592. You can do this calculation on the imp or in the agent, but it seems most sensible to do it on the imp as then your agent doesn’t need to know anything about the details of the hardware registers involved.

In the following code I’m creating a binary string “bytes” which has the 32 bit value in big-endian order (MSB byte first), then printing it (vs sending it to the device as you already have code for that).

const multiplier = 85.89934592;
local desired = 32768;
local fdiv = ((desired * multiplier) + 0.5).tointeger(); // round up before going to integrer
local bytes = format("%c%c%c%c", fdiv>>24, fdiv>>16, fdiv>>8, fdiv);
server.log(bytes); // IDE will log the raw binary

This logs the bytes you’re looking for:

2019-04-07T18:41:35.812 -07:00	[Device]	binary: 00 2a f3 1e

Thank you Hugo, that will work for what i am after. In reference to the precision , by my windows calculations for say a 1,Mhz sine wave ( i need the following hex values 0x05, 0x1e, 0xb8, 0x52).
That should give a theoretical output of 1,000,000.001 hz.
On the imp, the above conversion you provided gives ( 0x05, 0x1e, 0xb8, 0x50). If i back convert the imp calculation, that returns a theoretical output of 999,999.9776 ( pretty close).
If i now load both the above values into the sparkfun module,with my imp code, on a breadboard with a ratsnest of hookup wires, with my old uncalibrated frequency counter, i am recording an output of 999,999 or sometimes 999,998 , so am pleased with the results. Thank you.


As the frequencies get larger, you’re seeing the result of truncation from single-precision floating point here - the 85.89934592 is actually being stored as 85.89934540-ish in IEEE754 format - which accounts for the difference in the calculation. See to see how exactly this is working.

If the extra resolution was important for your application, you can certainly write code to do this with more precision though at a significant performance penalty; we’ve been working with some customers on options here for higher precision support on the agent side but nothing to announce at this point.