Porting Arduboy2 library to SAMD

If ‘the other library’ is another sound library, then ‘the other library’ is likely to have all strong symbols as it’s the default,
and it’s unlikely another library would have the same idea of declaring its symbols as weak.

Ultimately though, being able to control the interrupt vector at runtime would be better because it would be possible to check the existing value and react accordingly.


A random thought:

If it’s at all necessary for the library user to be able to alter the pins used by the library, templates would probably be the best solution.

E.g.

struct DefaultSettings
{
// Specify pins and the like
};

template<typename Settings>
class Implementation;

using API = Implementation<DefaultSettings>;

I admit, I did actually miss that part.
I only skimmed your comment because I was multitasking.
(And one of those tasks was playing Elite Dangerous. :P)

Unfortunately I have absolutely no way of verifying if your code is correct.
I could probably check that it compiles if I set up the Arduino IDE to do so,
but I wouldn’t be able to test it.

As @MLXXXp says though, Beep or no Beep,
interrupts are likely to rear their ugly heads at some point.

Yes, especially as it appears from reading the SAMD21 datasheet that the events system can’t set pin outputs as event users (ie you can’t toggle a pin based on e.g. a timer event in the events system). On the ATtiny 0 and 1 series they let you do this, so it seems strange that it’s not an option for a more feature rich microcontroller.

1 Like

Yes, I kind of leaning it this direction as well.

1 Like

I have spent a couple of evenings looking at the events system again on SAMD21. There’s a slim chance I can make the DAC output a square wave with the only recourse to an interrupt handler being required in a DAC interrupt. It may be possible for the events system to trigger a DAC “conversion” (aka write voltage to pin) as a consequence of a timer overflowing. But no interrupt handler is required at this stage. However, the DAC can generate an event when it’s DATABUF register (where your value to be written to the pin - HIGH or LOW in our case - is loaded from into the DATA register that is what is converted to the pin voltage) is empty. If we then generate an interrupt from the DATABUF empty and then use the interrupt handler to load the inverse of the last value converted to the pin into DATABUF before the next time TC5 overflows, we’re laughing.

But in case that doesn’t work or no-one on AVRfreaks helps me over the line, shall we discuss which timer we’d pick for Speaker2? TCC0 and TCC1 are especially useful for PWM (@MLXXXp sensibly suggested reserving TCC1 for RGB LEDs) and I think I’ve nabbed TCC0 for the original waveform out, so shall we pick from TC3, TC4 and TC5? Bearing in mind that TC5 is already the Arduino SAMD21 Tones library timer.

Are you saying you will need to use the DAC interrupt, or you can do it with no interrupts at all? If you need an interrupt, you may as well use a timer interrupt and just toggle the speaker pin digitally in the ISR, instead of using the DAC at all.

Once you need any interrupt, you run into the problem with interrupts that we have been discussing. Assuming it’s the same as with AVR (which hasn’t been entirely determined), if you use a timer interrupt then no other libraries can use that timer with that interrupt. If you use the DAC interrupt then no other libraries can use the DAC with its interrupt.

Hence the previous discussion of ways to get around the problem.

1 Like

Yes. My thinking is that others who are using SAMD based Arduboy-compatible (and using Arduboy2 until someone ports another library) are less likely to be using a DAC interrupt than they are to be using a timer interrupt. So I was aiming to reduce the likelihood of clashes/conflicts.

The other thing that using the DAC interrupt may help with is quickly loading DAC values from a sound buffer, such as a look up table for alternative waveforms to make new sound effects. I’m new to all of this but it would be a very simple call in an interrupt handler to increment an index and load a value from an array into the DAC DATABUF register (which is then used as the basis of conversion the next time the timer event occurs). This could be done in the timer ISR and just by using a timer you have to reserve it (at least temporarily) for audio use so it’s by no means perfect.

Like I said before, my philosophy for Arduboy2 is to not take over any interrupts. If you need to use an interrupt then a separate independent library should be created to support that feature (such as my removing the Playtune code that was in the original Arduboy library and turning it into the ArduboyPlaytune library).

