Go Down

Topic: Arduino DDS Sinewave Generator (Read 77176 times) previous topic - next topic

koldby

#90
Nov 12, 2019, 01:57 pm Last Edit: Nov 12, 2019, 02:03 pm by koldby
45-150 is in the interval 0-1025 - what's the problem?
If you can't do the simple arithmetic, use the "map()" function.

Code: [Select]
int ledPin = 13;                 // LED pin 7 What's that?

Code: [Select]
PROGMEM const byte sine256[] = Remind me again what you wrote about in reply #86?

Now do you see why we ask you to post your code?
Otherwise, it's just time-wasting - like I said, noobs make inadvertent errors.
 I'm sorry if that offends you, but that's how it is.
I f you look closely , you will see that it was NOT the problem. I did NOT make any errors in the code and I DID say that it compiled correctly. The only error I made , was when I explained what I did , so the code worked, noob or not, no errors in my code. It would´t have compiled then would it ??????

My question at that time, after I , without any help, had solved the problems in the original code, was how to change the frequency range.
And if you do not understand why I want to do that, I am sorry for you. Of course it is included in 0-1023 Hz.
It would also be included in 0-10 Mhz but that would worsen the situation (hint).....

I do not know what the line:
Code: [Select]
int ledPin = 13;                 // LED pin 7 What's that?

is, but it is in the original code..
Again I have NOT changed anything in the original code , except for the line I have already mentioned...


TheMemberFormerlyKnownAsAWOL

#91
Nov 12, 2019, 02:24 pm Last Edit: Nov 12, 2019, 02:33 pm by TheMemberFormerlyKnownAsAWOL
Let's have a little game of spot-the-difference, shall we?

A little "If you look closely", if you will...

From your reply #75
Quote
the line:

