Porting Arduboy2 library to SAMD

The pixels are like postage stamps!

They’re perforated and they cost more every year? :P



It’s just a shield for the feather layout so you can pick your poison for mcu. SAMD included, but also esp and other fun bits. With the 128x128 4 bit display.

I think we found the answer.


Name needs some work, gamefeather.com is $3,000 and there is “feather the game” too.

Plenty of sample code (this is D21, but I’d think the concepts would at least be close if the code wasn’t directly portable).

1 Like

Sounds like a nice organization pattern to me. :slight_smile:

That doesn’t sound bad either. :slight_smile:

1 Like

Whoa, this is like electronics inception - which came first in this shield, the Arduboy “essence” or the feather format?

Ardufeather? Featherboy?

I humbly submit that for the price, I’d rather spend the money not on a feather and that a processor module could work. Ie produce castellated SAMD 21 and 51 PCBs with minimal passives in a pin layout to match the esp32 wroom modules and that’s the footprint on the main PCB with screen etc.

Just connected the LCD to the M0 and uploaded the u8g2 demo sketch, this time using HW SPI. My previous test on this LCD was with SW SPI. The main difference is the speed increase with which data is transferred. There’s still the decay/lag that was noticeable before (contrast is set to 250 out of 255) but I think it looks better. Will now see if I can boot it with direct commands in the Arduboy2 library.


Seeing this, I think your first experiment when you come to working with the timers should be to reimplement Arduino’s delay function (assuming it doesn’t already exist).

I’d (probably) never recommend delay for use in a game,
but for testing and simple hardware control it can be handy.

To implement delay, you pretty much just need time counters and a busy loop.
The relevant functions seem to all be in wiring.c.

(If you can figure it out, adding some kind of time-saving sleep would be kinder on the battery than burning CPU cycles in a loop, but sleep can often be slow to enter and wake, so that might only be viable for longer delays.)

I’ve been looking at getting the LCD display working with Arduboy2 library this morning. I’m using a variety of sources to try and pin down what commands and data format should be sent to the UC1701 display controller but the main reference at the moment is the capture from my oscilloscope while using the verified u8g2 demo program you see in the video above. By introducing delays between the frames, I can do a single trace capture and compare e.g. the u8g2.begin() output with the library. So far I can match the data that is sent at arduboy.boot() with that sent at u8g2.begin(). But no boot logo appears and I can’t do a print screen. I think it would be easier to confirm using an image rather than a print function, so I’m working on the basis that I should get the boot logo working first.

Ignore the blue (not cyan) trace - it’s not connected. This is the capture from a working transfer of an image to the LCD using u8g2 library. Pink is connected to DC, so we can see at the start of each of the two burst sections of data that three commands are sent. There are 8 of these bursts of, I’m assuming, 128 bytes (128 x 64 / 8bits / 8 bursts = 128 Bytes).

The first two of the three command bytes at the start are always 0x10 and 0x00. The third is 0xB0, 0xB1… …0xB7 for the last one (couldn’t fit all three commands on the scope screen hence the decoding isn’t showing up but it is there if I zoom in).

