Porting Arduboy2 library to SAMD

I couldn’t remember offhand what it already included,
what I knew was that you’d need Arduboy2Core.h to get access to the ARDUBOY_SAMD define.

If you’re sticking with the using Sprites = SpritesB; approach then all the functions in Sprites.cpp would also have to be placed in an AVR-specific conditional block.

(I will admit, one thing I’m mildly concerned about is whether or not Sprites and SpritesB being two distinct types (i.e. std::is_same<Sprites, SpritesB>::value is false) is important,
but if it turns out that their distinctness is important I know of an easy solution.)

Don’t worry about what gets used most frequently yet.
Start by worrying about the minimum you can get working whilst confirming that your tests are working.

I’d recommend you start by getting the LED working because that’s a nice, simple interface that can communicate success and errors (e.g. green for ‘success’, red for ‘failure’, other colours for more specific failures).

After the LED is working, move onto the buttons, that gives you a nice “press button, get light” test.
After that you’d move on to the more complex stuff like the screen and sound.

If I think of anything later I’ll add it, though I probably won’t add anything today.


The problem with that is then to maintain backwards compatibility the constexpr variables would have to stay in MACRO_CASE and that violates the principle of least astonishment (not to mention the advice of pretty much every decent C++ style guide).

1 Like

Well, you could do something like
#define EEPROM_STORAGE_SPACE_START EEPROMstorageSpaceStart
to still get the error detection and other benefits of using constexpr. New sketches could use the constexpr name directly.

1 Like

This is Adafruit’s port of the Arduboy2 Library, used for the Pygamer, which uses an SAMD51 (I believe is an M4 Express SAMD51 or something).

1 Like

For some reason I expected you to be opposed to that approach.
(Perhaps because it effectively doubles the amount of symbols that need to be maintained.)

If all the macros were displaced into a 'compat.h` header then it possibly wouldn’t be too much clutter.


Specifically it’s an ATSAMD51J19.

I admit I had almost forgotten about that.

@GlitchJomo thanks. I remember looking at that several months ago and thinking it was too circuit python focused but I haven’t looked again since. Will do though, just to check.

1 Like


Yes, this is harder to work with than the original, as far as I am concerned.

2 Likes

Not really. It’s the kind of thing @Dreamer3 might not like, though. :thinking:

A separate compatibility file may make it cleaner but putting the #define directly above the constexpr (or whatever) would probably be better for readability and maintenance. For the documentation, the pairs could cross reference each other.

1 Like

Yes, obviously you’d keep them together, but what is the point of having two vs just continuing to use the exiting all caps names everywhere? It seems WORSE to me to have new code using the new cased versions and older code using the older all case versions rather than just keeping it consistent.

1 Like

You’d have to provide non-assembly languages versions. As someone pointed out you can often find them elsewhere. Sprite + Mask is assembly on AVR platform because it HAS to be to meet the speed requirements it was written against. On much faster chips this likely isn’t necessary and C code would be more than adequate… and if not you’d of course have to write new inline code for the new architecture. :slight_smile:

@SimonMerrett The way things were originally architected you should really (other than inline asm) only need a new SAMBCore and then you could use a define to build the base class against a new core. The whole idea of separating out the core was the have the hardware specific things there. And the “base” lib should already be pretty portable (assuming your OLED hardware is still the same, of course).

You’ll have to argue that with @Pharap.

1 Like

Either way, it might be possible to just autogenerate them using a script,
which might reduce the risk of human error (assuming the human writing the script doesn’t err).


The ideal situation would be that the library had never used macros in the first place (maybe a few for conditional compilation, but certainly not for constant values).
Obviously history can’t be changed, the library is stuck with the macros lest it break all existing code.

But what can be done is to retroactively introduce what should have been used in the first place - constexpr variables.
constexpr variables can do several things that plain literals cannot, and they have several advantages over macros.

Firstly, instead of evaluating to an unpredictable expression (from the user’s point of view), they are variables, so you can always be sure that they’ll behave like a const lvalue.
Secondly, because they’re lvalues it’s possible to bind const references to them which means they can be used in cases where literals would not suffice.

I hasten to add that by default constexpr variables do not occupy memory unless they are referenced or their address is taken and the compiler is unable to optimise the reference/pointer away, thus by default they should have no additional performance impact (memory or speed).

Ultimately though this is probably low priority as far as new features go.

And Beep, and Sprites, and Audio,
and the random seed generation code in Arduboy2Base

There may be more depending on what the level of Arduino and avr-libc support for SAMD51 is.
I know for a fact there are some boards out there that don’t have a random because that’s part of avr-libc rather than Arduino.

1 Like

I meant that you’d derive Arduboy2Base from the new core:

SAMBCore > Arduboy2Base > Arduboy2

At that point Sprites should “just work” (again, once the assembly is removed) since all it should care about is that the API matches. Audio is likely different just because of the hardware differences, but IIRC Audio was already broken out into it’s own class/interface… so, yes I misspoke, you’d need SAMBCore and some sort of SAMBAudio… if you need other things (Beep) it’s just because our audio primitives were never abstracted very well to begin with - but that proves hard with the very limited AVR hardware.

Gamebuino META has a pretty nice audio abstraction where audio is just byte stream that you can feed into from multiple sources, channels, etc… I’d consider borrowing anything that was useful for a foundation if it looked helpful… then you’d be writing/porting Arduboy audio stuff to work on top of that framework.

But it has been a long time since I looked at this stuff. :slight_smile:

1 Like

Happy New Year everyone!