PROGMEM  prog_uchar sine256[]  = {

Should be:

PROGMEM  prog_uchar sine256[]  =
{
And now the code from the code you attached (Lord knows why; you could have posted it)
Code: [Select]
PROGMEM const byte sine256[] =

Like I said, noobs make mistakes, and don't realise how a simple transcription error can cause so many problems and misunderstanding.

I genuinely do not understand why you cannot use the map function to change the frequency range.

Quote
It would also be included in 0-10 Mhz but that would worsen the situation (hint).....
Using a cheap, simple DDS device like an AD9850, you could handle that entire range (and more) with better than Hz/20 resolution.
Please don't PM technical questions - post them on the forum, then everyone benefits/suffers equally

koldby

You are really slow , are you not? The only error I made was in the post where I explained what I had done. That was a typo. NOT IN THE CODE!

And , I do know you have to be careful, when you type , I was raised with DOS computers...

As I said, I was uncertain if it was the right procedure to attach the code or just include it in the text. A long code would take up a lot of space if it was just included in the text, but, no problem , I will include it in the text, if there ever will be a next time.

Maybe I can use the map() funktion, but I am not familiar with it and I would have to look into it to see how it works.
I thought maybe there could be an easier way. For instance changing the "initial output frequency"  dfreq as this is used to calculate the new frequency:
 dfreq=1000.0;                    // initial output frequency = 1000.o Hz
  tword_m=pow(2,32)*dfreq/refclk;  // calulate DDS new tuning word

TheMemberFormerlyKnownAsAWOL

Maybe I can use the map() funktion, but I am not familiar with it and I would have to look into it to see how it works.

...which is why I provided you with a useful link to the reference.

Quote
I was raised with DOS computers..
Like I said, a noob.
Please don't PM technical questions - post them on the forum, then everyone benefits/suffers equally

koldby

Oh yes I am a noob when it comes to Arduino stuff, as I have said before, no doubt about that.

Apparently the map() function is not precise enough for my purpose.

koldby

Never mind. I cannot use this Sine wave generator. It is not stable enough. It jumps in frequency, even with a two resistor divider at the input (analog 0) and a very low noise PS (LifePo4 batteries). Even my dirty old Heathkit signal generator is more stable that this. And it is nut drift, it si jumping, rather randomly, you can even see it on a scope.

Thanks for help and support.

cattledog

Code: [Select]
//dfreq=analogRead(0);
dfreq = 100;


If you replace this analogRead() line with a fixed value is the output stable?

TheMemberFormerlyKnownAsAWOL

Never mind. I cannot use this Sine wave generator. It is not stable enough. It jumps in frequency, even with a two resistor divider at the input (analog 0) and a very low noise PS (LifePo4 batteries). Even my dirty old Heathkit signal generator is more stable that this. And it is nut drift, it si jumping, rather randomly, you can even see it on a scope.

Thanks for help and support.
The Analog Devices DDS devices will show your antique Heathkit what stability is all about.
Please don't PM technical questions - post them on the forum, then everyone benefits/suffers equally

koldby

Code: [Select]
//dfreq=analogRead(0);
dfreq = 100;


If you replace this analogRead() line with a fixed value is the output stable?
Good point! Thanks...
Yes the output is a rockstable 100 Hz.
So the conclusion must be, as far as I can see it, either the voltage divider is not steady enough or the "analogRead" function is not steady enough. I have measured the voltage with a pretty precise VDM and did not see any correlated jump in the voltage @ analog 0 input. The pin is decoupled with a 10uF , so noise should not be an issue either...

Thanks for the positive and helpful input

ivconic

#99
May 17, 2020, 04:30 pm Last Edit: May 17, 2020, 04:49 pm by ivconic
I made it, applied suggested filter.
But i need frequency range 7-14kHz.
So i noticed certain hums and interferences above 2-3kHz.
How to additionaly clen up this signal?
Here is short video with signal at 8kHz:
https://www.youtube.com/watch?v=tthFA1mXV0Q&feature=youtu.be

MarkT

Well there's an obvious problem in the updating of the tuning word:
Code: [Select]

      cbi (TIMSK2,TOIE2);              // disble Timer2 Interrupt
      tword_m=pow(2,32)*dfreq/refclk;  // calulate DDS new tuning word
      sbi (TIMSK2,TOIE2);              // enable Timer2 Interrupt

The vital interrupt is disabled far too long - floats are very slow on an 8-bit microcontroller.
Also interrupts are being chucked away - you must use the global interrupt flag for critical sections.

This is  what should be happening:

Code: [Select]

      unsigned long new_tword = pow(2,32)*dfreq/refclk;  // calulate DDS new tuning word
      noInterrupts();   // enter critical section for the minimum time possible
      tword_m = new_tword ;
      interrupts();


Incidentally there is _no_ difference between
Code: [Select]

PROGMEM const byte sine256[] = {

and
Code: [Select]

PROGMEM const byte sine256[] =
{
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

ivconic

#101
May 18, 2020, 03:13 pm Last Edit: May 18, 2020, 03:14 pm by ivconic
No. Those modifications leads to no out from Atmega at all.
Original code works, i found out i made mistake, corrected it and now is alright.
Now i have second "problem".
From 100Hz up till approx 6kHZ oscilogrames are splendid and with thin lines.
But above 6khZ until 14kHz i stil getting perfect sinus but with fat lines.
14kHZ  diplayed on osciloscope with fat (multiple close together) lines.
This directly means: jitters!
I guess problem lays in "int sine256" table.
Generation is not cyclostatic.
See short video here:
https://www.youtube.com/watch?v=dPNGCZALCCI

MarkT

I'm still right about the interrupts - you will risk losng interrupts if you enable/disable a specific interrupt
channel, rather than using the global interrupt flag. 

The global interrupt flag suspends handling of interrupts (but does not cancel them), whereas specific
flags suspend _generation_ of interrupts, allowing a timer event to be skipped if the timing is unfortunate.

You cannot expect perfect traces from the DDS method unless you filter out everything above the Nyquist
frequency - the steppiness will be visible, but only has components above Nyquist.  A spectrum analyzer is a
much more revealing tool for this sort of signal - DDS signals are very clean below Nyquist.

I've also noticed in setup():
Code: [Select]
  // disable interrupts to avoid timing distortion
  cbi (TIMSK0,TOIE0);              // disable Timer0 !!! delay() is now not available
  sbi (TIMSK2,TOIE2);              // enable Timer2 Interrupt

  dfreq=1000.0;                    // initial output frequency = 1000.o Hz
  tword_m=pow(2,32)*dfreq/refclk;  // calulate DDS new tuning word

the enabling of Timer2 interrupts should happen _after_ dfreq & tword_m are initialized, not before...
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

MarkT

I had a play with the code, slight adaptions required as a Mega2560 was to hand, but I proved to myself that
the line
Code: [Select]

  tword_m=pow(2,32)*dfreq/refclk;  // calulate DDS new tuning word

is definitely a problem, as the calculation takes about 40us or more, so you lose interrupts anyway.

Using this fixed the problem:
Code: [Select]

      unsigned long my_tword_m=pow(2,32)*dfreq/refclk;  // calulate DDS new tuning word
      noInterrupts() ;
      tword_m = my_tword_m;  // calulate DDS new tuning word
      interrupts() ;


Before the fix 4kHz tone came out with lots of jitter/phase noise like this:


And after:



Trying 14kHz seemed clean enough, although a few more spurs higher up in frequency anyway:


All these spectra are zoomed in to 500Hz span and at 1Hz resolution, so would readily see even tiny jitter
issues.
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

Go Up