I added the BeepPin classes to allow simple sounds that produced a bare minimum of code, with the convenience of not having to include another library, only because they don’t require interrupts.

Unfortunately, the port to SAMD with the current hardware design makes it difficult to follow this rule.

Thinking about this…
I don’t believe the SAMD hardware design is “cast in stone” yet. It may be possible to assign a third pin to the speaker. That pin would be one that had WO capability from a timer different from that used for PA15 (and preferably one that could also run with a timer WO complimentary to that on PA15). This new pin and the DAC pin (PA02) could both be wired to the same speaker pin through a series resistor on each. (The resistors are for protection in case both pins were set as outputs at the same time, and even possibly to allow simple mixing).

The higher level we go the more abstract we can get. A SAMD21 or D51 is an entirely different ballpark than a Amtel 32u4… lets make sure we aren’t still applying the thinking we used to design a library for a 2kb RAM/32kb ROM devices in 20 years when we’re building the Arduboy 54 with 56 terabytes and a quadrillion HZ CPU. :wink:

I think the more powerful the hardware gets the less likely someone is to NEED to access it at the lowest-level possible - and also the harder it becomes to do so - since it gets more and more complex.

You can hot swap interrupts on AVR too with a jump table based approach, but the compiler doesn’t make any of that easy to do.

Just some food for thought.

1 Like

Agreed. But we must also keep in mind that the goal here (at least mine) is to design new hardware and port the Arduboy libraries such that little or no modifications are required to recompile and run existing 32U4 based Arduboy sketches. And even with greatly increased resources, it can’t hurt to strive for elegance and efficiency.

I like this recently published, somewhat related article:

1 Like

Sure. Sounds fine. But doesn’t mean that with MUCH faster hardware the abstraction could get crazy deep… all the way up to our own emulator as an example. What’s important is that games run “as-is” (or in this case as written) not how it uses interrupts or HTML or XML or SVG - or whether it’s JS or Dart or WebAssembly. :slight_smile:

I could imagine (not saying we should) a SAMD51 version that’s designed around a micro-kernel and interrupts and all sorts of crazy thing magic… it could even do live flashing, literally play TWO games at once (just a crazy idea, not sure the utility of that), etc… you could do all that without changing the API one bit. :slight_smile:

Actually an example you could run a EEPROM editor side by side with a game and do “live hacking” of the data. :slight_smile:

How does one take advantage of the actual new hardware then? A new SAMD only library? Or really “bigger games” (more assets) is most of what we’re imagining - but of course they wouldn’t compile for the original Arduboy (or they would compile but would trigger the size warning and couldn’t be loaded).

At the moment I’m only imagining “a SAMD device that runs Arduboy2 games after simple recompile of existing code with no editing”.

(Obviously minus the games that use AVR-specific features for whatever reason - e.g. the few games that use an interrupt to drive custom-made bytebeat sound.)

If the SAMD chip eventually becomes “Arduboy 2.0/2.5/3.0” then a new library will probably be introduced,
but for now I think that’s beyond the scope of this project.

I can only speak for myself of course, this is first and foremost @SimonMerrett’s project.

1 Like

I want to be able to easily compile and run the hundreds of existing games for the Arduboy. The libraries can be extended (conditionally if necessary) for games targeted for the new hardware. These new games don’t necessarily need to run on the original Arduboy.

1 Like

BUT, will there be a “Turbo” button???

Well that’s kind of you to say but really my project is the HW and this is a means to an end. I don’t want to put effort into the port for it only to run on one device and no-one else could easily benefit, so the discussion about these things is useful.

Most definitely not. I was just following your lead. The DAC pin is a totally logical choice. But I didn’t know you weren’t keen on interrupt handlers at the time and I hadn’t read the datasheet anything like as thoroughly as I have now. I think a GPIO linked to a W/O would be fine. But I don’t know that