This is making me think we need to adjust the Arduboy2Core::paintScreen(uint8_t image[], bool clear) function to insert these commands at the appropriate point. Like

  for (int i = 0; i < (HEIGHT*WIDTH)/8; i++)
	  if (i % 8 == 0) {
		  SPItransfer(i / 8);

Any thoughts? I don’t know the SSD1306 like some of you lot do so is there’ a reason why I can’t see this kind of organisation already happening in the Arduboy2Core::paintScreen(uint8_t image[], bool clear) function (remember that the AVR version is nothing like the SPI.transfer() function that we have adopted for the SAMD)?

EDIT that code clearly didn’t work. Here’s something slightly more informed but not tested:

  uint8_t rowPair = 0;
  for (int i = 0; i < (HEIGHT*WIDTH)/8; i++)
	  if (i % 8 == 0) {
		  rowPair = 0xB0 | (0x01 << (i / 8));
1 Like

I’ve supported many of the Rabid Prototypes campaigns on Kickstarter and he truly has dropped the ball on the Tachyon campaign. It really is a shame. I was issued a refund without requesting one as I guess he didn’t like that I would occasionally ask for updates on the project. (Shake head) I went with the Adafruit Itsybitsy M4 quite some time ago as I regularly purchase form Digikey and add Adafruit boards to bump orders into the free shipping tier.


So, here’s where I’m up to with getting Arduboy2 to send data to the LCD, using the HelloWorld example sketch. I’m very pleased as even though this is messed up, I can see data that we intended to be passed appearing on the screen! Going to take a break and drill holes in aluminium with my CNC router as a reward!

1 Like

Getting closer?

1 Like


A bit too much contrast (I think it’s only one setting below max) and the code needs a huge amount of tidying but this modified HelloWorld.ino seems to be working nicely. It uses a 15fps frame rate so I don’t know if changing that as well as the contrast would help.

Nice work! The ghosting tho :dizzy_face:

It may get better with different screen settings - the LCD controller seems to have a fair amount of adjustment available:

Snippet from UC1701 datasheet

But if not, “because retro”. It’s highly intentional, to give an authentic 8bit feeling. OLEDs indeed! :grin:

Anyway, I have a serious question. The hardware configuration files that you find in an Arduino hardware folder to specify compiler options, pin mapping etc are clearly not part of the Arduboy2 library but they are part of getting Arduboy2 working on the SAMD microcontrollers. What’s the best way to share them? As a separate repo? Somehow linked to other repos that may also contain hardware configuration for Arduboy devices? I don’t have an Arduboy so I haven’t even checked what’s out there already.

I have a crystalless bootloader (might have made a crystalless version of the Zero bootloader but I can’t remember - was back in the summer) and today made an accompanying set of variant files. The main edit was adding -DCRYSTALLESS to the build options in boards.txt (which took a while to track down as the source of my board’s silence on the oscilloscope, so it was a breakthrough even though it was trivial to rectify). The rest was changing names in boards.txt so it would appear as a separate board in the Arduino IDE and copying the Sparkfun SAMD21 mini’s variant.h and variant.cpp into the folder (which lives in the Arduino IDE project folder’s hardware folder, for a local board. This could easily be added to the boards manager in the IDE if we hosted it somewhere and added the required acoutrements, such as version folder, json file, changelog, variant compliance changelog etc.

Fixed the screenshot for you too

There was still some blue left

Thanks, my subscription to Photoshop ran out while I was looking for more ports on my oscilloscope to connect random traces to earlier!

1 Like
C:\Users\...\AppData\Local\Temp\arduino_build_588628\sketch\Utils/Eeprom.h:21:24: fatal error: avr/eeprom.h: No such file or directory
 #include <avr/eeprom.h>
compilation terminated.


I know I went through Arduboy2.h and .cpp and deleted/commented out any reference to eeprom, and now it’s coming home to roost. I promise to take a look at the Pokkito port in due course but if anyone has any bright ideas about how to tackle eeprom in SAMDs, I’m all ears. We may need to do it properly from the start though. IIRC, the adafruit library port for circuit python just writes a file and treats it as eeprom, so not very useful here.

In the meantime, I will have a dig into the LCD settings. By the way, for anyone playing along at home, the settings for all the screenshots and videos you’ve seen so far are:

0xE2, /* soft reset 0x0e2*/
0xAE, /* display off 0x0ae*/
0x40, /* set display start line to 0   0x040*/
0xA0, /* ADC set to reverse 0x0a0*/
0xC8, /* common output mode 0x0c8*/
0xA6, /* display normal, bit val 0: LCD pixel off. 0x0a6*/
0xA2, /* LCD bias 1/9 0x0a2*/
0x2F, /* all power  control circuits on 0x02f*/
0xF8, /* set booster ratio to 0x0f8*/
0x00, /* 4x 0x000*/
0x23, /* set V0 voltage resistor ratio to large 0x023*/
0x81, /* set contrast 0x081*/
0x27, /* contrast value 0x027*/
0xAC, /* indicator 0x0ac*/
0x00, /* disable 0x000*/
0xAF,  /* display on 0x0af*/

Which is quickly followed by the contrast being raised to either 0x3E or 0x32 (out of 0x3F max)

Arduboy2Core::paintScreen(uint8_t image[], bool clear) should be nearly up to @Pharap’s standard in the most recent commit. Just be aware that I haven’t been able to successfully make the LCD vs OLED displays conditional, so in that commit I have made the default display the UC1701-driven LCD. I’ll revert if someone can tell me how to make the display settings conditional (I tried doing #define (UC1701) in Arduboy2Core.h and #if defined (UC1701) in Arduboy2Core.cpp but the compiler didn’t seem to react to it).

Give GIMP a go instead:

Open source and completely free, no silly subscriptions to worry about.

For now your best solution to this would be to create a dummy avr/eeprom.h.
You’d have to implement a number of functions,
but they don’t actually have to be functional at this point,
you could get away with making them do nothing.

Most of what you’d need is already here:

If you take that and comment out the readEEPROM and writeEEPROM calls then you should have more or less what you need.

If you don’t have access to a C++11 standard library implementation then you’ll also need to remove all the uses of std::, but that’s a simple find-and-replace operation.

The problem with that approach comes with flushing the data back to the device.
With EEPROM, all writes are immediate, there’s no buffer and no flushing required.
With SD cards and similar systems the data hangs around in a RAM buffer and has to be manually flushed to disk.

If that’s literal, then you’ll want to remove those brackets for a start.
I’m not even sure how the preprocessor would react to that.
Logically it should try to define a function macro that doesn’t have a name,
but even if that were legal I’d assume it would be impossible to actually use a macro with no name.