VGA1306 (VGA-out for DIY Arduboys implemented on an FPGA!)

Thought I’d better reply to this over here… :smirk:

…if you remove the flash chip from the socket and use some other external device to send the initial configuration to the FPGA in ‘slave mode’, then the four SPI pins (SPI_SO, SPI_SI, SPI_SS_B and SPI_SCK) become available to the user application 49 clock cycles later - and that same external device can then take advantage of those IO!

Details are on page 26/27 of the iCE40 Programming and Configuration Technical Note.

(EDIT: SPI_SS_B and SPI_SCK do have pull-up resistors attached though, which may limit their usefulness! :roll_eyes:)


Hmm…I can tell 32 shades.

these many things make me think of my homemade bridge diode…
Or one of those mililtary circuit board(Fallout junk items) ancient circuit board with no less than 50 of them on board
Wait. it work with SSD1306? :tada:
If you can give me the sketch for NES controller (for a Arduino Micro), and @uXe figure out how to get one of your board to be, then I might be able to fit all these onto one Proto-shield. With a 3.5mm headphone jack.
That being what I am aiming for, but @uXe’s board is a tad too big.

Have uploaded an ‘SH1106-friendly’ variation of the code - which listens out for the 0xB0 page-address command to achieve VSYNC, instead of relying on the DC pin:


Somebody was going to throw away a display that had VGA! so finally I was able to test the board

Thanks a lot @uXe works like a charm and makes me again to want to learn FPGAs :stuck_out_tongue:

1 Like

Great choice of game for your first run!

Probably also time to clean the desk.

1 Like

Ignore @filmote, please don’t ever clean your desk, a good programmer’s desk should be messy :P

1 Like

That’s funny to hear from someone known to clean up codes all the time :P

1 Like

Bammmmm !      

Clean code, messy desk - it’s like the ‘cold hands, warm heart’ thing. :P

My code is clean because I’ve worked out how to make it clean by designing it with the bits of paper strewn across my desk. :P

(P.S. ‘code’ is uncountable when used in a programming context.)

Rather than cleaning I think I need a motorized double-decker desk. That would be awesome. Also it is not messy, I know where is everything.

1 Like

Sure … everything is on the desk.


hahah awesome answer. I am going to use that one-liner now in my daily life

1 Like

WOOT! :laughing:

Then you will be happy to know I spent today exploring the use of the VGA1306 board as a stand-alone FPGA gaming device! :wink:

Re-assigned the four input pins to be used as inputs for four directional buttons tied to pull-up resistors (using a resistor array in a DIP package here):

Here’s the Verilog… now get learnin’! :crazy_face:

1 Like

What is the 8 pin IC? Is there another AVR CPU on here we’re actually talking with that’s then talking to the Lattice chip?

The 8-pin IC is an SPI Flash memory chip - the specific one I used here is a A25L080. The FPGA automatically reads the ‘firmware’ from the flash chip and configures itself every time at power-up.

Basically, you just externally reflash that chip to load new firmware - or you can also pull the chip from the socket altogether and use the SPI pins that are exposed on that 8-pin footprint (plus RESET & DONE on the separate 2-pin header) to directly upload new firmware instead using a microcontroller (needs to be 3.3V!) or a Raspberry Pi for example…

Good explanation that helped me make sense of it here:

What is all the boilerplate code at the end? IE:

if(c_col == 639 && c_row == 84) begin
              raddr_temp <= 6;

That’s just my hacky way of dealing with the way the Arduboy screen buffer is formatted, and scaling it up from 128x64 to 640x320! :smile:

There is likely a more elegant way to do it - but it works / it ain’t broke… :wink:

I get that, but what is it actually doing? What is raddr_temp for?

There is an array with 8192 elements stored in the FPGA’s internal dual-port ‘Block RAM’.

It is constantly being written to on the rising edge of the Arduboy’s SPI Clock here and read from on the rising edge of the VGA Clock here.

raddr_temp contains the array address for the first pixel in each of the screen buffer’s 64 rows.

The comments in the code describe its use: “reset before the start of each line and set pixel buffer address back to beginning of line”.

And it is only updated once for every five rows drawn to the VGA screen, so 64 rows get scaled up to 320 rows.

Ah it’s an array of bits. I got it now. The 640x320 code is a little clearer than the others also.

All you need per iteration is a single subtraction to go back a row and switch to the next bit position.

if(c_col == 639 && c_row+1 is divisible by 5) begin
              raddr_temp <= raddr_temp - 1024 - 1;

c_row can be replaced with a modulus check also, but I’m not sure how to code that in FPGA. In C it would look like if ((c_row+1) % 5 == 0)

That would remove all that repeated code with a single conditional with some simple math.