This morning, I sat down and within a minute realised that I had removed the AVR code from Arduboy2Core::paintScreen(uint8_t image[], bool clear) without putting anything in its place for the SAMD. After copying across

  for (int i = 0; i < (HEIGHT*WIDTH)/8; i++)
  {
    SPI.transfer(image[i]);
  }

from Arduboy_Z, ButtonTest example works. EDIT: I have now changed SPI.transfer(image[i]); to SPItransfer(image[i]); and it works fine. I had already amended it to use an LED as the output while I couldn’t get the OLED working, so I now have the following working:

  • Arduboy2 library compiling without errors or warnings (apart from the bit about "this may not work with your M0 as it’s a library for AVR chips - TODO: change that in the list of compatible architectures).
  • Buttons with arduboy.pressed(UP_BUTTON) etc
  • OLED displaying boot logo and able to move text around the display based on button input
  • LED

UPDATED FORK NOW PUSHED TO GITHUB

What should I try next? Sound? Compiling a game? Bear in mind I don’t have the M0 microcontroller with a full range of button inputs - it’s just a screen module connected to the M0 dev board with jumper wires atm. I could get the LCD and start trying to get a boot screen up and running on that. I think it would start with looking at the SPI settings (speed, mode etc) and the LCD commands for booting and sending data. I’m sure that’s all in the u8glib header file for the display controller. I have made a standalone of the LCD, rather than the other LCD which is installed in the PCB for the Ardugirl, so would be easily able to connect one to the M0.

2 Likes

For many sketches, at some point the additional sound generating libraries will have to be ported.

2 Likes

Yes, the speed increase on the SAMD range makes digitalWrite() etc an easy swap for port manipulation but I have yet to grapple with SAMD timers. Hence the audio is a bit daunting atm!

1 Like

Same here. Timers and other peripheral allocation (DMA?) is something that should be paid attention to and try to “get it right the first time”.

1 Like


Just leaving these here as they’ll probably be useful for our needs.

1 Like

To clarify, you’re suggesting creating a class called SAMBCore (which should possibly be called SAMDCore or SAMD51Core depending on which CPUs/setups it actually supports) which would implement the same public API as Arduboy2Core and then Arduboy2Base would conditionally inherit it?

If so that could work, but the only advantage I can think of is that you’d have a separate file (or file pair) for each hardware-specific implementation.

Also, you may as well still call it Arduboy2Core and rather than conditionally inheriting Arduboy2Core vs SAMDCore, you’d conditionally #include "Arduboy2Core_SAMD.h" rather than #include "Arduboy2Core_AVR.h".


To be honest though,
at that point you might as well just have a Arduboy2AVR folder and an Arduboy2SAMD folder,
each with different implementations, and then conditionally include the contents of the folders.

I.e.
A directory structure like:

Arduboy2
- Arduboy2.h
- Arduboy2Core.h
- Arduboy2Audio.h
- Arduboy2Beep.h
- Sprites.h
- SpritesB.h
- Arduboy2AVR
-- Arduboy2.h
-- Arduboy2.cpp
-- Arduboy2Core.h
-- Arduboy2Core.cpp
-- Arduboy2Audio.h
-- Arduboy2Audio.cpp
-- Arduboy2Beep.h
-- Arduboy2Beep.cpp
-- Sprites.h
-- Sprites.cpp
-- SpritesB.h
-- SpritesB.cpp
- Arduboy2SAMD
-- Arduboy2.h
-- Arduboy2.cpp
-- Arduboy2Core.h
-- Arduboy2Core.cpp
-- Arduboy2Audio.h
-- Arduboy2Audio.cpp
-- Arduboy2Beep.h
-- Arduboy2Beep.cpp
-- Sprites.h
-- Sprites.cpp
-- SpritesB.h
-- SpritesB.cpp

And then have the root headers conditionally include the headers for the correct architecture, e.g.

#if defined(AVR)
#include "Arduboy2AVR/Arduboy2.h"
#elif defined(SAMD)
#include "Arduboy2SAMD/Arduboy2.h"
#else
#error "Unrecognised architecture"
#end

Try compiling some games with either the sound removed or that don’t have sound in the first place (e.g. Minesweeper).

I think you should make sure everything else is in full working order before you move on to sound.
That way the likelihood of running into issues that aren’t sound related should be lower.

One bit of good news for you though:
You shouldn’t need to port FixedPointsArduino,
because it should already run on a SAMD without any modifications.
So games like 1943 should work alright (minus the sound).
(Emphasis on ‘should’. :P)


By the way, this implementation isn’t quite right.
You also need to clear image[i] if clear is true.
So you want something like:

constexpr size_t size = ((HEIGHT * WIDTH) / 8);

if(clear)
{
	for (size_t index = 0; index < size; ++index)
	{
		SPI.transfer(image[index]);
		image[index] = 0;
	}
}
else
{
	for (size_t index = 0; index < size; ++index)
	{
		SPI.transfer(image[index]);
	}
}

There’s two loops because I’m pessemistically assuming speed is more of a concern than memory.
If memory is more of a concern than speed then do the more expected:

constexpr size_t size = ((HEIGHT * WIDTH) / 8);

for (size_t index = 0; index < size; ++index)
{
	SPI.transfer(image[index]);
	if(clear)
		image[index] = 0;
}

Last edit, I promise.

@SimonMerrett, what size is the LCD and how are you planning to represent Arduboy games on it?
Are you planning to have a 128x64 black-and-white box in the centre, or something more elaborate?

1 Like

128x64. No translation issues envisaged in terms of pixel mapping (or whatever the proper term is).

1 Like

That’s handy.
I wasn’t anticipating that because most LCDs I’ve encountered tend to be larger.

I don’t know whether there is a ‘proper’ term or not,
but pixel mapping is a perfectly adequate description.

1 Like