would put many people off using Arduboy2 if it conditionally used interrupts for SAMD21s and 51s. As pure speculation, I think you might find some people, were SAMD-based consoles to take off, feeling limited if the DAC were not routed/routable to the speaker pin.

I can follow this.

Is there any way of “mixing” two tone waveforms in software (conditionally for SAMD devices) and outputting on a single hardware pin? I have asked about the RAMP mode here for this reason.


On the other hand, we could just skip straight to the SAMD51 with its unique combination of a DAC and TC W/O on the same pin…

1 Like

For a 48 pin SAMD21, based on my initial wiring, I would move SD CS to PB02 (Arduino A5) then use PA14 for the new speaker pin. This would give:

Speaker 1* PA15 TC3/WO[1] or TCC0/WO[5]
Speaker 2* PA14 TC3/WO[0] or TCC0/WO[4]

*Since the two pins are “symetrical” we could call PA14 Speaker 1 and PA15 Speaker 2 but I think the one we call Speaker 2 should be the one that the DAC is also on.

For the BeepPin classes, one pin could use TC3 and the other could use TCC0. Since both pins using either timer are WO capable, no interrupts would be required.

The ArduboyTones library, that needs to generate complimenary outputs on the two pins for high volume, could use either TC3 for both pins or TCC0 for both (to be discussed).

ArduboyPlaytune would use both timers for its two channels.

ATMlib and ArdVoice could use the DAC, since they both currently use PWM as a DAC.

If you do that, you don’t get the capability of a higher volume by having one pin high when the other is low.

You have to understand that you can’t get anything but full high or low signals from a digital pin. You can’t get a triangle, sawtooth or anything else except square/rectangular from anything but the DAC. Other waveforms can be produced digitally using PWM with low pass filtering but the pin still toggles from fully on to fully off. Also the DAC pin has to be set as either the DAC output or as a digital output, not both at the same time.

You should have picked up by now that this has been my plan since before you started this topic :wink:

1 Like

Short reply as I’m on my phone. So we’re moving along nicely. I’ve still got questions about the concept of operation for Speaker2 but nothing that’s a show-stopper.

I feel like a rough BoM for the (my) next HW revision is needed soon. But before that, I need a screen. I can’t settle with the idea of the SSD1306 0.96" screens being paired with the SAMD51. The LCD I have tried in my first version HW is lovely and large and is daylight readable with adjustable back-light. But I don’t think the ghosting will be ever good enough.

Mr.Blinky recommended a couple of displays on my HW WIP thread but neither of them seem big enough (admittedly not seen them in person). I can live with few pixels but I want to be able to see them! Any more ideas for screens? Happy to start a new thread or have posts about HW choices broken out into one?

I’ve already said, I’d like to see the exact same 1.3" SSD1306 OLED display fitted to a board that would fit in the existing Arduboy case and reuse many of the existing Arduboy components.

And again, my goal is mainly to provide more flash and RAM, and a Micro-SD slot to allow more than one game without needing to upload. Anything else is just a bonus.

Sounds good. What about having those two on opposite piezo terminals, calling them Speaker0 and Speaker1. That way, Speaker1 is still usable on it’s own, with Speaker0 just set LOW at init for single volume activity. I thought that Speaker 2 on DAC should also connect to the same piezo terminal as Speaker0.

I was hoping you could achieve a volume reducing effect by generating square wave tones with Speaker1 pin but then raising DAC to a set voltage to reduce the peak voltage difference between each piezo terminal. But I think that the overall Vpp is the same and all you’re doing is making it appear AC wrt the DAC pin.

Do you think the cap is necessary in series with the piezo?image

The names are arbitrary but I think they should continue be referenced as Speaker 1 and Speaker 2 to match the BeepPin1 and BeepPin2 classes. For now, I’m calling the DAC connection Speaker DAC.

