Loopus Doopus

That’s how it works on TV.

edkost, I would recommend that you take a few steps back and re-review some of the advice and information being offered. GoForSmoke previously posted a link in post #7 which contains information about how the Arduino environment works which is necessary to understand in order to be able to create proper Arduino sketches. He also posted some excerpts from it with some of the very pertinent information about setup() and loop() In post #8 you said you would go off and study it. Nick gave you the information in post #15 on how to properly post code in a forum post. But then in post #16, you not only incorrectly posted your example code but then asked about why you got an error when loop() was removed.

You have not absorbed some of the very basic information related to using the Arduino programming environment and the C/C++ language.

loop() is not a "loop" It is a C++ function that happens to be named loop The only loop in your code from post #16 is this:

while(true);

There are many issues with that code, especially since the code says it is about printing binary digits of a 16 bit value but then uses bits beyond bit 15. (note: 16 bit values don't have a binary digit 16 or 17) All that messy String stuff could be replaced with a simple loop that looks at each bit of the variable using a bitwise AND operation.

I understand that learning new things can take time, but it appears that you are continuing to blaze forward without processing the information being set in front you and taking the time to learn some of the very basics/fundamentals of using Arduino.

At this point, I think you need to focus on the very basics like mastering and understanding how to use the Arduino programming environment and the fundamentals of a basic Arduino sketch.

So far in this thread, you happened to have attracted the attention and gotten responses from a few of the very technically knowledgeable people on the forum. A few more posts like these, and many, including myself, will simply start to ignore your posts

My remaining interest in this thread at this point, which is purely from a curiosity stand point, is, where did that wacky code in post #16 come from?

--- bill

bperrybap:
I do appreciate your attempts to set me straight on my quest to be a decent code writer. Who knows, it may happen.
I did not understand that loop() was not the actual loop. I think I have seen arduino code examples that use it.
The code that you are curious about came from inside my overheated head. I could not find any code or hardware I could buy that also used some included code that provided the functionality I needed. I am sure there are simpler ways to accomplish what I need but I don’t want to spend weeks of time to learn a nicer way to accomplish this one-time function.
The function I need is to output to a parallel port the calculated sin values of 3600 points between 0 and 359.9 degrees inclusive of a sine waveform. This data will be written to an external parallel EEPROM or EPROM. The amplitude granularity needs to be 16 bits and the fine temporal granularity is needed to ultimately produce sine waves of varying frequency with harmonics >90 dB down at frequencies up to 6 kHz with amplitude error <0.05% from 1 Hz-6 kHz. The arduino is not fast enough to calculate and output these values so once the values are output and stored the arduino is out of the picture. Hardware will ‘playback’ the fast EEPROM and process the data to generate the sine waves to the required precision. Simple as that!

loop() functions as a loop just fine and I did include that last example to show one way to use it.

If you need 3600 16-bit values to come out of the Arduino then calculate them on a PC using high precision floats, write that to a text file and compile it into a 7200 byte table in Arduino flash then write them out.

OR -- feed the data from your PC to your Arduino and write that out directly.

"I don't want to spend weeks of time to learn a nicer way to accomplish this one-time function."

What I'm trying to get you to learn shouldn't take weeks unless you only have an hour a week to spend.

Something about people in general, most will spend days farting around to avoid one hour of actual work.

A while back I used a PC to do the same thing in Excel and generate a txt file that I sent to a EPROM programmer. Worked fine. I wanted to try something different this time.
Generating the sin values in the arduino due was easy, even using loops. Here is the code:

void setup() { Serial.begin(9600); } 

const float pi = 3.1415926;
float a = 88.0; //artbitrary value.  Normally would be 0
float b = 0.0;
float c = 0.0;
int d = 0; 

void loop() {
  c = a * pi / 180;
  b = sin(c);
if (a < 90.1)  //arbitrary value.  Normally would be 359.8
{  a = a + .1;
Serial.println(b, 7);  //SIN of variable 'a' in DEG
b = b + 1;
b = b * 32767; 
d = b;  //seems unnecessary
Serial.println(d); }  //SIN offset and scaled to be between 0 and 65534
else
{ return; } }

I expect it is trash code, but it does work and someday if I live long enough (I’m 73 now) I may know why. Now I just have to figure out how to insert each output integer into the horrible code that converts it to a parallel output. Fun.

edkost: I did not understand that loop() was not the actual loop. I think I have seen arduino code examples that use it.

Every arduino sketch will use a loop() function as it is required to use the Arduino environment.

loop() is not a loop. It is a function just like any other function. However, in the Arduino environment, the loop() function gets called over and over again by a loop in the Arduino main() function. You can see the code in main() in post #2 by 6v6gt. The main() function has a for loop that calls loop() over and over again forever.

So while loop() is not a loop, whatever you put in loop will be executed over and over again because main() calls loop() over and over again.

The actual loop that causes loop() to loop is not in loop() but main() as loop() is not a loop.

--- bill

You are showing signs of being stuck in an endless loop.

edkost: I expect it is trash code, but it does work and someday if I live long enough (I'm 73 now) I may know why. Now I just have to figure out how to insert each output integer into the horrible code that converts it to a parallel output. Fun.

Ah, depending on the Arduino, you don't have 3600 x 2 bytes of RAM. The Uno has 2k, for example.

The arduino is not fast enough to calculate and output these values so once the values are output and stored the arduino is out of the picture.

I'm not sure where the Arduino comes into it, in that case. I think people have generated sine waves by pulling numbers out of a table, up to a certain frequency, I can't remember what that was.

See here for example.

Arduino can use 32-bit 6-place floating point values to generate 3 or 4 places results without an FPU eventually if that’s what you want. It’s like using a flat tip screwdriver as a chisel, you can but don’t expect professional results.

Nick: I am using a Due and I think it has 96 kB of SRAM. The sinewave generator you referenced is a PWM system and although it can generate a wide range of sinewaves, or any other waveform, it has high distortion without extensive filtering. I need something rather clean with harmonics at least 90 dB down. A tunable filter that can do the job will be massively complex and also slow in order to operate at 1 Hz and also 6 kHz. Thanks for looking.

So are you planning to push these numbers into a DAC? This is the first time you mentioned those requirements, and that you have a Due.

This is turning into quite the X-Y problem isn’t it? The thread starts with you asking about “why a loop runs continuously” and morphs into generating a sine wave with distortion < 90 db using external hardware.

Not to mention, having the singular most useless thread title I’ve seen in this forum.

Now that we know (we think) that we are trying to generate a sine wave using some sort of hardware, I’ve experimented with making this work. I have a 12-bit DAC (MCP4921) which communicates using SPI. I wired it up thus:

Pin
---
1  Vdd -> +5V
2  /CS -> Arduino D10 (slave select)
3  SCK -> Arduino D13 (SCK)
4  SDI -> Arduino D11 (MOSI)
5  /LDAC -> Gnd (always active)
6 VrefA -> +5V (reference voltage)
7 AVss  -> Gnd
8 VoutA -> Output to scope

I threw in a few decoupling capacitors to try to keep noise down.

Code:

#include <SPI.h>

const byte sine256[256] PROGMEM  = {
  127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,176,178,181,184,187,190,192,195,198,200,203,205,208,210,212,215,217,219,221,223,225,227,229,231,233,234,236,238,239,240,
  242,243,244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,254,254,254,254,253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,240,239,238,236,234,233,231,229,227,225,223,
  221,219,217,215,212,210,208,205,203,200,198,195,192,190,187,184,181,178,176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118,115,111,108,105,102,99,96,93,90,87,84,81,78,
  76,73,70,67,64,62,59,56,54,51,49,46,44,42,39,37,35,33,31,29,27,25,23,21,20,18,16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31,
  33,35,37,39,42,44,46,49,51,54,56,59,62,64,67,70,73,76,78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124

};

byte i;

ISR (TIMER1_COMPA_vect)
  {
  int value = pgm_read_byte (sine256 + i) << 4;
  PORTB &= ~bit (2);  // SS <- LOW
  SPI.transfer (0b00110000 | (value >> 8));  // high order 4 bits
  SPI.transfer (value);  // low order bits
  PORTB |=  bit (2);  // SS <- HIGH
  i++;
  }


void setup ()
  {
  SPI.begin ();
  SPI.setClockDivider(SPI_CLOCK_DIV2);

  TCCR1A = 0;
  TCCR1B = 0;
  TCCR1C = 0;
  
  OCR1A = 239;
  TCCR1B = bit (WGM12) | bit (CS10);  // CTC, prescaler of 1
  TIMSK1 = bit (OCIE1A);
  }  // end of setup



void loop ()
  {
  OCR1A = analogRead (0);  // alter frequency
  }  // end of loop

This uses the sine table from Arduino DDS sine wave generator.

The results seem reasonable (see attachments).

DAC_example.png

The distortion seems to be around -51 dB.

DAC_example2.png

However, the maximum frequency I can get is quite low (around 270 Hz). Why is this?

Well, in the ISR I push out to the DAC the next value in the table of sine wave values. Currently this is a 256-byte table, so the output is really only 8-bit resolution.

The time taken to enter the ISR, retrieve something from the table, output it to the DAC using 2 x SPI.transfer, and then leave the ISR, works out to around 15 µs.

Therefore we can only output one part of the sine wave every 15 µs, and it takes 256 of them to complete one cycle. Thus it will take 15 * 256 = 3.84 ms to send one cycle. Taking the inverse, that is only 260 Hz.

You have somewhat harder requirements. You want 16 bit audio, which means sending 65536 numbers to the DAC (256 times as many) per cycle and you want to go up to 6 kHz (which is 23 times the frequency I could get). Now I know the Due has a faster processor, but it isn’t that much faster (not 5888 times as fast!).

No doubt there are ways of achieving this, but you may need to do a bit of research to find the best one.

If you just want to generate the table with the Arduino (and nothing else) you could just do it with a spreadsheet, or a simple C program on your PC.

How does it look when you use every other data point to get twice the frequency?

Is there any kind of burst mode read you get from the EEPROM, like you can with SD? Then the fetch could fill a buffer same as when playing WAV audio.

Aren't there circuits that generate acceptable sine waves?

How does it look when you use every other data point to get twice the frequency?

It’s not too bad:

DAC_example3.png

How about every fourth sample?

DAC_example4.png

Starting to look a bit chunky.


Is there any kind of burst mode read you get from the EEPROM, like you can with SD?

This was PROGMEM. No.

Aren’t there circuits that generate acceptable sine waves?

Probably.

I know that rotating fields can be generated from fixed coils, the fields have a kind of inertia of their own so out on a fantasy branch here suppose that many small coils with a linear Hall sensor at center might have a chance of generating smooth sine waves.. though at some speed I bet it would get hot.

[quote author=Nick Gammon link=msg=2664002 date=1458017234]You want 16 bit audio, which means sending 65536 numbers to the DAC (256 times as many) per cycle and you want to go up to 6 kHz (which is 23 times the frequency I could get). [/quote]

Not correct. The sample rate depends on the maximum output frequency. According ot Mr. Nyquist, at 6kHz, he needs to send at least 12,000 samples per second to achieve that. Even using an audio-quality D/A, he only needs to send 48,000 samples per second, which can be done even on an AVR-based board if it's not doing much else, and the interface is fast enough.

Regards, Ray L.

I was just going by what the OP said:

edkost:
The function I need is to output to a parallel port the calculated sin values of 3600 points between 0 and 359.9 degrees inclusive of a sine waveform. This data will be written to an external parallel EEPROM or EPROM. The amplitude granularity needs to be 16 bits and the fine temporal granularity is needed to ultimately produce sine waves of varying frequency with harmonics >90 dB down at frequencies up to 6 kHz with amplitude error <0.05% from 1 Hz-6 kHz.

He wants to (whether he needs to is another issue) send 3600 points.