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


(Simon) #83

Bammmmm !      


(Pharap) #84

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.)


Game Design Docs
(Erwin) #85

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.


(Simon) #86

Sure … everything is on the desk.


(Erwin) #87

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


#88

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:


(Josh Goebel) #89

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?


#90

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:


(Josh Goebel) #91

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

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

#92

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:


(Josh Goebel) #93

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


#94

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.


(Josh Goebel) #95

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;
            end

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.


#96

I can see how that would work for the first 8 rows, but then what happens when you get to row 9 of 64 and you have an address of -1 when you want 1031?


(Josh Goebel) #97

OK, so you may also need a “every 8 rows, increment by 1032” or something. :slight_smile:

Or actually if you don’t do the subtraction it should already be perfectly lined up, no? So in that case you’d just check for every 8th row and do nothing at all.

Basically you want to use math to write “for every row, do this” and “for every 8 rows, do this”. So then you describe only 2 conditions, not 64.


#98

What’s great about FPGAs though is that those extra 62 conditions aren’t going to slow you down any… because the comparisons are all happening simultaneously, not sequentially!

Getting close to having boards available for sale now, and I look forward to seeing how far the community will optimise / ‘bum’ down my imperfect / ‘не слишком изящным’ Verilog! :smiley:


#99

I hope you’ll break out unused GPIO’s too for future additions (Kind of thinking (S)NES controller to parallel buttons? push button for mode selection? :smiley: )

Also got this crazy idea for my pro micro that serves as (S)NES controller:
Compress the VGA1306 firmware and store it in the pro micro so it can uploaded (and be updated) to the VGA1306 board. One more project on the heap :stuck_out_tongue:


#100

Sorry, that may have to wait for version 2.0! :flushed:

Yes, the FPGA can receive its firmware directly in ‘SPI Slave Mode’ (here is a Raspberry Pi script I have used for this purpose if it helps).

Here is a nice flowchart illustrating the process:

Taken from the iCE40 Programming and Configuration Technical Note (details are in Section 13, from page 25 onwards).

You will need to level-shift down to 3.3V to use the FPGA SPI pins directly though!


#101

Thanks for the info and links. Looks like I have something nice to play with this weekend :slight_smile:


#102

Enjoy! :smile:

(Note: Regarding the RESET and DONE pins on their separate two-pin header. RESET has a pull-up resistor attached, so you don’t need to drive it high - you can just release it. And DONE has an internal “weak pull-up resistor”, but you may be able to disregard the DONE pin anyway - I don’t pay any attention to it when using that Raspberry Pi script and have not had any problems…)