Transfer Arduboy sBuffer via SPI to drive an LED matrix

Yes, I meant mainly faster :rofl: I don’t think the uno can work as a slave for @JayGarcia because the LCDs he is intending to use don’t do PWM they are just “shift and latch” LED arrays so the slave has to do a lot of bit-banging really fast to achieve a decent refresh rate.

I agree with you 100%.

Even at 1FPS for this POC, i still have the issue stated in the above post. :frowning:

Did you slow down the SPI master clock (i.e. Arduboy) to CLK/4 as suggested by @MLXXXp?
Slowing down the controller memory refresh to 1FPS only reduces the amount SPI words transmitted in the time unit, it doesn’t slow down the SPI clock. i.e. each SPI word is still transmitted at CLK/2.

I haven’t done any specific research, but I’d look into using an Arduino Zero (or something with the same processor), or a Maple clone, to see if either would be capable.

To do this you have to change bootSPI() in Arduboy2Core.cpp, or just rewrite the registers in your sketch.

For 4 MHZ:
SPCR = _BV(SPE) | _BV(MSTR);
SPSR = 0;

For 2MHz:
SPCR = _BV(SPE) | _BV(MSTR) | _BV(SPR0);
SPSR = _BV(SPI2X);

3 Likes

Thank you SO MUCH for this. I was scouring the net on how to do such a thing but only found specific examples that requires the SPI library and method calls. None of them worked by injecting those calls into the library.

SCOTT!!! You’re the effing man!!!

Going to post a video shortly. ;D

1 Like

More work to be done but this was yyyyyuge with a Yeh!

5 Likes

You could use one of these, to allow the Leonardo to send over SPI for compatibility, while also allowing the Uno to receive over serial UART:

1 Like

Nice but the Uno is not fast enough to control the LED arrays so it has to be swapped for something with a faster SPI anyway. So the SPI -> UART would mean an extra (unnecessary) component. Instead what you did with your SSD1306 -> FPGA -> VGA project would be ideal for this. It would have a steep learning curve for @JayGarcia because of having to learn Verilog upfront unless he is willing to pair up with someone to do it (I’d be willing). @uXe, do you plan to open source the verilog source for your SSD1306 -> VGA project?

1 Like

I’ve wanted to do this but using addressable LED’s like the ws2182 neopixels. Then you could make a great big display for pretty cheap!

I’ve also thought about building a little slave arduino that sits on the SPI bus and slurps up all the pixels and then outputs them back to PC or otherwise for doing screen capture, so I think that’s really where you’re at on this!

2 Likes

Thanks @dxb. I looked at FPGA and Verilog and quickly realized that it wasn’t the right avenue for me. I don’t have an engineering background, so a ton of JIT learning for me. =)

@uXe, your VGA project is off the effing chain!!

Coming a bit late to the party I see.

I totally forgot about that! so AVR based Arduino’s are no good as 8MHz SPI slave (without additional support hardware) :cry:

Unfortunatly my bootloader isn’t of much use. the 1K extra space isn’t enough to keep USB code in the sketch. The USB code of the bootloader is of no use either because the ram variables and object involved are on incompatible ram addresses. Even if it was possible I think outputting 60 frames of data over USB would require too much CPU time.

Not required for just the 1K buffer output (a timeout can be used to synch). But if you want to support invert mode or other display commands, OLED DC is needed.

I think you can get away with that. But I would still hook up the OLED CS to SS to make sure SPI is in sync after powering on in case of instable power / noise

I totally agree on that. I’m wondering if the Raspberri Pi would be usable as a spi slave. according to the BCM2835 ARM Peripherals SPI speeds can get to 250MHz which is far beyond the 8MHz we need.

Another option could be using an USB to SPI bridge like using a FT220X based breakout board.

I’d love a Raspberri Pi Arduboy debug system with TV out :slight_smile:

3 Likes

Thank you very much for your input on this. =) You’re not late. I’m still very early in the project and will def need support. :slight_smile:

I read online that Pi as an SPI slave is extremely difficult. I’ve enabled SPI development on my beagle bone and am probably going to go that route.

In the interim, I have a teensy 3.6 (32bit 180Mhz) that i’m wiring up as a slave to test and iron out issues.

I also received the 64x32 LED matrices today. They are gorgeous.

You highlighted something that has been puzzling me. Ideally, I’d like a way to signal to mark the start/end of an sBuffer transfer (in case of noise).

I imagine that I can do that via another pin (SS?) like in the example posted above:

digitalWrite(SS, LOW);    // SS is pin 10
// Do the SPI transfer
digitalWrite(SS, HIGH);    // SS is pin 10

I also need to emulate other display methods like invert(); and/or mirror(), though mirror() is extremely low in the priorities for me.

I think where i need to go is essentially write a compatible SPI module to the production OLED SPI Driver. That should be a fun task :slight_smile:

SS is the RXLED. I’d use Arduino Pin 2 or Pin 3 for this (unless you plan on using I2C for something).

And don’t use digitalWrite(). Since all digitalXXX() and pinMode() calls have been eliminated from the library, you’ll end up pulling in a lot of extra code. Use direct pin register manipulation like the Arduboy2 library does.

1 Like

Hell yes. Thank you =)

1 Like

Have not included these in my FPGA project yet either. The thing is - the OLED command-based display methods like invert() and allPixelsOn() already don’t work with our ‘conventional’ way of screen-mirroring / capture by sending the buffer over USB serial anyway… how many games actually use these?

Maybe there needs to be an ‘invert’ flag added to paintScreen()? Added bonus would be that ‘invert’ when combined with the already existing ‘clear’ flag would also give you allPixelsOn().

I feel using a timeout is not robust because games sending the frame buffer in chunks for whatever reason (i.e. not using the Arduboy2 library) will not sync correctly depending on the timeout value. On the other hand it will probably work for most games so there is that… :slight_smile: :+1:

That is not enough unfortunately. Master and slave can come out of reset at different times and the master will send commands to setup the controller before sending frame buffer data so the slave could (and will) start receiving SPI word without knowing what they are. Additionally all it takes is a single controller command (like invert screen) to make the receiving end go out of sync. So you really want the Command/Data line to be connected to the slave.

The first time the command/cata line goes from command to data is your mark. From there pixels start at the current cursor position (which default to top/left corner) and wrap around every 1024 bytes. command / data is required to at least skip commands otherwise the slave will get out of sync on the first command (invert screen for instance).

To be sure to catch the first C to D transition the slave must keep the master (arduboy) in reset until it’s ready to receive frames. The SPI rx interrupt on the slave must read the CD line as soon as possible after each interrupt otherwise commands and data words will be confused.

The Arduboy2 library could be modified to improve the robustness of these methods by inverting its current convention of leaving the C/D line set to data by default. If C/D were set to C by default but became D during frame buffer transfers then any SPI screen mirroring method would be able to sync at the start of each frame.

Yes, you can use another pin. But using @Mr.Blinky’s timeout approach together with the CD line to distinguish between commands and data will work for most games, maybe with occasional glitches. With timeout based frame-start detection, master and slave can be powered up independently i.e. no need to control the arduboy reset from the SPI slave, and the CD line will avoid (or mitigate) false frame starts.

This is exactly what I have done with my FPGA project to get reliable frame sync.

I would suggest maybe implementing this change as a ‘variation’ (the same way @Mr.Blinky has made different board variants to support SH1106 / SSD1309 controllers)?

(And maybe also including ‘software’ versions of invert() etc in that variant? Would make life a lot easier for me and @JayGarcia! :smile:)

2 Likes