I've made a bitbang based square wave synthesizer library, which works at around the same range as the tone() function but with more options. (noise generation, variable duty cycles, pitch selection in MIDI values, arpeggio, pitchbend).
It's all well and good, but in order for it to work, I have to have a generate() function nested in loop() so it is called constantly without interruption. I'll attach the library and a larger example below, but here's the bones of what is required:
I think that we should start with the fallacy in your thread title. The Arduino is a single threaded processor. There is no background.
You could use a timer to generate an interrupt at whatever frequency you need, and have the interrupt service routine call generate(). The problem with that, though, is that which instance's generate() method should it call?
You could have a static method that manages that, by calling all instance's generate() method, but then you'd need a static method for each instance to call to register that it needed to have it's generate() method called (or was no longer interested in having its generate() method called).
The timer doesn't operate in the background. It happens because of interrupts, which interrupt the normal flow of your program. The operate not in addition to (in the background) what your program is doing, but instead of what your program is doing.
Ultimately it would make more sense to code the library up as interrupt driven
at its core, so it can select what frequency to be interrupted. Have a look at
other examples where people have coded function generators using the Arduino.
Thanks! I'll look into how to implement interrupts this evening.
But one other question:
earlier, I noticed while debugging with the Serial.print() function that the frequency of the generated notes were lower than when I ran the library without Serial communication. If I remember correctly, the arduino's serial communication library uses interrupts?
If I make my library interrupt driven, will there be an increase or decrease of performance alongside these other interrupt driven libraries? Or will there be no difference?
other interrupts will be ignored (turned off) until the current one is finished. as delay() and millis() both rely on interrupts, they will not work while an ISR is running. delayMicroseconds(), which does not rely on interrupts, will work as expected.
Does this mean micros() is also unaffected? If so, the interrupts should have no adverse affects.
If I remember correctly, the arduino's serial communication library uses interrupts?
Yes, it does.
If I make my library interrupt driven, will there be an increase or decrease of performance alongside these other interrupt driven libraries? Or will there be no difference?
Interrupts take time. Of course there will be an impact to the program that is running (and other interrupt based functionality).
Does this mean micros() is also unaffected? If so, the interrupts should have no adverse affects.
micros() continues to accrue time while an ISR is running. That does not validate your conclusion. Any ISR will have an impact. How big depends on how often the interrupt happens, and what happens in the ISR.
Hmn, okay. As the library's coded now, the waveforms are generated by referencing pre-calculated wavelengths in microseconds. I've been looking ISRs, and there are a lot of variables for me to take into consideration. This is the most information I've been able to find in one place about them: Gammon Forum : Electronics : Microprocessors : Interrupts
While I can afford to be a little off in the sound generation, the more accurate the better. Depending on how the library's going to be used, nesting generate() in a loop may or may not be more useful than using an interrupt, depending on what else is being run. So the implementation is going to be optional, I think. Maybe an additional setup function like
At the moment I'm looking at the SoftPWM library for some inspiration as to how I should use a time based interrupt, or whatever else they use.
At some point, I'm probably going to add some more functions and/or effects to turn this into a full-on chiptune library, so i'm thinking there may be a preference for generate()s inside some sequenced while() loops.
The more I learn about timer interrupts, the steeper the learning curve begins to look. Sure, I could implement interrupts for the UNO no problem, but what about other chips which use different timers and instructions? SoftPWM's library uses a lot of tightly woven macros stuff to determine what timing code should be used for each chip at compile time. I'd use attachInterrupt(), but it doesn't support a time based event. To put things in perspective, last weekend was the first time I've used OOP.