Porting Arduboy2 library to SAMD

Conditionally compiled symbols might complicate third party library development somewhat.

Though admittedly I doubt we’ll see many more sound libraries being developed (at last count we’re on 3.5, including Beep),
so it might be manageable.

It would probably be link time - weak symbols are compiled into the .elf, marked as weak symbols, and then overriden by ‘strong’ symbols at link time.

I have not yet been able to find any definitive information about whether weak symbols can override weak symbols.
I’ve found one source that claims:

if there exists several weak symbols, GCC will choose one that have the largest size (memory occupation).

But as this is an unofficial source (i.e. a blog) I wouldn’t bet on it just yet.

I had a quick look to see if any ELF documentation defined any behaviour,
but the only resource I could find that commented on the subject claimed that the resolution of multiple weak symbols depended on “a variety of factors”.
No other resource I found even touched on what happens when two weak symbols with the same name are defined.
These weren’t small blogs either, they were proper technical references by ARM and by Oracle.

Even after digging through the ARM one a bit more, the best I could find was:

If any non-weak reference remains unsatisfied at the end of the scanning operation, generate an error message.

Which says nothing of what happens to ‘unsatisfied’ weak references, let alone two potentially conflicting weak references.


If the library port does end up using weak handlers (assuming that’s an option),
might I suggest using C++11 attribute syntax for the attributes?
https://en.cppreference.com/w/cpp/language/attributes

Portability might not be a big concern, but you don’t loose anything by being cautious.
(Except maybe causing a few would-be errors to be downgraded to warnings on compilers that don’t support a specified attribute.)

The audio libraries (which is what we’re primarily discussing) all deal with the peripherals directly at the register level, so they’re going to need conditional compiling based on the microprocessor anyway.

If it turns out it can be done at all, I wonder if we could have the Arduboy specify weak and have the other library’s symbol(s) be strong? It’s just to get around the problem of the Arduboy library taking over an interrupt. We only want it to behave the same as it currently does for AVR.

@MLXXXp @Pharap much of this is going over my head and will probably be helpful for future developments, which is fine, but I just wanted to check that you had seen I have audio now working without needing interrupts

1 Like

Yes, I saw it. But that’s only for BeepPin on one pin. For BeepPin support on the DAC capable pin, you’re very likely going to need a timer using an interrupt.

1 Like

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