Speaker 1 and Speaker 2 should go on opposite speaker terminals so you can get the higher volume by complimenting the two outputs, and to match the existing Arduboy wiring. (That’s why it’s good to have at least one timer common to both pins but with a different WOx for each, to allow making use of the ability to invert one WO.) For normal volume you leave one pin low while generating the sound on the other. For mixing two digital sounds you just play a different sound on each pin.

The values for the resistors and capacitor in the diagram are subject to change.

SAMD21_speaker

To use the DAC, you set Speaker DAC as an output and Speaker 1 as an output and hold it low. You set Speaker 2 as an input so it’s high impedance and thus doesn’t interfere with anything. (Likewise, when the DAC isn’t being used Speaker DAC must be set as an input and Speaker 2 as an output.)

You can also mix a digital sound with the DAC output by playing that digital sound on Speaker 1 instead of holding it low.

Using the two resistors as a mixer or volume control is something that would have to be experimented with. It would depend on the value of the resistors and the impedance of the speaker. We would also have to keep in mind that setting Speaker 2 and Speaker DAC both as outputs would “waste” power through the resistors whenever the these two pins weren’t at the same voltage.


Another thing to consider is that the way the Arduboy 2 library handles muting of the sound when you use the audio.off() and audio.on() functions is it sets both pins as inputs. The BeepPin classes rely on this. From the library’s BeepPin documentation:

Although there’s no specific code to handle mute control, the Arduboy2Audio class will work since it has code to mute sound by setting the speaker pins to input mode and unmute by setting the pins as outputs. The BeepPin1 class doesn’t interfere with this operation.

With this new circuitry, the Arduboy2Audio function will have to make sure that Speaker DAC pin is also set as an input, in order for the mute functionality to work properly. It actually gets complicated because when you unmute, (along with Speaker 1,) you only want to set either Speaker 2 or Speaker DAC as an output, not both (for the “lower volume” and “wasted power” reason described above). I don’t know how you would determine which of the two to set as an output. Perhaps:

  • Save the unmuted state of the pins in EEPROM before muting, and restore to unmute?
  • Maybe we need the capability to mute/unmute the DAC separately from the existing digital mute?
  • Maybe we can get away with only setting Speaker 1 to input mode and not touch Speaker 2 and Speaker DAC? The Arduboy2 bootPins() function would set Speaker 2 to output and Speaker DAC to input. Anything wanting to use the DAC would first have to set Speaker 2 to input and Speaker DAC to output. If this works properly, it’s probably the best solution.

Note that some (all?) of the additional audio libraries targeted towards the Arduboy handle muting properly, by querying the state maintained by the Arduboy2 audio class and actually ceasing to generate sound. They don’t rely on the audio class controlling the input/output state of the pins (but it doesn’t affect them).


Not really. In fact, the Arduboy as shipped doesn’t have a cap at position C12. It has a 220 ohm resistor. (Why a resistor instead of a zero ohm resistor/jumper, and why 220 ohms? I’m not sure. I’ve never asked or seen a reason.)

However, for piezo speakers its usually recommended that you don’t impose a DC voltage on them. Without a cap, this is what happens when generating sounds using only one pin because one pin will always be positive (or at zero volts) with respect to the other.

The reason for not putting DC on a piezo isn’t because it could cause damage (as long as you stay within the maximum voltage rating). It’s because DC will constantly deform the speaker in one direction, thus lowering the volume/efficiency. At the low voltage that we’re running the speaker at it probably doesn’t make much of a difference, though. (It’s another thing that could be determined by experimentation.)


One more thing:
The I/O pin outputs of the SAMD21 have nowhere near the 40mA sink/source current capability of the ATmega32U4. SAMD21 outputs can be set for 2 modes; low drive strength and high drive strength. At 3.3V, the low strength (which is the default) is specified to be able to source 2mA and sink 3mA. High strength is specified to source/sink 7mA/10mA. The reason to have a low drive strength is to produce slower rise and fall slew rates, thus reducing electrical noise emmisions.

For the speaker, we likely want to set the outputs for high drive strength. (The same may be true for driving LEDs)

2 Likes