Hobbyist: FPGA between MCU and external memory? - Page 1
Forum section: electronics / general

author: Nominal Animal
author_rank: Super Contributor
timestamp: February 24, 2025, 08:17:20 am
content: The question is the difficulty level for a hobbyist to use cheap FPGAs to expose SRAM or SDRAM or PSRAM to a microcontroller. This would be my first real FPGA project, and I'd like to avoid BGA, too. If you don't already know, I'm a lightweight very-limited-budget hobbyist in electronics, total newbie with FPGAs, but have decades of programming experience (including some low-level, bare metal stuff) in about a dozen programming languages.I have a dual purpose for this thread: one is to perhaps get advice on starting this hobby project, and the other (more important to me) is to discuss similar use cases and projects others might be working on. I don't know how to simplify this starting post without losing context, so sincere apologies for those who hate the walls of text!Edited to clarify:The core of the question is about the technical and especially design aspects of putting an FPGA between a memory IC and a microcontroller. Or, equivalently, an FPGA with built-in memory between two identical microcontrollers; the MCU or MCUs see only ordinary external memory. In my case, I don't necessarily need access arbitration, because I can use two RAM ICs with separate buses, with each MCU accessing their own one, never the same RAM, as long as I can swap which one they access. I believe this is a relatively unusual design, with the FPGA-uses-own-RAM being the common one, with only rarer devices like oscilloscopes and other data acquisition equipment sharing memory this way, so I want to learn about the important design-affecting issues and approaches up front.The rest of this post is details on what and why, but the above is the part that gives me pause.BackgroundI like to interface small 1" - 4" display modules to Linux-based appliances and single-board computers for use as an external information display for nontechnical humans. High-fidelity IPS panels up to 800×480 (my preference is 320×240) are quite cheap. I can do this using various microcontrollers with USB connection to the host, with the host software only controlling the display, not generating the image. The issue is that typical microcontrollers only expose a single framebuffer, and that's just not very effective. The displays have their own controllers and easy digital interfaces, so I find the idea of using an FPGA as a programmable framebuffer extremely interesting. I'm only a hobbyist, so I want to keep the costs down and everything hand-solderable, so the optimum would be to use external SRAM/SDRAM/PSRAM as a framebuffer exposed to a microcontroller to draw onto, with the FPGA updating the display module transparently on the background.In particular, I like the idea of having 3-4 completely separate planes: a background one with full 16/18-bit color, plus 2-3 various indexed/paletted planes drawn on top. Similar stuff was used in arcade games and home game consoles, back when memory was scarcer. (Even today, with our stupidly powerful GPUs even in phones, the actual displayed image is composited from separate "sub-frames" in graphics memory.)A practical example of this is a small gauge display. The static part is in the background plane. The gauge needles and displayed values are on a separate plane on top, so the MCU does not need to modify –– read-then-write –– to change these, just clear and draw the new ones on top. Because the memory for each plane is separate, clearing the gauge plane does not affect the full-color background at all. Plus, the MCU does much less work.I often use capacitive touch to control what is displayed, so yet another plane can be used for the touch interaction; I like rings or circular arcs extending outwards from the touch point like a ripple to indicate touch registration (separate from touch action on the graphics). As a separate plane/framebuffer in memory, the ripples can just be copied to the framebuffer by the MCU without any calculation, or any effect on what is being done to the other planes.If there is a fourth plane available, it can be used in between, for additional overlays and transients. The indexed color mode I'm most interested in these is one byte per pixel, with each of the 256 possible values freely chosen from a full-color palette (262k colors) with a full transparency control. For creating antialiased text and polygons, using 3 or 4 low bits for transparency makes things easier for the MCU, but precise and clean graphics and antialiased text.It would also be fun to play with the kind of visual models used in old game consoles. All my hobby stuff like this is CC0-1.0/Public Domain, so if I get this working, it'd also be available for other hobbyists for use in old-style portable pixel art and retro gaming projects, too.As an end result, I'm hoping to end up with a display carrier board with an FPC connector to the display modules using ILI9341/9488/ST7789 etc. controllers, containing the MCU, external RAM, FPGA, USB connector, and perhaps a microSD socket for graphics asset storage. I currently only use Linux and open source tools, so I'd prefer to avoid proprietary software; and I don't have funds for developer kits.Hardware:Among the many microcontrollers from NXP, STmicroelectronics, and others, I've taken a liking toWCH CH32V307VCT6: it has a high-speed USB 2.0 (480 Mbit/s) and an external parallel static memory interface (FSMC) interface for up to 16 MBytes (but with data and address bits multiplexed on the same pins). It's cheap (<5€ in singles), programmable using open source tools in Linux, simple enough for a hobbyist like myself to put on a custom board, and although not terribly powerful, definitely powerful enough for this.As to the memory itself, I've been thinking about using two SRAM modules, something like IS61/64WV51216EEBLL 512k×16 SRAM (PDFdatasheet at Mouser), with one "connected" to the MCU while the FPGA reads the other for the framebuffer generation. As I've not done any real projects with FPGAs yet, this is purely to keep the two separated, so that I don't have to work out a bulletproof sharing logic between the FPGA framebuffer read access and MCU read/write access. Having access only to the part of the framebuffers not currently being displayed is absolutely fine for me, even if it means extra cost: this is hobbyist one-offs, not production stuff. I do believe CH32V307VCT6 memory interface has a WAIT input I might use to interleave FPGA and MCU accesses, but I know how risky that kind of complexity is in a hobby project, so I'm aiming to keep it simple, even if it means extra hardware. The downside is that using two in parallel would take quite a lot of pins: about 40 per SRAM module, another 24 to the MCU, and another 24 or so for the display module.Even faster SDRAM might make things easier. I do need very fast random access for the MCU (20 ns write cycle time or less). While the FPGA needs similar throughput (I'd like to get about 70 Mbytes/s), it's almost all just linear scanning. With fast enough SRAM, the FPGA could probably use fixed time division multiplexing approach, using "access slots" for the MCU, the FPGA frame buffer, and SDRAM refresh. I know nothing about how to control SDRAM or any of the other RAM types; SRAM thus far seems the simplest to implement. I'm very open to suggestions, though.As to the FPGA, I have no idea. I prefer to avoid BGA, which limits my selection, especially as I'd like to have > 100 I/O pins. I'd like to have fast 6×6=12-bit multiplication, because optimally I'd do 24 of those in parallel in the output stage (per pixel), with a throughput of about 10 Mpixels/second. Otherwise the logic is limited to marshalling the RAM accesses and RAM lookup. Many FPGAs seem to support different voltage levels on different banks. The MCU and display I/O will be 2.8V–3.3V. Again, this is my first real FPGA project, so any suggestions would be appreciated.As to the display modules, I have a few320×240 and 480×320 IPS TFTsfrom BuyDisplay/EastRising. I personally also like the smaller 1"-2" ones, but for nontechnical people, the display needs to be 2.4" – 4" to be practically useful.Existing software implementation:I already have experimentally implemented the image generation stuff on a computer and on an MCU, so it's just the hardware that gives me pause. I have considered using a dual-core microcontroller, with one core dedicated for the display generation and updates, but most of the cheap ones just do not have enough RAM for multiple framebuffers/planes, or they support full-speed USB 2.0 only (12 Mbit/s, not high-speed 480 Mbit/s) –– for example, Raspberry Pi RP2350 and Bouffalo Labs BL808 ––, and I feel those are limits I don't want.(I also have a largeish collection of pixel tricks and effects dating back to nineties. I particularly like retro arcade and puzzle games with orthographic projection views, like in Gauntlet and similar, and have some tricks for those if anyone is interested.)The software is all experimental code, not published yet, but I like this "new" approach (well, going back to roots of computer graphics, retro game consoles and the like, except with better hardware) A LOT. So, this is not a question of "is this possible", but "how could I do this in hardware", and have fun at the same time. And hobbyist-level stuff only! I don't care if someone else develops this further into a product, but I definitely will not. If the end result works, I'll put it all out in OSHW, likely CC0-1.0/Public Domain.(CH32V307VCT6 has only 64kBytes of RAM, which does not suffice even for a small full-color framebuffer. The FSMC interface is not pin-compatible with any SRAM chips I've found, because of the way it multiplexes the address and data pins. I could maybe design a circuit for the needed glue logic, or just use the host computer/appliance and just stream the framebuffer changes.. but I don't want to.)My favourite microcontroller,Teensy 4.1(based on NXP i.MX RT1062), has a high-speed USB 2.0 (that even with just plain old USB serial in Linux can sustain 25 Mbytes/s in one direction), lots of RAM (1 MBytes) plus PSRAM support (up to 16 MBytes), and has a Cortex-M7 running at 600 MHz so it has no issues doing this in software. It's pinout isn't optimal for driving these external display modules, and although PJRC sells the proprietary bootloader chip (which also handles power sequencing on startup) so I could design my own board with a more betterer pinout, it is 0.8mm pitch BGA, and I still fail at BGAs. In other words, I can do this on relatively cheap hardware already; it's just that an FPGA-based reprogrammable hardware approach exposing the framebuffer/graphics resources as external memory would be even more useful.Assuming it's not expensive, of course.Advice needed:Suggestions for the FPGA? I know of Lattice iCE40, and have a Sipeed Tang Nano 1k and 9k development boards. So, a complete beginner. I'd like to spin my own boards, and avoid BGA. The displays are in the 2.4"-4" range, so board space is not an issue; I'll use JLCPCB or similar for the boards. I'm not interested in expensive developer boards and kits, because I have a tiny budget.Pointers to existing projects interposing an FPGA between a MCU and RAM (SRAM/SDRAM/PSRAM)? Especially if some kind of access delegation is used. This is the part that is most likely to bite me in the butt, so any pointers how to do this right would be welcome. I only need a couple of megabytes of RAM total, so no need to go into dynamic RAM and their intricacies: I'd like to keep this simple.Advice, articles, projects, or books showing how to interface SRAM/SDRAM to an FPGA correctly? I like async SRAM because it is simple. SDRAM requiring periodic refresh cycles scares me a bit, especially because the MCU will not be aware of those. I can control the async timing on the MCU, but I'd rather keep it as fast as possible to make maximum use. (The CH32V307 maximum clock frequency is 144 MHz, but I'd be happy with 20ns read and write cycles to the managed external memory.)Note the tiny budget, though, and this being hobbyist only, and that I'm a Linux-only user right now: I do not have any Windows licenses, and relying on Wine feels clunky, so any Windows-only toolchains are not possible for me. I'm hoping I can find something supported by Yosys, nextpnr, and similar open source projects, although I'm happy with free vendor tools too, as long as they run in Linux.

author: pcprogrammer
author_rank: Super Contributor
timestamp: February 24, 2025, 08:40:43 am
content: Hi Nominal Animal,sounds like an interesting project.On the FPGA side the Gowin GW2AR-18 ones are very interesting. Unfortunately getting them in Europe seems to be a bit difficult and to my surprise LCSC does not sell them either. But the eLQFP144 pin ones cost about 10 dollars in the USA.https://www.edgeelectronics.com/fpga/gw2ar-lv18lq144c8-i7/One benefit is that you can get versions that have 8MB of SDRAM in the chip with a 32 bit wide databus and 166MHz max clock frequency. A read burst of 256 words takes ~1.55us at this clock rate.Hardware design is not that complex for these devices. Just take a look at the crappy schematics of the Sipeed Tang Nano boards.Since you are new to FPGA design and usage of SDRAM, you have some learning to do. I also just recently started with this to make a video conversion system.https://www.eevblog.com/forum/projects/please-recommend-a-vga-to-parallel-lcd-board-or-ic/msg5828029/#msg5828029SDRAM is not that complex. You can write your own controller for it to suit your needs.Be aware that programming for a FPGA is very different to writing software. I suggest taking a look at verilog tutorials (I find this easier than VHDL).https://www.asic-world.com/verilog/veritut.htmlI'm happy to share my recently gained knowledge with you.Success,Peter

author: SiliconWizard
author_rank: Super Contributor
timestamp: February 24, 2025, 08:53:44 am
content: About the CH32V307, note two things:- You can actually use up to 128KB RAM (it's a configuration and will decrease the amount of Flash available for code by 64KB).- It has an interface for 8-bit and (IIRC?) 16-bit PSRAM. Those chips are easy to find, but possibly not as easy to assemble as they are usually BGA (unless you can find some in another package). They are the same as the small quad spi PSRAM, but with a wider synchronous data bus (so faster access). The CH32V307 can use these, from what I had read in the datasheet. The interface is usually called "Hyperbus". One example:https://www.digikey.com/en/products/detail/infineon-technologies/S27KL0642DPBHI020/11611394Now the CH32V307 possibly doesn't have enough processing power to do what you want by itself even with that much RAM.Lattice iCE40 FPGAs look like a good and easily available option. As for RAM, you can go for either SRAM or PSRAM or SDRAM. I think PSRAM will be your cheapest bet here for a given amount of memory, and implementing access in HDL is not too difficult. Note though that anything that's not SRAM will have bursty I/O, meaning that either you the delay for initiating bursts of consecutive data blocks is OK in your design, or you'll need to implement some kind of cache to make it a bit more transparent. But either way, you'll have to account for possible delays when accessing data.

author: Nominal Animal
author_rank: Super Contributor
timestamp: February 24, 2025, 12:06:43 pm
content: I'm very aware of the difference between Verilog/VHDL/etc. and application software development, but it is an important point to note. I too see learners often struggling with their existing notions conflicting in a new domain, for example moving from application development to embedded development using freestanding C and/or C++. Even moreso when changing paradigms (imperative vs. functional and so on).I do have a Sipeed Tang Nano 9K with a HDMI connector for playing with full-size displays, and a Tang Nano 1K for controlling small TFTs. Their USB is limited to full-speed only, which I don't want to be limited to. (I guess I've been overpampered with Teensy 4.x.)Note: The core of this project is very similar to using an FPGA to provide dual-port access to external (standard) RAM. It's just that one "port" is the FPGA itself reading the needed framebuffer data out in a very predictable fashion.CH32V307 isn't grunty enough to implement my framebuffer idea in software; even on Teensies the use of PSRAM must be limited to keep the data bandwidth high enough with the standard PSRAM chips (currently APS6404L_3SQR at 84 MHz). It's just that it's a simple, cheap MCU with high-speed USB and asimpleexternal RAM interface I think I could manage; compare to e.g. NXP i.MX RT1060 series and their power up sequencing and so on. The display data generation itself is parallelizable to any degree (down to one pixel per task), with per-task work just memory lookups and basic arithmetic on 4-15 bit integers, which I believe maps well to FPGAs.(There are ARM Cortex M7 and M33 MCUs from Microchip and ST and NXP I could use instead, but thus far there have been too many for me to find all suitable ones – with high-speed USB and an external RAM interface I could hijack for this, enough internal RAM, and non-BGA packages – that I as a hobbyist could use. Microchip SAMS70, for example.)Teensy 4.1 itself uses QSPI (SDR) to talk with the external PSRAM. It'd be really nice to interface the display FPGA with that, especially because there is support for two PSRAM chips (same bus, different chip selects), and it has both RAM and grunt aplenty – and the SDIO micro-SD slot built-in. Making my own Teensy-type board for displays is in my todo list, but thus far, I've failed with BGA ICs. I do have now a small hot plate and hot air and a couple of different cheap irons, but no oven. I really need cheap BGAs to train with, I guess.As long as the data transfer between the FPGA and the MCU is within electrical specs, I don't mind the MCU framebuffer access occasionally being delayed some clock cycles. I'm much more worried about getting the approach technically correct, and not relying on "tricks" or picking parts that exceed specs, and getting sufficient write throughput for the MCU. That's also why I don't just cobble something together and call it done.You might remember my working out the TFT backlight driving some years back here, because I detest flicker, and some of the displays I have use LEDs in parallel so are not suitable for the cheap flicker-free backlight series-LED drivers. Combining ultrasonic PWM and (peak) current control is what I like. "Cheap but over-engineered", I guess!

author: pcprogrammer
author_rank: Super Contributor
timestamp: February 24, 2025, 12:32:17 pm
content: A QSPI interface between a MCU and a FPGA is simple. Lots of examples around for SPI, and adapting for 4 bits in parallel is simply adding shift registers for them. Depending on the external wires a 100MHz should not be a problem. No idea what the Teensy supports.An important thing in the FPGA side of this is to be aware of metastability. To make what you want having different clock domains is unavoidable, because the LCD most likely needs a different clock speed to push the data to it, the memory might run on a much higher clock and the bus with the MCU will also have it's own clock rate.To cope with crossing these domains internal dual port memory can be used to handle the data, but for handshaking it is needed to synchronize the signals to the clock of the domain they enter.This was a problem I encountered in my project. I had setup the double buffered dual ports and triggered the state machines with handshake signals, but without synchronization it locked up almost instantly in the real hardware. In simulation it looked perfect though. Now that I added the needed synchronization to the signals, it runs rock steady. See:https://cdrdv2-public.intel.com/650346/wp-01082-quartus-ii-metastability.pdfThe Tang Nano 9K can also control your smaller LCD's and allows you to play with what I wrote above. For the PSRAM used in the 9K the controlling is different than for the SDRAM in the 20K, but the principle will be the same.What I find to be a downer with the Tang Nano boards is that they used the 88 pin FPGA to keep it narrow enough, but this does not provide a lot of useful pins on the headers. Sure there are a lot of pins, but when you use the LCD connector maybe half of them can't be used anymore. Also you can't use and the LCD and the HDMI at the same time. They are also a bit pricey in comparison to what you get, at least to my taste.

author: tszaboo
author_rank: Super Contributor
timestamp: February 24, 2025, 12:39:52 pm
content: Here is an AI summary for that wall-of-text:QuoteMy suggestion is this:If you want to learn FPGAs, than buy an evaluation board, and connect it to another evaluation board. Because when your hadware doesn't work for whatever reason, you will be stuck, and no way to understand or correct why it doesn't work.

author: SiliconWizard
author_rank: Super Contributor
timestamp: February 24, 2025, 12:47:38 pm
content: There are a few things to consider: Nominal already has a Sipeed Tang Nano 9K, with which he could definitely implement what he wants. It has an embedded SDRAM, which is not too difficult to implement a controller for (and there are available out there too).Now he wanted to make his own board, so that also has constraints which may not make the Gowin FPGA route easy (as he mentioned). But in any case, I don't think that'll be wasted time. He can start by developing his ideas on the Tang Nano 9K, which is plenty for that, and once satisfied with the approach, make a custom board. And even if it's not the same FPGA, porting the code should not be hard, and SDRAM chips are available in workable packages.

author: tggzzz
author_rank: Super Contributor
timestamp: February 24, 2025, 01:01:01 pm
content: I recommend starting with an FPGA development board; you really don't want to be simultaneously debugging hardware, plus FPGA concepts, plus PCB PDNs, plus transmission lines. Presumably you want to concentrate onyourobjectives.There are many minor differences between programming FPGAs and MCUs, e.g. language syntax. I'll merely note the major differences you will need to understand:everything should be parallel; think of having an infinite number of hardware threads in an MCUclock domains, when metastability might rear its head, and how to tame its consequencesFSMs, and how to code them. There are many design patterns, but the "two process" pattern offers simplicity and maintainability. Process1= synchronous clocked state register, process2=asynchronous logic defining the next statethe building blocks primitives supplied by the FPGA manufacturer. Learn what they are, plus how to slot them into your design

author: pcprogrammer
author_rank: Super Contributor
timestamp: February 24, 2025, 01:02:29 pm
content: Quote from: SiliconWizard on February 24, 2025, 12:47:38 pmI find these Gowin FPGA's confusing when it comes to which memory is used. Member avst played with a Tang Nano 9K for the video capture thing we are working on and he told me that is has PSRAM instead of the SDRAM used in the FPGA on the Tang Nano 20K.But on the Sipeed site they mention SDR SDRAM 64M bits, although the picture of the board shows a GW1NR-LV9 QN88PC6/I5, and for that one Mouser states it has abundant PSRAM.So which is it.

author: SiliconWizard
author_rank: Super Contributor
timestamp: February 24, 2025, 01:12:55 pm
content: Quote from: pcprogrammer on February 24, 2025, 01:02:29 pmAh, that's because it can have either, depending on the package:https://www.gowinsemi.com/en/product/detail/49/The GW1NR-LV9 in QN88Ppackage appears to have PSRAM indeed, with a 16-bit data bus. And from the Tang Nano 9K schematic, is its a QN88P package. So, that would be PSRAM.Making the Sipeed Wiki bogus, which states SDRAM.

author: Nominal Animal
author_rank: Super Contributor
timestamp: February 24, 2025, 01:56:38 pm
content: Quote from: tszaboo on February 24, 2025, 12:39:52 pmThis is not that. I already have those for that purpose. This is a specific hardware project with specific issues – FPGA exposing RAM to an MCU, while simultaneously itself accessing that RAM; or using two separate RAM ICs and having the FPGA use one while the MCU uses the other –, and I want to better understand those issues before starting the actual build. I see many OSHW FPGA projects struggling with accessing external memories (although those tend to be higher bandwidth DDR dynamic memory chips).I could pick an existing FPGA dev board with sufficient RAM on it, but that isn't designed to interface that same RAM also to a MCU. This is a design-level issue; a typical devkit will have "sufficient" interface to RAM, and that may not be enough for me here, especially if I end up using two separate memory chips with each having their own data bus to the FPGA.Quote from: tszaboo on February 24, 2025, 12:39:52 pmI'm fully aware. I've used several other description languages before, I'm not stuck in the imperative worldview at all.(Not all programming languages describe the steps a "processing unit" should do. There are several completely different approaches, even though most software developers only learn the imperative approach (and occasionally a functional one, like Ocaml or Haskell). In particular, description languages describe the rules of operation, evaluating everything in parallel, instead of as a sequence of steps. OpenSCAD implements a simple descriptive language for its constructive solid geometry: there is no progression through the code, it's all evaluated at once, all statements in parallel. For animation, the entire "program" (geometry ruleset) is re-evaluated, once per animation frame, with a built-in variable representing the time/frame.)Quote from: tggzzz on February 24, 2025, 01:01:01 pmAgain, I have those.The question I'd like to focus on is the design and implementation aspects when interposing an FPGA between the MCU and the external RAM.All the background and context was there because I thought it was necessary to describe why "don't do that, <do something else> instead" won't work for this use case.The MCU access will not be linear, they will be random. The FPGA/display part will be quite linear. The issue is that those do not mix well, so as a workaround, I was thinking of using two separate external RAM chips, each with their own bus and I/O pins, so that while the FPGA accesses one, the MCU can access the other, with no contention.Another way to look at this would be to consider the case where you have two (identical) MCUs, and would like them to access a shared asynchronous SRAM (so no bursts), but dual-port SRAM is too expensive so you use an FPGA as the RAM controller.I see now that I should have omitted all that background context, and focus on the FPGA aspect, the technical details involved in using an FPGA between RAM and a MCU. Apologies; me fail, initial post poor quality. I will try to do better in the future. In the mean time, although I don't like changing the "past", I think I'll add a clarifying paragraph to the question, so others will more easily understand what I'm asking about.

author: tggzzz
author_rank: Super Contributor
timestamp: February 24, 2025, 02:11:56 pm
content: Quote from: Nominal Animal on February 24, 2025, 01:56:38 pmWhat primitives are in the FPGA hardware and/or library? Dual port RAM is not uncommon.What's the cycle time, latency, jitter and transfers/s for each of the RAM, MCU and display? Hardware FIFOs may be able to reconcile those, and are a typical library component.Understanding the specific FPGA's hardware building blocks and manufacturer defined library components ismoreimportant than understanding the processor instruction set and software library.

author: Nominal Animal
author_rank: Super Contributor
timestamp: February 24, 2025, 02:48:50 pm
content: Quote from: tggzzz on February 24, 2025, 02:11:56 pmRight. I haven't chosen any specific FPGA yet. The arithmetic-logic stuff I need is on low-bit-count integers, say 6-bit values, with the major one being a multiplication-addition between two 6-bit values and obtaining the high 6 bits of the results. To choose an FPGA well suited for being between an MCU and external memory, I'd need to understand the design aspects first, and indeed what manufacturer defined library components would be most useful here. I don't need a softcore in the FPGA at all, as the processing pipeline is basically a fixed display controller, just with a nonstandard nonlinear framebuffer.From your response and reading other FPGA threads here and elsewhere, it seems that most FPGA developers seem to use basically one family of ICs, and pick the problems they want to solve based on the capabilities of that chosen FPGA. I want to do the opposite, and hear what kind of library components are particularly useful for this topology, FPGA mainly as a memory arbitrator between an MCU and a fixed-operation core, or two MCUs.(To stave off the inevitable suggestion, I've already looked at and have dual-core MCUs.)Quote from: tggzzz on February 24, 2025, 02:11:56 pmI'd like to target 20ns or less random access single read and write cycles for the MCU, including uninterrupted back-to-back accesses (for 50Mwords/sec random access throughput). For everything else, I'm going to live with what I can get. For the display stuff, the access pattern is more linear (burst and prefetch/buffering possible) but with about four separate continuous data streams, with an aggregate sustained 40-70 Mbytes/sec read rate. Even the exact RAM size is up for discussion.So, any specifics on what to look for in this particular case? I definitely don't need dynamic RAM, so async SRAM, SDRAM, and PSRAM (including HyperBus) library stuff I already know to look for. What about the library components when the FPGA itself should look like RAM? Are those even in vendor libraries, or is it so much rarer use case that those who need such, use proprietary IP for that?Is the routing mux at the memory IC problematic? That is, if I use two separate memory chips and buses to those, I still want to the able to flip which accesses which. Or is faster random-access SRAM a better answer, perhaps time-domain multiplexing the FPGA and MCU accesses? Those with practical FPGA design experience will know; I'm hoping they'll tell.

author: tggzzz
author_rank: Super Contributor
timestamp: February 24, 2025, 03:37:09 pm
content: Quote from: Nominal Animal on February 24, 2025, 02:48:50 pmThe obvious component to look for would be a memory controller! That will indicate the feasible memory types and performance.Then just read the manufacturer's component library, understanding the type of component and how it might be used. Some components will be conceptually simple but the implementation will be tailored to the FPGA architecture - e.g. metastable-hardened synchroniser, or a FIFO which can be used to improve jitter and latency requirements/performance. Others can be complete subsystems, e.g. a DDS generator or FFT engine.QuoteThere's that tendency in MCU+software based designs as well.I think you'll find that the development environment and libraries are more of a lock-in than the FPGA itself. They are very complex and there is a significant learning curve. Essentially the choice is between Xilinx, Altera, and all the niches.QuoteThe FPGA will be several memory addressed control/status and data registers connected directly to the MCU's IO pins; any FPGA can do that trivially.The FPGA is also ideally suited for matching and arbitrating data transfers between MCU, memory and other components. Arbitration "clashes" will have to be accommodated by the FPGA and system architecture. There will be several different clock domains, which implies needing synchronisation components when crossing domains. Hopefully library components (e.g. FIFOs) will simplify that and aid implementing the system architectureAll that implies you need to do hardware-software co-design, just as you would with an MCUs peripherals and software libraries.QuoteYes repeat no, depending. RTFDS!QuoteProviding the system level throughput/latency/jitter requirements can be satisfied, the FPGA will be able to implement that.

author: xvr
author_rank: Frequent Contributor
timestamp: February 24, 2025, 04:00:17 pm
content: Having 2 RAMs for separate frame buffers can be a viable option if you have a lot of FPGA pins to connect 2 RAMs to and if you completely redraw each frame buffer for each frame. Otherwise, synchronizing the contents of different frame buffers will be a very painful task.Multiple image planes can also exhaust the RAM bandwidth - each additional plane requires an additional read from the RAM for each pixel. A more preferable way to organize a plane is to use the FPGA's internal Block RAM for creating sprites (multi-level and custom geometry)

author: pcprogrammer
author_rank: Super Contributor
timestamp: February 24, 2025, 04:55:20 pm
content: As an example on how to handle different streams, here is what I made so far for the video capture project. It uses block ram as semi dual port memory (one read and one write port) to interface between the SDRAM and the streams.With burst read and write there is a lot of room in the time domain to get things done. For the streams to display this is what you need to make it work. Not an issue with static memory of course, and depending on the FPGA there might even be enough block ram to do what you want without additional memory. Depends on resolution, color depth and number of planes you need.The SDRAM controller IP of Gowin is a bit obscure, and the manual does not provide much help, which made me decide to just write my own. Started with an example found on the net and made it fit my purpose.SDRAM is not that hard. The three control lines RAS, CAS and WE make up 8 commands and are clocked in on the rising edge of the clock. For a read or write operation you open up a row (RAS =0, CAS = 1, WEN = 1) and then wait a couple of cycles before sending the read or write command. For a write the column address and data have to be supplied on the same clock. For a read the column has to be supplied on the same clock, but the data comes out CAS clock cycles later.Within the same row reads or writes can be send directly, but when the row needs to be changed, you need to close the active row first with a precharge and then open up the new row and wait again before sending read or write commands.Using burst mode the data can be retrieved or presented on a cycle basis, which makes it quick.A refresh just has to be issued at timed intervals which is also done in my code. My setup uses about 30% of the available memory bandwidth, based on burst actions.The SDRAM used in the GW2AR-18 devices seems to be Micron MT48LC2M32B2 64Mbit SDRAM's. They don't seem to make them anymore.https://datasheet.octopart.com/MT48LC2M32B2TG-7-IT%3AG-Micron-datasheet-8193693.pdfFor the PSRAM I can't say. Have not played with it, but it is most likely very similar from a system point of view.

author: langwadt
author_rank: Super Contributor
timestamp: February 24, 2025, 05:05:22 pm
content: for such small display why are you even considering FPGA and external ram when you can get something like this for $10https://jlcpcb.com/partdetail/STMicroelectronics-STM32H7A3VIT6/C730222?

author: brucehoult
author_rank: Super Contributor
timestamp: February 24, 2025, 06:47:40 pm
content: Quote from: langwadt on February 24, 2025, 05:05:22 pmI'm unsure exactly what that gets you for your $10. In particular I didn't see a spec for RAM.OP mentioned BL808, but didn't mention CV1800B (available on the Milk-V Duo for $5, which is effectively a DIP breakout board) or SG2000.The CV1800B has 64 MB of in-package PSRAM, plus two USBs, and a 64 bit 700 MHz microcontroller. And bonus 1 GHz 64 bit Linux app processor with 128 bit vector unit. The Duo is normally booted from a micro SD card, but under where the cars sits there are 8 pads to solder on an SPI NOR or NAND flash chip instead.The CV1800B package is a 68 pin 0.35mm pitch QFN (7mmx7mmx0.9mm)

author: langwadt
author_rank: Super Contributor
timestamp: February 24, 2025, 07:19:23 pm
content: Quote from: brucehoult on February 24, 2025, 06:47:40 pm280MHz Cortex-M7 MCUs, 2MB Flash, 1.4MB RAM in a 100 pin LQFP

author: pcprogrammer
author_rank: Super Contributor
timestamp: February 24, 2025, 07:28:30 pm
content: Quote from: brucehoult on February 24, 2025, 06:47:40 pmOn the ST site is states 1376KB of SRAM.https://www.st.com/en/microcontrollers-microprocessors/stm32h7a3vi.htmlQuote from: brucehoult on February 24, 2025, 06:47:40 pmFor me QFN is a bitch to solder, but with a hot plate it might be easier, and that is what Nominal Animal has, according to his posts.But for display interfacing I think it might be a bit limited. The chip supports mipi for video input, but not for display output. The bigger SG2002 does have mipi output support.I think that a plus for the FPGA is the flexibility on connecting what ever display you like.

author: asmi
author_rank: Super Contributor
timestamp: February 24, 2025, 08:06:42 pm
content: Quote from: Nominal Animal on February 24, 2025, 08:17:20 amAs I understand, all these displays already have controller onboard, so you can connect them to MCU directly via SPI-like bus, no need for FPGA for that. FPGA is typically required to drive "dumb" panels which needs to be continuously fed with data to display as they can not display anything by themselves, though higher end MCUs often have peripherals to do that too.

author: Smokey
author_rank: Super Contributor
timestamp: February 24, 2025, 09:13:21 pm
content: As someone who has specced out the design for a product that does almost exactly what you are describing, I would recommend looking at off the shelf single part display driver solutions (memory/processor/interface/etc) first before trying to cost optimize with the least expensive separate micro, memory, and fpga hardware. Yes, it may be more expensive per unit but unless you plan on making 10,000 of these you will never make up the difference with the extended hardware and software (and hdl) development time and effort (especially if you are starting from zero).Before you start anything, make a spreadsheet and quantify all the numbers for what you are actually trying to do. Display resolution, bits per pixel, buffer sizes, data transmission bandwidths between micro-memory and memory-display, display update rate, serial/parallel busses. Don't get caught off guard by either the actual memory requirements or the data transmission bandwidths to support your desired frame rates. Higher resolution displays need bigger pipes than you would think at first and you don't want to be either surprised or backed into a design corner.One more thing... the display interfaces and configuration settings are almost never plug and play (especially if you get into DSI), and made exponentially worse by poor data sheets (there is a reason stuff like raspberry pi only support specific select LCDs despite having an interface with lots of options). Expect some pain and suffering getting here too. BuyDisplay has decent support for the space, but they only go so far technically if you only look like you are going to buy a couple displays and get too needy.

author: bson
author_rank: Unknown
timestamp: February 24, 2025, 09:15:28 pm
content: I would pick a fast SRAM and implement some sort of interleaved dual port interface. The reason is you will use up pins in a hurry with multiple memory buses. You could use two SRAM packages and interleave them on the same bus (just mutually exclude CS's) but that doesn't really buy anything over a single package split into two logical memories. You're already looking at maybe 25-30 pins per bus.Make your life easier by picking a high speed grade, low complexity (low LUT count and features) FPGA. I'd also suggest sticking with one of the big vendors for now as their integrated tools, crappy though they often are, significantly lower the learning barrier. And let's be frank, you can spend a LOT of time without any hardware, just designing modules and test benches, running simulations, and understanding how to use constraints effectively. So you could just pick something like a MachXO2-640-6, install Lattice Diamond, and go to town - just pick a 100 pin device and pretend you're going to use it. It's pretty easy to change devices, or have multiple devices or speed grades (another learning barrier) in a project. A lot of QFP parts available. The big tools have reasonably complete (though extremely scattered and normalized) help trees, application notes, and sample projects to mine for ideas.I think the easiest is just to set up a toolset, pick a device, and start designing. Find out what works and what doesn't, what the tradeoffs are. Verify with test benches. Debug using printf's and wave diagrams. You don't actually need any hardware for this.I have a couple of "learning" books, and they are so elementary as to be useless, so I won't name them. They're more about introduction to logic design rather than how to implement logic in FPGA - I mention this since I think you'd done plenty of logic design before, or at least understand how it differs from software for a Von Neumann machine. If you have logic circuit design experience you're going to love FPGAs.

author: Someone
author_rank: Super Contributor
timestamp: February 24, 2025, 10:01:54 pm
content: Quote from: Nominal Animal on February 24, 2025, 01:56:38 pmDid you know a good portion of FPGA design are prototyped on dev boards before any hardware is designed/built? While you don't have an architecture planned out (or as above calculated in terms of bandwidths) it is too early to be thinking of what parts are going into the mix.Just like in software you can build out some stubs/simulations of bits of the system that are large/complex and test the bits you are unsure of under some limited/basic conditions, to check if it the concept is feasible.What has been repeated and re-inforced in this thread is "two memories, exclusive access by two masters" but that does not match up with your desired single unchanging background plane with dynamic planes being updated over the top. Your description leads towards having multiple buffers for each of the planes that can be swapped in and out per plane, which isn't hard in a single memory address space.Quote from: Nominal Animal on February 24, 2025, 08:17:20 amHaving multiple [arbitrary description of separable operations] accessing a single memory is the dominant paradigm of software, and naturally extends to what you are doing. The FPGA/hardware specific counterpoint is synchronous (or close to) streaming which might only be applicable to the pixel output pipeline.Where is the blockage in connecting [arbitrary write only] master and [arbitrary read only] master to a conventional memory? Ignore the specific interfaces they use for the moment, break it into understandable bits. If that does not make sense then adding multiple readers (and/or writers) will really get you confused.

author: Nominal Animal
author_rank: Super Contributor
timestamp: February 25, 2025, 05:36:35 am
content: Quote from: brucehoult on February 24, 2025, 06:47:40 pmYup. I already have a SG2002 (Milk-V Duo 256M), its "big brother", too. CV1800B would do absolutely fine for me, but I don't see any hobbyist designs to compare to. The schematics (PDF) and docs are available, but I'm not sure if I can pull that off as a hardware design. I fear I'd be bitten by the power-up sequencing of the four supply voltages it needs (3.3V, 1.8V, 1.35V, and 0.9V).Quote from: brucehoult on February 24, 2025, 06:47:40 pmI suspect my soldering results for 0.35mm pitch QFN would be even worse than they are for 0.8mm pitch BGA.(Even the early versions of SparkFun MicroMod Teensy, using an M.2 connector for peripherals, suffers from contact issues due to the PCB bending a little. Using a thicker PCB would help, but standard M.2 connectors limit the thickness. I don't like the idea of trying to do single boards better than SparkFun can design and manufacture in batches.)Quote from: asmi on February 24, 2025, 08:06:42 pmYes. The ones I like most use ILI9341, ST7789, ILI9488, and similar controllers (they have only minor differences between them) exposed via 40-50 pin FPC.In the overlong background, I explained that I already have flat framebuffers in hardware, but would prefer a layered one instead, with one full-color background framebuffer, with two or three indexed-color/paletted overlay framebuffers with full alpha support on top. I can do this in software on a sufficiently high-powered ARM microcontroller, but the composition is a parallelizable operation best suited for FPGAs and ASICs, not general-purpose processors. Icoulddo this the retro way, using discrete logic and fake ALU chips (MCUs or SRAMs or EEPROMs), all running off a 12-18 MHz bus clock, combining data from 3-4 parallel data buses (retro way using SRAM chips with address coming off a counter).Quote from: Someone on February 24, 2025, 10:01:54 pmNo, they are all mutable. I could show the software implementation of the approach, and how much this reduces memory use and required memory bandwidth if the composition of the planes is done by external hardware. Simply put, in my use cases and omitting the composition cost, the memory use and number of operations needed per displayed frame is a small fraction of that needed when using a standard flat full-color framebuffer.Even more so, if the plane is slightly larger than the visible area, and the start address is programmable within a fixed-size wraparound region, for implementing scrolling. Only the new data becoming visible will need to be written, old visible data does not need to be touched.It is a waste of resources to recompute each pixel every frame if you only have one general-purpose core, though.Quote from: Smokey on February 24, 2025, 09:13:21 pmLike I wrote in my overlong initial post, I have already implemented this on a microcontroller, and have played extensively in software implementations of such nonlinear framebuffers. It is not a question of whether I can do it, but whether I can do it "better" than what I already have, within my oddish constraints. My budget is close to zero because of personal situation, but I have no time limit at all. I've played with this for years now on ARM MCUs as a hobby already.It can sound odd that I want a "real" FPGA project when I haven't properly learned any HDL yet (target being Verilog-2005 due to Yosys support). Thing is, I know how I learn best, and having an example use case to apply my understanding to is very useful. Choosing the complexity level is tricky, because I quickly lose interest when the problems are easy to solve; but can chew on them if they are difficult but not clearly intractable for a single hobbyist. Don't worry, I will not be limited to the subdomain that covers my immediate needs, though: that only acts as my opening, my stepping stone, into understanding the entire approach, the worldview, the paradigm, with my curiosity driving me to expand outside my immediate needs. This just works very, very well for me, and helps me keep an open mind, not letting my existing conceptions hinder me. Not everyone learns like this, though, so this approach may seem ass-backwards or even doomed to failure to others, just because they learn best some other way.Quote from: Someone on February 24, 2025, 10:01:54 pmOf course. I've got a "library" (mostly in offline storage) of thousands of such unit test cases in software, examining specific algorithms and math, accumulated throughout the years.I do believe I'll start by connecting one of the FPGA dev boards I have to one of my Teensy 4.1 MCUS, with the FPGA pretending to be PSRAM. Teensy works very well withAPS6404L_3SQRQSPI PSRAM at 84 MHz clock, and I can lower the QSPI clock to compensate for leads-in-the-air wiring (but I'll try to use the every-other-wire-is-GND approach too). For read tests, I can use the address bits reordered and XOR'd to generate the data, and verify all sorts of read access patterns by the MCU yields correct results.Next step, I can implement read-write access by using internal RAM (for example, using only a few least significant bits of the address).Separately, I can connect an APS6404L PSRAM or more, each with their own QSPI bus to an FPGA, and that FPGA to a Teensy 4.1, and test the case where the FPGA is a simple multiplexer. For control, I think I'll use an UART, with one-byte commands from the MCU to the FPGA, with the FPGA responding asynchronously with one-byte state information when the command is completed. I need the asynch'ity later. I'll also do the UART FPGA implementation separately first, before combining with the PSRAM muxing.This is how I do software development in general, too: I implement subsystems in isolation, but with a view of future integration/adaptation. After verifying the subsystem works in isolation (often using a test harness), I integrate the subsystem to the separate combined project, followed by rigorous testing. (I do not usually create software libraries per se, as I end up adapting each previously tested approach for a new use case. I do not copy-paste or just include my old libraries; I've found I get better results when I adapt each tested approach to the needs of each actual use case. Testing each adaptation thoroughly before integration is very important, though: bugs will occur, but limiting them to a small changeset avoids a lot of frustration and saves time.)I'll do the FPGA-only display controller separately, too. I already have a Tang Nano 1K and Tang Nano 9K with compatible display modules to do this with. I've also got the schematics for these, and Mouser sells the FPGA ICs, and the basic schematic seems simple enough that I should be able to design my own board with these later on.As a next step to that, I can check if APS6404L_3SQR PSRAM (in linear bursts) as a data source for the framebuffer is fast enough, and get a ballbark idea of the kind of resources and data bandwidth needed from the FPGA for this aspect of the future whole.A sensible plan seems to be building up nicely, thanks everyone!

author: pcprogrammer
author_rank: Super Contributor
timestamp: February 25, 2025, 08:02:06 am
content: As to simulation, mentioned by others, it most likely does not reveal metastability issues unless you simulate very long runs, and even then it might be difficult to spot that it went wrong.In my case the simulations I ran revealed nothing, but perfectly working logic, that allowed me to tweak some timing issues with passing data from the block memory to the SDRAM. Only when I tried the design on the hardware it revealed problems.So yes, simulation is very helpful in verifying the logic of the design, and tweaking it when needed, but don't rely on it to be absolutely correct.

author: brucehoult
author_rank: Super Contributor
timestamp: February 25, 2025, 08:39:17 am
content: Quote from: Nominal Animal on February 25, 2025, 05:36:35 amYou can use a Duo as a 2.5mm pitch DIP chip. It's cheaper than many of the MCUs being mentioned -- and I think far cheaper than any FPGA that would do the job, not even counting accompanying MCU.QuoteThe Duos all do 128 bit vector processing, with over 2.2 GB/s of total DRAM bandwidth available. eg. a 1 MB to 1 MB memcpy() using RVV takes 0.864 ms, or 1130 MB/s = 2260 MB/s total bandwidth. That's at the default 850 MHz speed of the official buildroot image. I don't think 1 GHz would help it -- the CPU core is already capable of over 3100 MB/s memcpy in cache for transfers from 2k to 16k buffer size.It's still going to saturate the memory bus with some operation involving reading multiple vector registers of data from different buffers and doing some 8 bit AND / OR / MIN / MAX / blend operation on them.And don't forget you can control 8 bit or 32 bit pixels with 1 bit per element mask registers, and do AND / OR / XOR etc on masks too.How fast do you need?QuoteHow wide RAM chips?4 parallel 8 bit buses at 16 MHz is 64 MB/s, or 256 MB/s with x32 SRAMs. Even the 256 MB/s is only 10% of the 2260 MB/s a CV1800B can do in its 64 MB RAM.

author: Nominal Animal
author_rank: Super Contributor
timestamp: February 25, 2025, 10:15:49 am
content: Quote from: brucehoult on February 25, 2025, 08:39:17 amI didn't think of that, d'oh.The ALU needed for ARGB processing is a simple one, working with three 6-bit units in parallel, with 6×6=6-bit multiplication operation, and 6-bit addition and subtraction operators. The planes can also operate in parallel, working on sequential pixels at the same time in a pipeline.Essentially, we start with the 15-bit r5g5b5 color, expanding it by copying the MSB to new LSB on each to 18-bit r6g6b6. I might do some shenanigans with the unused half of the colorspace. Before generating pixels, at the start of a new frame, each plane reads in a 256-entry A7R6G6B6 palette (25×256 = 6400 bits, probably using 32-bit words or 1024 bytes on the external RAM per plane). There is plenty of time to do this; it's done at about 14ms intervals (70 Hz or so). Each plane receives the 18-bit r6g6b6 value from the plane below it in the pipeline, with the full-color one at the bottom, and a stream of 8-bit color index values from the plane buffer.. Each 8-bit value is looked up in the palette, and the two values combined usingr_new = ((64 - a) * r_0 + a * r_1 + 32) >> 6g_new = ((64 - a) * g_0 + a * g_1 + 32) >> 6b_new = ((64 - a) * b_0 + a * b_1 + 32) >> 6and the resulting 18-bit color r6g6b6 passed to the next plane in the pipeline. At the output, the 18-bit color may be truncated to 15/16 bits, but it's all parallel data with a write strobe to all the controllers I have, running at 6 to 18 MHz clock frequency. Clock jitter is not a problem, either, the bus is asynchronous.I wonder if I could use the NPU for this?With 32-bit general purpose processors, I limit to r5g5b5 (binary 0b00000RRRRR00000GGGGG00000BBBBB) or r5g6b5 (binary 0b00000RRRRR000000GGGGGG00000BBBBB), so it's just two multiplications per plane per pixel, plus additions, shifts, and AND masking to clear the high bits for the next plane. The palette is similarly expanded, and the result is only compacted for the output pins. (Teensy doesn't have a contiguous set of I/O pins exposed, so instead I exclusive-OR the result with the previous output word, and three 64-word look-up tables exclusive-OR'd together, saving the result for next, and writing it to the GPIO bank DR_TOGGLE to update the output pins.)With 6-bit modular arithmetic, special-casinga=0anda=64, the calculation can be implemented asc_new = ((c_0 << 6) + a * (c_1 - c_0) + 32) >> 6noting that the temporary result is 12 bits. You don't need to worry about overflow or underflow: as long as you ignore the extra bits, the result will be correct. (The full ALUs I want need 6+6+6=24 or 6+6+7=25 input bits, and 6 output bits; and I need nine of them. Or, I can use the expanded form and two 12/13-bit input and 6/7-bit output ones with an adder in Y form. I never said discrete logic would be trivial, just feasible. Many FPGAs seem to have hardware single-cycle multipliers, which would be extra nice here.)I tend to not need the other blitting modes this way. Even shadows work just fine using RGB blending. Using La*b* or YCrCb colorspace would give better results, but it's not like I need specific operations per se, just something that looks nice and doesn't limit me in ways I don't like.My preferred displays are 320×240 with 70 Hz optimal refresh rate. That corresponds to 10,752,000 bytes of 16-bit color data plus 5,376,000+71,680 = 5,447,680 bytes per plane, per second; say 27,095,040 bytes per second. Using 6-bit modular arithmetic, I'll need 48,384,000 multiplications and 435,456,000 additions or subtractions per second, which corresponds to about 5,376,000 multiplications per second per arithmetic unit.On a 32-bit ARM core, it is about 16,128,000 pixel blends per second. And parallelizes easier than anything I've worked with before. It's a very clear pipeline.I might want to scale up to 480×320, doubling all of above, but that's the maximum scale I'm interested in. Anything larger, and I'm better off using an embedded Linux stick with OpenGL ES support for controlling the display anyway. (The default non-HDMI TFT LCD for Tang Nano 9k is 800×480.)I need to check the RISC-V vector instruction set supported, but I do believe Zve32x extension (vmulhu.vxorvmulhu.vvat EEW=8) would work well for me here, using one byte per color component. In that case, it might make sense to blend one scan line at a time over the three planes in sequence, to keep the data in cache (might need to be written in assembly, with suitable prefetches in place). I've written MMX/SSE/AVX SIMD assembly code before, both by hand and using GCC vector extensions.The only thing is that @SiliconWizard is the only one who I've heard has done bare-metal, non-Linux development on Milk-V's. He posted about this in a thread here.

author: brucehoult
author_rank: Super Contributor
timestamp: February 25, 2025, 11:13:59 am
content: Quote from: Nominal Animal on February 25, 2025, 10:15:49 amThe data and computation rates you're talking about are trivial for a Duo, straight from RAM you don't even need to worry about cache. Just bear in mind that the vector unit is on the "Linux" applications processor, not the MCU core. But you can pass data between them. Or just let uboot SPL to get the hardware up and then simply run your code not the Linux kernel.Also recall that the vector ISA is XTHeadVector aka RVV draft 0.7.1, which is supported by gcc 14+ vector instrinsics (C source code compatible with RVV 1.0), but also also far far easier to program in asm than AVX etc. For such a simple computation I'd definitely use asm.Duo's RVV supports 8/16/32/64 bit integers and 32/64 bit FP.https://github.com/riscvarchive/riscv-v-spec/releases/download/0.7.1/riscv-v-spec-0.7.1.pdfThe optional ediv feature is not implemented (and was dropped from RVV 1.0 in favour of fractional LMUL)

author: Someone
author_rank: Super Contributor
timestamp: February 25, 2025, 11:42:07 am
content: Quote from: Nominal Animal on February 25, 2025, 05:36:35 amWhere did I say immutable? If you have two bank switched memories each with exclusive access then any change to any layer must be completed in full, and then applied to the second page/bank (unless it is transient and only appllies for a single step of the animation, which is why I used the unchanging background as the example). This is what you said:Quote from: Nominal Animal on February 24, 2025, 08:17:20 amMissing that the background would need to be present in both the banks!If planes are blocks within a linear space you only have to update the "new"/pending buffer of the plane that is changing, all unchanging content in memory is only in a single place (reducing storage and bandwidth demands).Quote from: Nominal Animal on February 25, 2025, 05:36:35 amSounds like you don't actually want any advice, your funeral.

author: Someone
author_rank: Super Contributor
timestamp: February 25, 2025, 11:46:52 am
content: Quote from: pcprogrammer on February 25, 2025, 08:02:06 amWhich is where the dev kits come in, so you can deploy some slimmed down and/or stubbed out test vehicle to shake out the non-deterministic bits. Without having to worry if it's your undersized power supply or stubs in the DDR RAM routing causing the problem.

author: tszaboo
author_rank: Super Contributor
timestamp: February 25, 2025, 12:48:42 pm
content: Quote from: Someone on February 24, 2025, 10:01:54 pmExactly, there is no way I would approve the start of a PCB including an FPGA, without seeing first a proof of concept working. And by proof of concept, I mean everything complex demonstrably working. Maybe less sample rate or resolution or communication speed. And especially the most overlooked part, how the entire thing is going to get programmed and verified. I've seen people connect JTAGs together, because "Its all software defined hardware anyway" and "JTAG specification allows this", just to find out you cannot program parts of it, because the toolchain doesn't implement all optional JTAG stuff. The number of pitfalls is very high.But still my favorite was looking at DDR2 signals, that need to be within 15ps of each other with a 200MHz oscilloscope.

author: Nominal Animal
author_rank: Super Contributor
timestamp: February 25, 2025, 06:05:50 pm
content: Quote from: brucehoult on February 25, 2025, 11:13:59 amOn Teensy 4.1 (NXP i.MX RT1062 ARM Cortex-M7) using 5 bits per color component, using naïve Arduino C++ code, it is less than 29 cycles per pixel to compose the four-layer framebuffer (likely applicable across ARMv7e-m, but there's plenty of room for optimization here). For a 320×240 display at 70 Hz, that's 26% of the CPU cycles running at 600 MHz (using 380k of RAM). And that's with utterly unoptimized code, using plain 32-bit unsigned integer arithmetic, too. I did say I already have thisworking, I just want to do it in a better way.I use completely randomized 320×120-pixel test data, re-randomizing the source data between compositions, the ARM_DWT_CYCCNT cycle counter for the measurements, and running the test for thousands of frames, so this is the baseline to improve on, not an optimistic estimate.Milk-V Duo is a 64-bit C906, so it won't do any worse, that's for sure. With 6 bits per color component,vsmul.vvwith SEW=8 only needs 8 bits per color component (so 8 color components per 64-bit register; 8 pixels in three registers), so it may domuchbetter. Expanding the full-color data to a padded form is something that I can for sure improve on, similarly for writing the parallel data to GPIO I/O bank on output; I need to take a careful look at the vector load instructions.Quote from: brucehoult on February 25, 2025, 11:13:59 amForgot; thanks!Quote from: Someone on February 25, 2025, 11:42:07 amI think me fail English, because to me that is obvious.The two-bank idea is just a possible workaround, if the framebuffer memory isn't fast enough otherwise. I'm sure proper designers just upgrade to hardware that is fast enough –– that's what HPC simulator folks do, too, instead of fixing the software instead. I plan ahead, so I always have alternatives and backup options.I'm not just jumping into "production" straight away, either. I'm trying to see what I need to investigate to come up with an FPGA design in the first place, what kind of experiments I need to do to find out my practical requirements, and so on. This will take a lot of time, but that's fine.Quote from: Someone on February 25, 2025, 11:42:07 amI don't get how you got to that conclusion. I intended the "I believe I'll start" as my current understanding of the suggested approach with an FPGA, using whatever hardware I already have available as an example, ending with a conclusion that this plan of attack makes sense to me. Which part of that is rejecting any of the advice suggested thus far? I'm serious, and want to know. Or did I just explain it poorly? (I do fail that way often.)I do have some hardware already at hand, but I'm not tied to them, although I have plenty time but no money to spend.

author: hgl
author_rank: Regular Contributor
timestamp: February 25, 2025, 06:08:59 pm
content: If it is mainly about the memory and not about FPGA you can use this board.https://de.aliexpress.com/item/1005006147123388.htmlInternal Ram 1Mbyte + external Ram 32MByteThe board also has LCD parallel RGB and serial SPI interfaces.You can read more about this in German here :https://www.mikrocontroller.net/topic/571964

author: asmi
author_rank: Super Contributor
timestamp: February 25, 2025, 06:53:51 pm
content: I just want to mention that you'd better make sure your memory has sufficient bandwidth to support your application. Video applications require surprisingly high amount of bandwidth. For example 480p@60 Hz video stream requires 640x480x4x60=70.3125 MiBytes/s of bandwidth for just a single stream, and in your case you need at least 2 streams (1 stream for each layer) + you need to leave some bandwidth for CPU and other processes. Here are some ballpark bandwidth numbers for memories typically used with FPGAs:Asyncronous SRAM 16 bit / 10 ns2 * (1000 / 10) = 200 MiBytes/sSDRAM 16 bit / 166 MHz2 * 166 = 332 MiBytes/sHyperRAM 8 bit / 200 MHz1 * 200 * 2 = 400 MiBytes/s (beware of high initial access latency!!!)DDR1 16 bit / 200 MHz2 * 200 * 2 = 800 MiBytes/sDDR2/3/3L 16 bit / 400 MHz2 * 400 * 2 = 1600 MiBytes/sDDR4 16 bit / 1.2 GHz2 * 1200 * 2 = 4800 MiBytes/s

author: iMo
author_rank: Super Contributor
timestamp: February 25, 2025, 07:22:02 pm
content: FYI - an fpga between an MCU and a psram..https://forum.arduino.cc/t/8mb-ramdisk-external-ram-for-arduino/215093

author: brucehoult
author_rank: Super Contributor
timestamp: February 26, 2025, 04:23:16 am
content: Quote from: Nominal Animal on February 25, 2025, 06:05:50 pmI've never has a 4.1 but I'm familiar with Teensy 4.0. It's a pretty fast processor for sure, but unfortunately doesn't have NEON (or MVE, which *is* in the more recent M55 and M85).But 5 bit components do make it easy to do make it easy to do SIMD-in-GPR with 4 or maybe even 5 elements per 32 bits, even with adds that might overflow. Only 3 elements though if you want to do 5x5 multiplies/scaling/blending (and it will have to be multiplying all elements by the same value. not per-element like real SIMD can do)Quote128 bit vector registers, so 16 elements in parallel.If you have fewer than 8 variables (I think yes?) then you can pretend you have 512 bit vector registers with LMUL=4. C906 takes 3 cycles per 128 bits for most vector operations, so there is no immediate advantage in using longer LMUL, but it does let you spread the loop overhead and pointer bumps over more data.

author: Smokey
author_rank: Super Contributor
timestamp: February 26, 2025, 08:01:21 am
content: Quote from: asmi on February 25, 2025, 06:53:51 pmI'm glad someone finally brought this up

author: Nominal Animal
author_rank: Super Contributor
timestamp: February 26, 2025, 09:38:05 am
content: Quote from: brucehoult on February 26, 2025, 04:23:16 amExact same MCU, just different pins exposed and more useful stuff on the board (like support for two 8 MByte PSRAM chips).Quote from: brucehoult on February 26, 2025, 04:23:16 amYup. In practice, because the 8-bit indexed planes need a look-up anyway, the palette is premultiplied with the corresponding transparency, yielding a 32-bit r10g10b10 color value per pixel, and a 6-bit opacity (32 - transparency). That means that the original background color is first expanded to o5r5o5g5o5b5 pattern –– that's a major chunk of the cycles needed! ––, then multiplied by the opacity, the premultiplied color value added, result shifted down, and ANDed with 31|(31<<10)|(31<<20) in preparation for the additional planes. Further indexed color planes look up the index, the premultiplied palette color value based on the index; and thus require just the multiplication, addition, shift, and AND. Finally, the 5-bit color components are extracted, each looked up in a separate 32-entry 32-bit tables corresponding to GPIO pin configuration. These three are exclusive-OR'd together and the current pin state, the result saved as the new pin state, and written to the DR_TOGGLE register. This allows any output pin order without affecting the other pins, as long as the 15 pins are in the same GPIO bank.The exact same math works for r10g12b10/r10g11b10 and r5g6b5, too.With RISC-Vvsmul.vvon 8-bit elements, each element is anint8_t, and I can use thec0 + alpha*(c1-c0)form, becausevsmul.vvreturns the most significant bits. One subtraction, one multiplication (with right shift), one addition. (I used your machine translated C906 PDF to verify C906 has this.) 24-bit background full color plane would be optimal, as it'd need no expansion, but 16 bits suffices and is denser, thus faster to render to and blit pixmaps to, pixmaps using less memory, and so on; so expanding r5g5b5 to r8b8g8 will likely take more cycles than the calculations do.To circle back to an FPGA implementation:For an FPGA, the latency in the operations does not matter as long as it is constant, because this is a pipeline, and the output-to-memory-read latency just does not matter at all. Even a simple barrel multiplier-adder implementing((64-alpha)*c0 + alpha*c1 + 32)on 6-bit unsigned c0 and c1 and alpha=0..64 (nominally 7-bit), and using only the high 6 bits of the result for the next step, will work absolutely fine. There are three of these in parallel for each plane, so nine operations per pixel, plus of course all that lookup stuff to get the color component and alpha values. It is, essentially, a ridiculously simple fixed arithmetic pipeline. Something like this is included in many Cortex-A7 2D DMA pixel engines, doing exactly these calculations in a separate mini-engine using DMA to read and write the data. And I only need ~ 11 Mpixels/sec throughput (5 bytes per pixel total across planes, with total three color and alpha lookups, one each from a 256-entry LUT). Very, very simple. But, when I started looking at combining this as exposing some expernal memory to a MCU, that's where I found I had no good starting points, resulting in this thread.Quote from: brucehoult on February 26, 2025, 04:23:16 amAh, yes. Got a brainfart having read NEON docs at the same time. Three 128-bit vector registers can do 16 pixels in parallel, but the main complexity there is to expand the 16-bit background color to 24-bit. It may end up being more efficient –– doing fractionally more multiplications but wasting less cycles in unpacking the color components –– to use only 75% of each vector register, doing just 4 pixels per 128-bit vector register.On an MCU, having to strobe the WRITE output pin in the middle of stable data is a yet another pain. I could use a scan-line buffer with GPIO bank toggle data, but either I'd have to waste every second word to toggling just the WRITE pin, or I need careful DMA triggering from a synthesized WRITE pin signal, or a small external logic circuit to generate a 10-20ns delayed pulse (remaining high for 15-25ns) from each rising or falling edge of a dedicated pin, asynchronously.I like the async edge-to-pulse approach a lot, and would like to integrate that to the carrier board. I haven't investigated that further yet, because I have absolutely nothing that can measure such short pulse durations or time intervals, and would have to rely on trusting simulations and seeing if it works.Thus far, I've stuffed the WRITE strobe inside the topmost plane scanning, so that it occurs approximately halfway between the data pin toggles. Less than stupidly naïve code does get quite complicated, with this kind of juggling memory accesses, GPIO pin toggling, and ensuring the cpu core pipeline is not stalled for stupid reasons, so this is one of the very rare cases where writing the key code in assembly is definitely warranted. GCC and Clang do make it very easy, allowing extended inline assembly inside C sources, so that one doesn't even have to know the calling conventions; that's how I normally do this. It's also why I don't want to make it public, not yet at least: it's the kind of code that shows the true colors/mettle of a developer, and I'm not mentally ready to be scrutinized at that level. Again. Yet. It's like showing up in public naked.Considering my very limited budget, but no time limitations, I think a carrier board for Milk-V Duo would be my best bet here. It has 64MiB of fast RAM, a high-speed USB 2.0 that I crave, and two cores, one of which I can dedicate for the framebuffer processing. Then, I can also change the framebuffer design –– limited only by the one C906 core capabilities of compositing it to an external display –– without hardware changes. It is a bit unfortunate, because now I don't have a good motivation to really get into FPGAs.There is also LuckFox Pico series based on Rockchip RV1103G1/RV1106G3 with a 32-bit Cortex-A7 (1.2 GHz) and a 32-bit RISC-V MCU running at 300 MHz, which has a 2D graphics engine capable of this kind of composition, and 128 MiB of RAM. I prefer the Milk-V Duo (64-bit RISC-V rv64gcv noting the vector engine differences) myself; just pointing out an alternative.Quote from: Smokey on February 26, 2025, 08:01:21 amI told everyone in the initial post that I need at most 70 Mbytes/s bandwidth to the FPGA, and described my preference of 320×240 and 480×320 displays. In #12, I reiterated the 40 Mbytes/s to 70 Mbytes/s aggregate bandwidth to the FPGA. In #28, I re-mention the 320×240 70 Hz display modules, then bluntly say "I might want to scale up to 480×320, doubling all of above, but that's the maximum scale I'm interested in. Anything larger, and I'm better off using an embedded Linux stick with OpenGL ES support for controlling the display anyway."I don't know how to make this any more clear, but I'll try:I am only interested in display sizes and resolutions up to 480×320 70Hz, i.e. maximum 11 Mpixels/second throughput.My preferred data formats are one R5G5B5 background plane (16 bits per pixel, 344,064-byte buffer including nonvisible portions; linear access pattern with 22,000,000 bytes/second read rate), plus three overlaid 8-bit indexed color planes (8 bits per pixel, 172,072-byte buffer per plane including nonvisible portions; linear access pattern with 11,000,000 bytes/second read rate each) plus 256-entry A6R6G6B6 LUT palette each, loaded just before the composition of each frame begins, at about 70 frames per second. This computes to around 55 Mbytes/s data read rate in the aggregate. Because of the underlying mechanics, I'd like to do it slightly faster, although I can slightly reduce the frame rate also if needed, so I added a 25% margin. That's where the 70 Mbytes/s aggregate rate comes from.The existingun-optimizedCortex-M7 (NXP i.MX RT1062) implementation uses 29 cycles per pixel running at 600 MHz, consuming about 26% of processor time (156M of 600M cycles per second) with 320×240 70Hz displays, and 52% (312M of 600M cycles/sec) with 480×320 70Hz displays. I feel this is wasted, and want to domorewith that processor instead of just running a simple fixed pixel pipeline on this$22/$24/$30development board. PJRC sells the proprietary bootloader and power sequencing IC, so I can even make my own Teensy-compatible boards. And I'd be happy to use some other MCU as well, as long as it has sufficient RAM, high-speed USB 2.0, and can drive a parallel display controller (~ 22 I/O pins). Of course, I don't want to have to share the only MCU core with the display pipeline either, I just want to separate the pixel pipeline to a simpler slave.This is not a product, it's my hobby project, albeit with real, non-commercial, use cases helping nontechnical users understand what their Linux appliances are up to, in humorous and visually pleasing manner. (I don't do the graphics myself; I know actual artists who do. Plus I use open source resources like various versions of Tux the penguin.) I do know of several retro-style game projects that would benefit from similar display controller or "graphics card" for a MCU, so I'm hoping to open-source my designs, as soon as I'm comfortable with others assessing my work in public. I'd be very happy to add/modify the planes to tile maps for retro game development, similar to what 90s-era game consoles and arcade games used, for example.The most pleasing implementation to me would be an FPGA that exposes external memory to a microcontroller, with the FPGA also using a very trivial fixed pixel pipeline with no latency requirements (so even barrel multiplication and addition of the 6-bit color components is absolutely fine, because the display data can lag the framebuffer reads by any amount, it just doesn't matter). That way, I and others could use different microcontrollers, whatever is needed, and even reprogram the pixel pipeline for those retro graphics projects, for example using tile maps or voxel rendering. (I did many such in the nineties myself, and have the best of those squirreled away for future use.)Although I'm an utter newbie with FPGAs, my background in various programming techniques including descriptive languages (but just no HDLs yet) means I can alreadyreadVerilog, so I know from other projects, and having the existing working MCU implementation, that the pixel pipeline is absolutely no issue here. If I didn't have an existing MCU implementation, I wouldn't know for sure.What I do not know, is the design points when interposing an FPGA between external memory and a MCU, while the FPGA itself also wants to access that same external memory. I have seen that other projects often struggle with external memory management, although mostly those are with dynamic RAM, not static or pseudo-static or SDRAM, which are what I'd like to use. Most hobbyist ones use development board integrated memories, avoiding that issue altogether. None of my friends I meet in real life do FPGA design, so I'm pretty much in the dark about theengineering aspectsof such designs.I do not have an exact requirement for the read-write bandwidth allocated to the MCU, because I am in control of that: I'd like to have that in the same ballpark as $1-$4 SRAM/PSRAM chips (in singles at LCSC/Digikey/Mouser, not bulk prices), as that is what these MCUs would use normally anyway. To that end, I imagined that bank-switching, having the MCU access one while the FPGA accesses the other, would be a suitable solution: FPGA would be simpler, basically a cross-point switch, separate from the the pixel pipeline. It's not a design parameter, just an option I can consider and try.Again, I have a working pixel pipeline implementation on an MCU, but I have nothing regarding the external memory, except one (family) of PSRAM chips that I know works with one of my microcontrollers, and another (much slower) MCU that I'd be happy to use also with an easier parallel async SRAM interface (with multiplexed parallel data and address pins). No designs, no chosen FPGAs, no memory chips selected; only examples of what I already have, so you have an idea what class of hardware I'm looking at. I also have FPGA dev boards to do unit testing and related and unrelated exercises as part of learning HDL, and although I'd like to do that in parallel with the design phase of this project, I think it is separate, normal, expected, and don't have any interest in discussing those learning aspects here.What kind of help am I looking for, then?Pointers on those pitfalls and traps for young players when putting an FPGA between a MCU and external memory.Clock domains and synchronization I'm already aware of, but otherwise I read that such interfacing is simple, and usually done with FPGA vendor library designs.I'd like to know more about the rules on how to choose suitable parts, because I do not have strict requirements yet, and I'd like to balance those requirements with costs, and have the result be achievable to a hobbyist. Also, if that is too much to ask, I'd like to know that too.If I wanted the FPGA to look like a 133 MHz QSPI PSRAM using 4 data pins, one clock pin, and a chip select pin, using the same command set that standardAPS6404L_3SQRPSRAM supports – simply because that is already extensively tested to work very well with the MCUs with QSPI PSRAM interfaces at 84 MHz clock –, how that affects the design? What kind of 1-8 MiB / 8-64 Mbit RAM would be fast enough for thatplusthe four aggregate linear burst streams that total to less than 70 Mbytes/second? The 300 MHz+ async SRAM chips that are available at Mouser and elsewhere I consider overkill, not worth their cost.If I wanted the FPGA to look like 1 MiB async SRAM (19/20 address pins multiplexed with 8 or 16 data pins, plus the normal selects and strobes) with 8 - 20 ns read and write access cycle times, what are the pitfalls to avoid? Are all, even the cheap FPGAs suitable for this use case?I know I can buffer writes and have even slow memory look much faster to the MCU wrt. single operations, as long as the throughput doesn't exceed the external memory capabilities. Fortunately, I expect MCU external memory writes to be vastly more common than reads: the design is such that it eliminates the need for MCU to read the framebuffer when updating graphics. However, not all memory types support a WAIT signal or clock stretching in I2C, the memory telling the host to hold for a bit until the data to be available. I know async SRAM doesn't have that, although some MCUs have an external memory subsystem with Flash/ROM support so they might actually support one even with SRAM. Are there any workarounds to this read timing issue?Examples of existing projects, preferably with memory throughputs above 100 Mbytes/s aggregate. It is much easier to emulate someone else poorly as a beginner, than as a beginner emulate a poor implementation but get much better end results.Anecdotes, wins, and fails in FPGA-memory or MCU-FPGA-MCU type designs. I like to learn from others mistakes and discoveries; I have no interest or benefit repeating the same mistakes that everyone else does, no matter how traditional and expected that is. It does not matter how in-depth that is, because that just causes me to dig down into the materials I have to understand both the story and the related context. I justtickthat way.Holy hell these posts of mine are long! I regret starting this thread, even though the information has been invaluable to me (Thanks to all, including Smokey!), because I don't think these posts of mine have enough value per word for others. Sorry.

author: brucehoult
author_rank: Super Contributor
timestamp: February 26, 2025, 09:38:27 am
content: Quote from: Smokey on February 26, 2025, 08:01:21 amAs I already pointed out, the 64 MB of DDR2 in-package in the CV1800B SoC (on e.g. the $3 Milk-V Duo board) does 2260 MB/s total bandwidth on an actual, real world,memcpy()test, not some theoretical speed-of-light.

author: Nominal Animal
author_rank: Super Contributor
timestamp: February 26, 2025, 09:57:27 am
content: And I've repeatedly told that the calculations show the FPGA only needs 70 Mbytes/second or less, in four separate linear cacheable/bufferable streams. It is the unpredictable MCU memory accesses, and how to cater for both of these in the same design, preferably keeping to the performance one can expect from say APM6404L QSPI PSRAM, that makes me scratch my head. Writes I can buffer, but those pesky unpredictable reads!CV1800B just has a dual-core rv64gcv processor, and I don't mind "wasting" the second core for the composition, because the rest of what I want to do with the same MCU, graphics update stuff and such, doesn't need nor profit from two cores. It is still wasting a 64-bit core for what a simple FPGA can do, but at these prices, it just Makes Sense.

author: brucehoult
author_rank: Super Contributor
timestamp: February 26, 2025, 10:41:23 am
content: Quote from: Nominal Animal on February 26, 2025, 09:57:27 amRight, which makes me wonder why people act like this is a difficult data rate to handle.QuoteHave you got an estimate for just how simple an FPGA, and the price?

author: Nominal Animal
author_rank: Super Contributor
timestamp: February 26, 2025, 01:08:05 pm
content: Quote from: brucehoult on February 26, 2025, 10:41:23 amNo, because just the framebuffer without external memory is useless to me. And I like to attack the hardest parts first, leaving the design finalization to when I have a firm grasp on the details.It's responding to the MCU read and write requests efficiently and fast enough, while also keeping those data pipelines to the compositor full, that make me scratch my head. I'd like to know more about it in general, before attacking it. Thus, this thread.I suppose that I really should have implemented the framebuffer on say Tang Nano, just to find out how much resources the implementation consumes. I didn't, because it is a problem I've already "solved". And, with the huge uncertainty I have whether I can do the external memory and MCU interfaces, it just wasn'tinterestingenough as-is.There are also FPGA-specific details, like what kind of lookup units and clock frequency it supports, that determines exactly how the core arithmetic, ((64-a)×c0 + a×c1 + 32)>>6 = (64×c0 + 32 + a×(c1-c0))>>6 = c0 + ((a×(c1 - c0) + 32)>>6) is best implemented. If one has 4096×6 block RAM, then that can do all the multiplications I want, one each in a single block RAM access. If it can do single-cycle lookups at 100 MHz, that only leaves the RAM lookups and additions and subtractions to do, with their latency irrelevant. However at 100 MHz, I have 9 cycles per pixel, which means even a barrel multiplier (a×b = a0*(b) + a1*(b<<1) + a2*(b<<2) + a3*(b<<3) + a4*(b<<4) + a5*(b<<5)) suffices, if I can have 9 of them in parallel. And some FPGAs have fixed single-cycle multiplication units built-in; as long as each term is 6 bits or more, and includes 7 most significant bits, they work for me, without any compromises needed.Even the memory access for the framebuffer is relatively simple, because it is linear data, and easily cached. The only "sequencing" in that is that I want to read the palettes (256 entries per plane, three planes; each entry specifying 6-bit r, g, b, and 6/7-bit opacity/alpha, 0..64) first just before starting the four framebuffer data streams in parallel (staggered) –– in suitable blocks, depending on how much bits I have to cache this data in a shift-register-like fashion. So, obviously some kind of memory arbitrator is needed. Where to find more about those?I do understand why selecting the FPGA first is so important, but I'd like to know more about how to do that selectionwell. It seems like many just pick a FPGA, and then work within its capabilities. I don't like that approach at all; I don't thrive in walled gardens, no matter how nice.

author: xvr
author_rank: Frequent Contributor
timestamp: February 26, 2025, 02:23:51 pm
content: QuoteNo. More important to select memory configuration first. FPGA is second.Let's consider different configurations:1. 2 separate RAM for framebuffers (as you suggest as possible configuration). This is will not work out (unless you are ready to fill all 4 planes for new framebuffer before each new frame gone to LCD).2. PSRAM for framebuffer + PSRAM interface between FPGA and MCU will not work out. PSRAM has no possibly to postpone transaction, so MCU interface can't handle PSRAM access when physical PSRAM will be busy talking to LCD framebuffer circuitry. Started LCD access can't be paused to handle MCU one.3. SRAM for framebuffer + PSRAM interface to MCU could work out, if SRAM will have enough bandwidth (70 MB/s + PSRAM bandwith for MCU interface). This approach required carefully planned timing sharing between MCU and framebuffer interfaces. Especially for MCU part, because it required not only a bandwidth but limited access latency.

author: dolbeau
author_rank: Regular Contributor
timestamp: February 26, 2025, 02:54:49 pm
content: Quote from: Nominal Animal on February 24, 2025, 08:17:20 amNot an MCU per se, but I have given access to FPGA DDR3 memory to a MC68030, MC68040, or SuperSPARC CPU for two use cases:(a) the memory is used as a framebuffer, with the FPGA playing the part of the display device connected to a screen. The CPU needs to access the framebuffer to display things (read and write, not just write). The FPGA is connected either to the SBus (SPARCstation 20), NuBus ('030 Mac, '040 Mac), or directly to the CPU bus ('030 Mac, '040 Mac)(b) the memory is used as actual memory (usable by the operating system), in this case only for the MC68030-based Macintosh IIsi, directly on the CPU bus (using whatever memory is not used for the framebuffer)For (a) the memory is also used from inside the FPGA, as there is a VexRiscV core with some micro-code for display acceleration.The main issue for (b) is that the (read) latency is higher than for the "real" memory in the system. In my case, the '030 bus is synchronous (20 MHz), the request then has to cross to the internal bus of the FPGA SoC (100 MHz system clock Wishbone, no relationship to the '030 clock) to access the memory controller, and then all the way back. Write are just immediately acknowledged and put in a FIFO (and read do not bypass at all, they have to wait for the FIFO to be empty, which doesn't help read latency either, could be improved) so are pretty quick. For read, I ended up adding support for the MC68030's burst mode, so each request brings back 128-bits (the width of the memory controller) which are sent back to the CPU in 4 bus cycles after the long wait to get it from the DDR3. It helps.Other than that, mostly smooth sailing hardware-wise as the memory controller I used (litedram) support multiple ports and does the arbitration for me.

author: pcprogrammer
author_rank: Super Contributor
timestamp: February 26, 2025, 02:56:46 pm
content: To make a complete picture every aspect is important. If you want to connect two 32 bit wide SRAM chips, you need the select a FPGA with enough IO (pins) to connect these and still have enough left to connect the LCD panel and the MCU.Using SDRAM uses less IO pins, but is more difficult to work with. The MCU interface is also an issue. Will it be a parallel bus or serial and if so with how many lanes.Choosing the FPGA also depends on the other selections. Do you need high speed serial connections and with what type of signals, like lvds or lvcmos at what ever voltage. The FPGA has to support all these choices. Most of the modern ones will, but you have to look at the specifications to be sure, and do the IO banks with their supplied voltages allow for all the connections.For instance, when you choose DRAM that needs 1.8V on the pins, you have to setup IO banks with a supply of 1.8V. This means that all the pins of these banks only work with 1.8V. If the MCU needs 3.3V, you have to setup an IO bank with a supply of 3.3V, etc.Then the number of logic elements needed, how many block ram, how many dsp blocks, etc.So to make a choice it is a bit of the chicken and the egg story.As for loading data into the LCD all that is needed to make it work properly with the memory is using a double buffered line buffer. The memory controller writes to line A at high speed and the LCD reads from line B at a lower speed. Once the LCD is done with the line, swap the buffers and trigger another read from the memory.Mixing of planes can be done before the LCD. Just setup four line buffers that are filled by the memory controller and mix the lines before they are send to the LCD. As long as the mixing can be done in a single pixel time it should not be a problem.My advice is to design a block diagram with the separate parts of the system and try to work out the needed data streams and data manipulations. Then try to write things up in a HDL and run it through a simulator. This will show if your logic is valid. Then choose an IDE for an FPGA. Don't look at yosis, but an IDE from a vendor like Quartus from Altera(Intel), Vivado from Xilinx(AMD) or Gowin FPGA designer. Select a FPGA and run your design. The IDE will tell if it will fit or not. When making the final choice leave some room for expansion or problem solving.Or just start to play with your Tang Nano 9K to see if you can get a frame buffer to work with the PSRAM and a LCD. Then expand things to suit your needs. That is how I learn, but your miles may vary.On a side note, it turns out that the SDRAM in the Tang Nano 20K is rather sensitive to timing issues. At 166MHz using a 180 degree phase shifted clock gave problems, that disappeared when making it the same phase, but not al the time, depending on the place and route. Have to test with 45 or 90 degree phase differences to see if I can get it stable.Edit: fixed some typos

author: Nominal Animal
author_rank: Super Contributor
timestamp: February 26, 2025, 09:04:32 pm
content: Quote from: xvr on February 26, 2025, 02:23:51 pmRight; that makes much more sense.Quote from: xvr on February 26, 2025, 02:23:51 pmIt does work just fine; it just works in a very different way that those used to single linear framebuffers are used to.Let's say we have three separate RAM chips, each with their own buffer contents A (=Abg+Aovl1+Aovl2+Aovl3), B, C. If the microcontroller does nothing but just repeatedly tell the FPGA to switch to the next buffer at the next retrace, the physical display will show a three-frame animation.Yes, it can feel wonky that when you update buffer contents, the existing contents are then from three frames back, not from the previous frame. It is not a problem. Thistriple bufferingis a very traditional computer graphics method when the frame update takes longer than the display update does, but you avoid both tearing effect and having to wait for the next retrace before updating the display contents for the next frame. Nowadays, this is still used in best video players, because it allows the processor to exceed single frame update duration without glitching the output, plus negative audio delay for proper sync without having to decouple the audio and video input stream buffering, as the triple buffering adds at least one frame (20ms or so) of extra video delay.I am extremely familiar with this technique. For Damage Buffers (a bitmap describing which areas of the buffer need to be updated due to previous modifications), they are maintained for each buffer, not just the current frame. It is all easily managed by the MCU or whatever is scribbling to the display buffers; the techniques are well known, albeit probably esoteric now that we have hardware that does notusuallyneed such tricks.Quote from: xvr on February 26, 2025, 02:23:51 pmThis is what I assumed, based on the datasheet of the PSRAM I'm already using. (It'd need to be magically faster PSRAM than what the MCU uses now, and that's not realistic.)Quote from: xvr on February 26, 2025, 02:23:51 pmRighto.Let's assume the MCU uses QSPI at 85.7 MHz (=600/7), with the CLK always running (so the FPGA can PLL on to that, and the MCU-FPGA-RAM uses that as the only clock domain). Each cycle takes 11.7ns. The address takes 6 cycles, with data bytes taking two cycles each; or a byte every 23ns. I can control the number of cycles in between the address and the first half of the first data byte, but let's say four cycles for reads, none for writes.It seems to me that if I use async SRAM with 10ns read and write cycle times, half the cycles satisfy the MCU needs. That doesn't leave me with sufficient framebuffer bandwidth, though.If I up the QSPI clock to 120 MHz (=600/5), each QSPI clock cycle takes 8.3ns. Let's assume I use two ISSI IS61WV5128EDBLL-10TLI (PDF) in parallel (10ns read and write cycles at 3.3V), with 19 common address outputs, 16 data I/Os, common chip enables and output enables but separate write enables (=4 outputs), for 39 I/Os for SRAM. Then, every other cycle (16.7ns intervals, plenty of time) the SRAM provides 16 data bits, and half the accesses satisfy the MCU, leaving 60 Mbytes/s for the framebuffer. This would be a bit tight, but still suffice.I could then use 120/7 = 17.1 MHz or 120/8 = 15 MHz clock for the display bus, keeping everything synchronized to the one single clock domain. The FPGA then needs 39+6+23 = 68 I/O pins at minimum.Using four of those SRAM chips in parallel would require 18 additional I/O pins, for a total of 86 I/Os minimum, but then there'd be plenty of data bandwidth to the SRAM. (A pair of 4Mb 10ns async SRAM is half the cost of a 8Mb 10ns async SRAM.)Does the above estimation look sane, along similar lines you'd do? (I do not mean to imply I've decided on the above; I'm just trying to show how I understand the advice thus far, and the design choices I believe I would make if I made them now based on that advice.)Tests that I'd do before locking in any design choices, would include a FPGA PSRAM interface at 120 MHz continuously running clock to verify MCU-FPGA read access by synthesizing the data from the address bits (reordering and XOR'ing); experimental synchronous time multiplexing SRAM arbitrator, to understand the complexity and resources needed; and the actual SRAM ICs connected to an FPGA to test data integrity and timing. For example, in Intel/Altera MAX 10 datasheet, I saw that they do provide implementations for various RAM types, except async SRAM is "do your own".

author: asmi
author_rank: Super Contributor
timestamp: February 26, 2025, 09:17:37 pm
content: Quote from: Nominal Animal on February 26, 2025, 09:04:32 pmI don't think it will suffice capacity-wise. 320*240*4=300 KiBytes, you will need two of those for layers, and three - for triple-buffering (that will require even more bandwidth BTW as now you simultaneously read 2 layer streams, then write result to a buffer, and have one more stream which actually output video signal to a display, which comes to 4 streams total), while two 512Kx8 devices will only give you 1 MiB.

author: Nominal Animal
author_rank: Super Contributor
timestamp: February 26, 2025, 09:37:08 pm
content: Quote from: asmi on February 26, 2025, 09:17:37 pmOnce again, I'm not doing traditional framebuffers. I've explained this already above. I'm using one 16-bit full-color background layer, with three indexed-color overlays. Maximum size I'm interested in is 320×480 pixels, so 320×480×(2+1+1+1) = 768,000 bytes per frame; × 70 frames/second yields 53,760,000 bytes. The palette data is 3×256×3 bytes × 70 frames/second = 161,280 bytes, for an aggregate total of 53,921,280 bytes per second RAM aggregate bandwidth.The desired total framebuffer area is 352×512 pixels; the extra 32 pixels along each axis are not displayed.352×512×(2+1+1+1) + 3×256×3 = 903,423 bytes.512k×(8+8) bits = 512k×2 bytes = 1024k = 1,048,576 bytes.Because 1,048,576 > 903,423, it will suffice.Why you keep ignoring all the data I post? I fully understand if TL;DR. But, ignoring posts and just responding based on your own assumptions and preconceptions about what you believe is being discussed without reading any of it is quite annoying.

author: xvr
author_rank: Frequent Contributor
timestamp: February 26, 2025, 10:15:21 pm
content: QuoteYes, it will work in this way (but quite complicated from software point of view)QuoteYes. But it will require a lot of FPGA pins to connect SRAM chips. I afraid that such FPGA will be available only in BGA package. It could be problem for hobby project.

author: brucehoult
author_rank: Super Contributor
timestamp: February 26, 2025, 10:38:07 pm
content: Quote from: xvr on February 26, 2025, 10:15:21 pmFor hobby projects it makes a great deal of sense, even if you want to make your own PCB, to mount a Tang Nano 9K on your PCB as a 48 pin DIP package  rather than trying to deal with the FPGA chip itself directly. And the same for the Milk-V Duo or Raspberry Pi Pico 2.TBH I think it would make a lot of sense for professional consulting engineers doing low to medium volume products too. each row of 24 pins is 2.54mm spacing, I'm not sure if the width between the rows is a standard one, ditto for Duo/Pico as a 40 pin DIP -- I'm pretty sure they will both be a "breadboard friendly" multiple of 0.1" at least.

author: Someone
author_rank: Super Contributor
timestamp: February 26, 2025, 10:41:43 pm
content: Quote from: Nominal Animal on February 26, 2025, 09:38:05 amThis is the sort of thing which goes against the established methods and then confuses everyone when you are simultaneously talking about optimising memory bandwidth to squeeze into some prematurely optimised limitation. A new palette every single frame?FPGA have fields of tiny memories, that are all fully parallel. Why put something like the colour palette (which without other clarification is almost always rarely updated/changed) as another locked to every frame constituent? Most people would have a palette as a separate parallel access, perhaps double buffered at best (or often having a subset of fixed values to allow seamless updating).Instead you suggest a struct for each frame that includes every single component to produce it alone, duplicating the memory footprint (a stated constraint) because it matches your (unexplained until now) idealised model ofdoubletriple bufferingAgain, which contradicts your opening claim of only needing to write once when something changes in the display.Start with an explanation of the API/system, if you're planning for other people to use it then that will need to be done anyway. All this trying to pick an FPGA and memory part is premature optimisation as you don't even have a system diagram or consistent explanation of what the thing does.

author: Someone
author_rank: Super Contributor
timestamp: February 26, 2025, 10:46:40 pm
content: Quote from: Nominal Animal on February 26, 2025, 01:08:05 pmSince you don't seem to be able to synthesise a solution and are here asking so many questions, it is apparent that you havenotsolved the frame buffer.Implementation of partially functional system on an FPGA is almost always the first step, be that dev boards or existing platform. Don't have the right memory attached? fake it with a stub, double check the system works under the assumptions.

author: Someone
author_rank: Super Contributor
timestamp: February 26, 2025, 10:51:52 pm
content: Quote from: brucehoult on February 26, 2025, 10:38:07 pmPlenty of commercial products using SoM (system on module) rather than designing everything from scratch, and often then reuse some existing platform, bootloaders, and OS. There seems to be some weird fetish from hobbyists to jump to component selection and program everything, when in reality the skills and experience to do everything takes too long to collect in a single person. Complex products are the result of numerous people contributing their specialisation.

author: nctnico
author_rank: Super Contributor
timestamp: February 26, 2025, 11:45:48 pm
content: Quote from: Nominal Animal on February 24, 2025, 12:06:43 pmYes and no. I have been doing FPGA design in VHDL for 20+ years and I always made it a point to approach writing VHDL from a functional perspective instead of thinking in terms of logic. And I also try to take full advantage of what the language has to offer. It is the same debate as assembly versus C. FPGA synthesizers are very capable of creating fast logic and just like C you can choose to optimise for speed or size. There is no need for optimalisation for the sake of optimalisation. However, there is a learning curve that you'll need to go through to take full advantage of an HDL. For me that has paid off though. On inherited designs I come across constructs/code I can replace with a few lines instead of half a page regulary. This includes inferring FPGA primitives like memory; I don't infer primitives unless the synthesizer can't infer a particular primitive by itself. Make sure to read the manual of the synthesizer to understand how code translates to FPGA primitives. Very valuable information! In the end a design which doesn't infer primitives is much more flexible and portable.Many HDL examples you find online are just crap because people just start to describe logic instead of a function. One of my favorite examples are prority encoders in VHDL. Take this one:https://github.com/ARC-Lab-UF/vhdl-tutorial/blob/main/combinational/priority_encoder_4in.vhdThis is an utterly obfustigated way of doing this. You can create a function with a few lines of code which does the same AND the function can be used for any width (as the author shows here:https://github.com/ARC-Lab-UF/vhdl-tutorial/blob/main/combinational/priority_encoder.vhd). Another pitfall is not using numerical types for signals which are a number. A memory address signal or counter signal are numbers so use numerical types for those. That makes it much easier to use these as an index for a memory or a mux.IMHO the Gowin FPGAs are a good choice for a project. Their software works well on Linux but I do use Eclipse (and the free veditor plugin) to write VHDL because of the realtime syntax checking and better overview when working on large projects. I think there are even better HDL plugins for VS-code but I have not used these.Where it comes to sharing memory:1) You could multiplex the memory in a fixed way. Half the bandwidth for video, half the bandwidth for the MCU. But I wouldn't take the memory cycle time below 15ns. You'll need to add more memory in parallel for more bandwidth. This is a simple but not a super efficient solution.2) Another option is to have a round-robin arbiter in the FPGA which gives priority for reading frame data. Writes from the MCU can be queued in a fifo implemented using the block ram inside the FPGA itself so the MCU can write at full speed until the FIFO is full (having a wait pin to stall the MCU access cycle is handy to have). One thing to keep in mind here is that there is dead time at the end of each line and each frame, during these the MCU has full speed access. Interrupts can be used to sync writing to the memory and the dead time in the video stream.3) Something to consider is using sprites for objects which are overlaid at a certain x/y position. If these aren't too large, these can be stored in internal memory so don't need external memory access. The round robin system could be of help if you only draw the overlay planes if there is an object on them. If there is nothing to draw, no memory bandwidth is needed.

author: incf
author_rank: Frequent Contributor
timestamp: February 27, 2025, 12:27:53 am
content: side tangent: I once implemented an LED sign using a FPGA and an embedded PicoBlaze core (not fun, do not recommend embedded "tiny" cores that lack compilers or debuggers) - it worked well, emitting color channels of shift register data/clock at ~100MHz.Personally, I had plans to do a similar system using a STM32F417 with its external memory interface. The FPGA would serve an external RAM controller where every even clock cycle went to the CPU and every odd clock cycle went to the FPGA for "pushing out pixels"It turned out to be far too much work once I got into the details of caching/buffering/etc. Two swappable banks of several QSPI RAMS in parallel @ 100MHz (or whatever speed you need) would probably be a lot simpler than bothering with parallel RAM / memory controllers / dual port memory.Very easy to share between a MCU and a FPGA. Very loose timing constraints, can run directly at some multiple of the pixel clock.

author: brucehoult
author_rank: Super Contributor
timestamp: February 27, 2025, 03:13:50 am
content: Quote from: incf on February 27, 2025, 12:27:53 amWait .. what? AMD don't have compilers for their soft core ISAs?I see one web page saying PicoBlaze needs 141 LUT and 98 flip-flops.For 125 LUT6  and 164 FF you can have SeRV, a 32 bit RISC-V RV32I processor that can use bog standard GCC or LLVM toolchains.Being bit-serial, it takes 32 cycles for most instructions, 64 for shifts and branches. But it has a very high Fmax, so can run at 10+ MIPS if the rest of your design allows.There is now also QeRV, the same basic design but with a 4 bit datapath (like Z80). I haven't seen precise numbers, but Olof says it's 15% bigger and 3x faster. 198 LUT on iCE40, 239 LUT on Cyclone 10, same FFs on all.

author: nctnico
author_rank: Super Contributor
timestamp: February 27, 2025, 07:21:11 am
content: Quote from: brucehoult on February 27, 2025, 03:13:50 amThat is probably for PacoBlaze, a more generic variant. Picoblaze is a super super tiny soft core which maps directly onto primitives found in Xilinx FPGAs. Programmable state machine is a better term. I have used it in various projects over the years but due to the very limited instruction set, using a compiler is not going to lead to efficient code.

author: pcprogrammer
author_rank: Super Contributor
timestamp: February 27, 2025, 08:07:23 am
content: Quote from: xvr on February 26, 2025, 10:15:21 pmGowin has a GW2AR-18 with 140 IO in a QFP176 package. Altera seems to stop at QFP144.Mouser sells the Gowin one, but you need to buy 60 and they are not cheap.A simpler option is to take the Sipeed Tang Primer 20K, which has 128MB of DDR3 on board and a lot of IO pins to the sodimm edge connector. The core board is relatively cheap:https://www.aliexpress.com/item/1005004653308809.html

author: Nominal Animal
author_rank: Super Contributor
timestamp: February 27, 2025, 08:10:27 am
content: Quote from: xvr on February 26, 2025, 10:15:21 pmNo, not that complicated. It's one of those things that looks complicated when you first read about it, but when you actually write the code for these use cases, you start asking yourself why didn't I do it this way before.Remember, this is not intended for 3D vector graphics using OpenGL ES or similar. We have lots of small cheap low-power embedded Linux boards with very powerful OpenGL ES implementations (Mali and others). This is for specific types of 2D stuff, and not your general-purpose video decoders and such. Sprite and 2D polygon animation with lightweight/low resource use blitting, not MPEG/AVC/etc. streams and JPEG images.Quote from: xvr on February 26, 2025, 10:15:21 pmI can see some in various QFP packages with sufficient I/O –– old iCE40HX1K/4K/8K, some MachXO2's, Gowin GW1N-UV1P5LQ100C6/I5 ––, but slim pickings indeed.Apparently, to make any real progress on this, I do need to get my BGA-fu in orderfirst.Quote from: Someone on February 26, 2025, 10:46:40 pmI'm not asking questions about the framebuffer. I'm asking questions about memory access and memory access arbitration, where the FPGA provides dual port access to some (external) RAM. I have a fully working framebuffer implementation, just not on an FPGA but on an Cortex-M7 32-bit MCU. I've described the framebuffer only because it provides the underlying reason and motivation for wanting to do this and in this particular strange way, and explains in detail the required read-only memory access patterns and bandwidths by one of the ports. The other port is a MCU with either QSPI PSRAM (max. 133 MHz) or parallel async SRAM interface, whichever (QSP PSRAM!) interface is easier. This Y-shaped memory access arbitrator is the core of this, and I'm asking about how todesignsuch properly. If I can't design and implement that, the FPGA aspect is immediately dead, and I progress on the dual-core MCU path instead.I thought some software developers were stuck in their preconceptions, but boy, I really wasn't prepared for some of the FPGA devs being even more stuck in theirs. These are just tools, not a religion or culture, dammit!

author: brucehoult
author_rank: Super Contributor
timestamp: February 27, 2025, 08:58:05 am
content: Quote from: nctnico on February 27, 2025, 07:21:11 amThis document ...https://opencores.org/usercontent/doc/1397608774... which hopefully is apples-to-apples lists PicoBlaze as 150 LUTs and pacoBlaze (3rd party picoblaze clone) as 177 LUTs. It lists pacoBlaze as having less than half the Fmax of picoBlaze (and 2/3 the KIPS/LUT), but if the ISA is more powerful (i.e. traditional RISC) and its a good compiler target then that's probably well worth it.As I see PicoBlaze has 2-address register-to-register instructions, maximum 1024x 18 bit instructions, 16 registers, 64 RAM locations, 256 IO ports, and 31 deep (10 bit) call stack. Actually it looks like a much easier compiler target than for example PIC. It's not all that different to something like one of the smaller AVRs.

author: brucehoult
author_rank: Super Contributor
timestamp: February 27, 2025, 09:06:42 am
content: Quote from: pcprogrammer on February 27, 2025, 08:07:23 amFPGA people regard Gowin stuff as being OK? Is it a good option to start an FPGA journey with?I like Sipeed stuff in general. I have a number of their RISC-V SBCs, ranging from Longan Nano to Lichee RV (Allwinner D1) to Lichee Pi 3A (SpacemiT K1) and 4A (THead TH1520).

author: pcprogrammer
author_rank: Super Contributor
timestamp: February 27, 2025, 09:31:25 am
content: Quote from: brucehoult on February 27, 2025, 09:06:42 amI don't know. I'm just a hobbyist that likes to play with hard and software. I have FPGA boards from several FPGA manufacturers and played with them a bit. The latest is the Gowin based Sipeed Tang Nano 20K, and it works. Can't tell if it is better or worse than any of the others.Since Nominal Animal stated it to be just for his hobby, I think a Gowin FPGA is just as good as any.

author: pcprogrammer
author_rank: Super Contributor
timestamp: February 27, 2025, 09:45:27 am
content: Quote from: Nominal Animal on February 27, 2025, 08:10:27 amAs I described in an earlier post, to access the memory, one way to set this up is to make use of buffers, be it single or double buffered. Most FPGA's have enough block ram on board to set these up. By using different clock domains and using burst access it is doable to make such a system as you have in mind.My example code I posted earlier has this for two streams, one input that writes into the memory and one that reads from the memory. There are some issues in that version with the timing in the interfacing with the memory, which is a bit tricky, but already solved.If you also need to read back data with the MCU, that is a bit more involved and needs handshaking between the two parts. Writes can go into buffers, but reads will be delayed, unless you can think up some clever cache mechanism.Another option with SRAM is to use interleaved access. But here it can also benefit from buffers. Use a higher clock to talk to the memory in such a way that you get time slices on a lower clock speed, and have the low speed clocks have a phase shift between them.Like suggested before, make a drawing of the system parts and the data streams between them. This will give a better view on what would need to be done in the FPGA.

author: Berni
author_rank: Super Contributor
timestamp: February 27, 2025, 10:22:42 am
content: I have a Lattice FPGA acting as a "graphics card" to a small STM32 via QSPI. It does some extra video processing on an external video feed so that's the reason for having a FPGA in there.But if you just want to display an image from a MCU/SoC then having a FPGA is completely unnecessary. Just pick a chip with video output capability and drive the LCD directly from there. It makes things a lot simpler and is still plenty performant due to how fast modern chips are. If you want performance then you can find MCUs with a built in simple "2D GPU" that is basically just a glorified DMA with a bit of color blending options tacked on. So you can have the CPU do useful stuff while pixels are being tossed around in the background.But if this is more of a hobby project, then there is value in this as being good learning experience as doing this touches on a lot of aspects of FPGAs while giving a nice visual result to look at and keep you motivated.

author: Nominal Animal
author_rank: Super Contributor
timestamp: February 27, 2025, 12:13:51 pm
content: Quote from: Berni on February 27, 2025, 10:22:42 amMay I ask which Lattice FPGA? And whether you have any tips/tricks/points on exposing the FPGA to the MCU via QSPI? Or whether you found it straightforward to implement? I'm particularly interested in knowing any pitfalls or errors to avoid in the design phase, and what to pay careful attention to.

author: Nominal Animal
author_rank: Super Contributor
timestamp: February 27, 2025, 12:31:34 pm
content: Quote from: pcprogrammer on February 27, 2025, 09:45:27 amThe display modules I'm using have a controller on them, and my writes are to their GRAM; it is not the standard RGB+Vsync+Hsync+DE+clock interface at all. They also export the Tearing Effect (internal Vsync), so all I need to do is complete GRAM update faster than the refresh is. Most controllers datasheets specify 66ns (15.1 MHz) write cycles, but 55ns (18 MHz) has always worked for me.I do not and will not need more than 11 Mpixels/sec throughput to the display, so any display-related clock between 11 MHz and 18 MHz should work.Because of this, I can actually use a single clock domain, as long as the display bus clock rate is between 11 MHz and 18 MHz, and the PSRAM QSPI clock is a suitable integer multiple of that (say 88 MHz to 126 MHz).(With a single buffer, the delay from graphics completion to visibility is about 1/70s ≃ 14ms; with triple buffering 29ms. I'm not doing anything that cares about that, and 20ms/40ms was standard in retro games anyway. Only these smaller display modules tend to have controllers with GRAM, so do not expect this to be generally possible.)Quote from: pcprogrammer on February 27, 2025, 09:45:27 amI liked that suggestion then, and I like it now. Yes, will do, even if for nothing but to clarify the design as it seems to be a bit contentious.

author: nctnico
author_rank: Super Contributor
timestamp: February 27, 2025, 12:37:11 pm
content: Quote from: brucehoult on February 27, 2025, 09:06:42 amSo far I have used these in 1 commercial project and that went smoothly. Programming from an MCU is also straightforward using (bit banged) SPI. Overall I rate the documentation as very good. I don't see any technical reasons why not to choose a Gowin FPGA for a project.

author: xvr
author_rank: Frequent Contributor
timestamp: February 27, 2025, 12:41:38 pm
content: QuoteIt is possible only if your MCU will generate steady PSRAM clock (not only at access time). You can use it as main clock and derive all other from it.But if this clock generated only at access time you can't use it as a master clockPS. I assume that PSRAM here is an one emulated by FPGA on MCU <-> FPGA interface.

author: Berni
author_rank: Super Contributor
timestamp: February 27, 2025, 12:51:07 pm
content: It is a CrosslinkNX family chip. It was chosen because it is reasonably priced while having MIPI capability, has a decent amount of internal RAM, comes in a friendly QFN package... etcImplementing QSPI on a FPGA is pretty easy since it is just SPI with extra data lines (SPI is the easiest protocol on FPGAs, it is basically just a shift register). The more annoying was the QSPI peripheral on the particular STM32 (it only supports memory mapped flash on QSPI) but the most newer STM32s have a better version of that peripheral. I was running low on pins so i actually also had a QSPI Flash chip on the same QSPI bus as the FPGA. These same QSPI pins were also used to boot the FPGA from the external flash.You can have the FPGA emulate any off the shelf QSPI SRAM chip(or i just reused commands that do nothing on QSPI Flash chips), this can get turned into the usual parallel memory bus of whatever flavor you have the taste for (Wishbone, Avalon, AHC..etc). At that point anything you hang off that internal memory bus can be accessed by the external MCU just like it was a softcore inside the FPGA.The thing to watch out for is that you don't have any cache on QSPI. The QSPI bus is pretty darn fast for how few wires it needs, but it is still a fair bit slower than a internal memory, so MCUs will typically cache accesses to QSPI memory to improve performance, this is great if there is just memory there, but once you have hardware registers that may change without the MCUs knowledge then you get stale cache problems(resulting in weird unpredictable bugs). So any cache must be turned off and the data should be accessed in large blocks (since latency is poor due to having to send the address on every read/write operation). You might have to resort to DMAing bytes into the QSPI peripheral to get that (rather than the sleek fancy 'it's just there in memory')

author: Nominal Animal
author_rank: Super Contributor
timestamp: February 27, 2025, 05:38:31 pm
content: Quote from: xvr on February 27, 2025, 12:41:38 pmYes, it explicitly supports free-running QSPI clock, mentioning FPGA applications.Quote from: xvr on February 27, 2025, 12:41:38 pmExactly. And it isn't simply a fixed fraction of the main clock; their relative phase can vary between accesses. Lots of traps here!Quote from: xvr on February 27, 2025, 12:41:38 pmYes!

author: xvr
author_rank: Frequent Contributor
timestamp: February 27, 2025, 06:17:31 pm
content: QuoteYou're in luckThis will greatly simplify the design.

author: Nominal Animal
author_rank: Super Contributor
timestamp: February 27, 2025, 06:57:33 pm
content: Quote from: Berni on February 27, 2025, 12:51:07 pmYes; very similar to when writing software on a multicore processor with non-coherent caches.Fortunately, the other memory port is utterly read-only, so I can enable MCU caching, as long as I flush those caches before telling the FPGA to switch frames (or risk having some written-but-not-sent-to-FPGA data not be visible yet).This is also something that impacts the Milk-V Duo dual-core MCU discussed as an alternative to an FPGA approach. The two cores do not have coherent caches but completely separate ones, so a D-cache flush (clear in XTheadCmo terms) is necessary to ensure the second core sees the modified data. Annoyingly, it cannot flush a range of addresses, only entire D-cache or only a specific cache line (64 bytes), and the cores only support write-back, not write-through mode. For my purposes, the 70 or so D-cache flushes per second shouldn't hurt too much.

author: Berni
author_rank: Super Contributor
timestamp: February 27, 2025, 07:13:42 pm
content: Also no need to have a steadily running clock from the MCU side. As long as your MCU supports some form of busy signal (a lot of them do because of PSRAM) then you can just make the MCU wait its turn whenever memory is not available.Flip floping memory between adresses is an old trick that doesn't work so well with modern memory as often modern memory has some amount of pipelining ability to reach higher speeds (be it giving results later, or allowing faster access to the next location). So a better alternative is to play to the modern memories strengths and use a cache in the FPGA. This is the easiest to do for framebuffer output as you always know what address you will need in the future. So while outputting 1 scan line of video, you can start reading the next scan line at maximum memory speed into a intermediate video line buffer. Once done you leave a large window of time where the memory is idle to do other things. If your MCU wants to access the frame buffer at the wrong moment you just raise the busy flag and make it wait. If you want to go more advanced you could also introduce a write cache to hold some amount of writes while the memory is busy to keep the MCU running more of the time.But as said before for this use case i recommend using a MCU with a built in 2D DMA in it, it will be simpler, cheaper..etc and just as performant.

author: Nominal Animal
author_rank: Super Contributor
timestamp: February 27, 2025, 09:28:22 pm
content: Quote from: Berni on February 27, 2025, 07:13:42 pmIt doesn't, really: unfortunately the DQS pin (for Flash-provided read strobe, or loopback for clock for read clock) is hardwired to the QSPI clock pin on the board.

author: brucehoult
author_rank: Super Contributor
timestamp: February 27, 2025, 11:24:08 pm
content: Quote from: Nominal Animal on February 27, 2025, 06:57:33 pmIsn't a cache line flush instruction the perfect thing? The memory bus isn't 64 bytes (512 bits) wide, in fact it is just 16 bits wide, so the write-back takes a number of clock cycles, leaving more than ample time to bump a pointer, test against a limit, and loop back. An instruction to flush a multi-KB or multi-MB address range would not be able to go any faster.

author: SiliconWizard
author_rank: Super Contributor
timestamp: February 28, 2025, 06:47:14 am
content: Quote from: brucehoult on February 27, 2025, 11:24:08 pmYes. You just need to clean all cache lines that contain at least one byte of the memory block. The cache line size on the CV1800B is 64. The instruction isth.dcache.cpa.Also don't forget to executeth.syncat the end.

author: Nominal Animal
author_rank: Super Contributor
timestamp: February 28, 2025, 12:34:54 pm
content: Quote from: brucehoult on February 27, 2025, 11:24:08 pmI typically scribble only to a small part of each plane per frame. I can track it, say one bit per cacheline, but it adds unnecessary complexity. I do not want to drop cachelines after each sub-object write, because that would negatively affect blitting, including writing text. I could drop the cachelines related to each blit/polygon draw/text string write, but it adds overhead I suspect sums to more than dropping all data cache when a frame is completely updated.The background buffer is on the order of 5632 cachelines, and the overlay planes 2816 each, for a total of say 14080 cachelines. With 64k of data cache (1024 cachelines), that is a loop over 220 64-bit words if using a bitmap, then further loops if the word contains nonzero bits. Not worth the cycles, I reckon.I would fully expect a flush-range, if implemented, to beslowerthan independent cacheline flushes when the region specified is smaller than the full data cache size (64k). (It would need to be implemented as checking each cacheline slot in the data cache.) It only becomes faster when the range is much larger than the cache is.Dropping the full data cache has the downside that it affects other cached stuff, so will affect unrelated code.Like I said, a bit annoying –– I will still have to check the above in practice, to verify my initial assessment is right ––, but by no means any kind of show-stopper at all. The RAM on this is stupidly fast compared to e.g. PSRAM on an MCU.

author: Nominal Animal
author_rank: Super Contributor
timestamp: March 01, 2025, 04:10:11 pm
content: Here's a diagram of the MCU-FPGA-Display/GRAM system I'm thinking of:(Click to embiggen)I have a microcontroller that uses QSPI PSRAM interface to access dedicated external RAM. I'd like it to do that through the FPGA, via a memory access arbitrator implemented in the FPGA, so that both the PSRAM interface and the graphics composer inside the FPGA can access the external RAM sufficiently "simultaneously".The microcontroller also sends simple commands to a graphics composer on the FPGA, with the composer responding asynchronously when the command is complete. Aside from initialization, there is only one command worth mentioning:Update frame, which waits for the next vertical refresh on the actual display device (as signaled by the TE aka Tear Effect pin), and then updates the graphics RAM buffer on the display device, and finally responds to the MCU of the operation completion.The display devices are small, with maximum size 480×320@70Hz, or about 11 Mpixels/second. Because I update the display data asynchronously (I do not directly refresh the display contents, only the backing graphics RAM on them), I can use any data rate between 11 Mpixels/second to 18 Mpixels/second or so.The graphics composer uses several separate buffers on the external RAM to composite the actual data going to the display data. These read-only streams are at aggregate minimum 55 MBytes/s (22 MB/s + 3×11 MB/s), but up to 90 MBytes/s (36 MB/s + 3×18 MB/s) can be utilized. Each stream is essentially linear in memory, with one discontinuity at most per refresh. It is not a typical single-framebuffer rasterizer, nor can it be replaced by any of the existing pixel engines that you find on many microcontrollers; it does a lot of look-ups, a little bit of arithmetic, but is a rather straightforward fixed pipeline. I have this implemented on an MCU, but I don't like how little it leaves me for other stuff, so I do know what I want here.The QSPI PSRAM interface between the MCU and the FPGA is SDR up to 133 MHz, currently APS6404L_3SQR PSRAM at 88 MHz is used successfully. The MCU supports free-running CLK, explicitly intended for FPGA applications, so I can use a single clock domain synchronized to that one, as I'm free to choose the display/GRAM clock. (Actually, that can even vary without any downsides, as long as the 11+ Mpixels/second requirement is fulfilled.)I require at least 1 MB of external RAM here, and can easily use up to 16 MB.I believe that in the price/complexity range I'm looking at, only async SRAM with 10ns or less read/write cycle times is suitable; perhaps using two or four 512k×8 10ns async SRAMs in parallel (for the cost; two 512k×8 costing about half what equivalent one 512k×16 costs), although it does mean quite a lot of I/O pins required on the FPGA. That is the gray bus between the SRAM and FPGA. The display/GRAM interface requires 23 I/O, the MCU 6 I/O, plus two for the command interface. I've thus far failed with my BGA endeavours, so I do prefer TQFP and similar legged surface mount devices.

author: pcprogrammer
author_rank: Super Contributor
timestamp: March 01, 2025, 05:37:48 pm
content: With SRAM it should be not that hard to do. If you make the SRAM databus 32 bits wide it would need 57 pins. (19 address, 32 data, oe, wen, 4x cs) With the 23 of the display and 8 for the MCU it would be I/O 88 pins. You also need pins for the configuration of the FPGA, but these could be shared with the MCU. Nearest package of FPGA's that I know of is QFP144, which gives you lots of extra pins to play with. (Gowin GW2A-18 ==> 119 IO)For this you could use a Gowin GW2A-LV18EQ144 or an Altera Cyclone IV EP4CE6E22C8N 144-Pin EQFP. From Xilinx, for as far as I know it is only older Spartan 3 devices that come in 144 pin qfp packages. No idea about lattice.The Gowin GW2A-18 has more logic and blockram. Only problem might be to get it cheap. Comparing between Mouser and Edge electronics shows that Mouser steels from you. >45 euro vs < 8 dollar.But a first test for you could be to just use the Tang Nano 9K you already have. Make use of the PSRAM that is in there, and see if you can hook up the 31 pins you need. Interfacing with the PSRAM is not as straight forward as with SRAM, but not impossible. Make use of the blockram to speed things up.This way you can first test your ideas to see if it will work and fit on the smaller GW1 used in the Tang Nano 9K. This is about similar to the Cyclone IV.Edit: Even though my project is for constant write LCD, the data stream setup is not that different. Study the design of it and see if you can make use of parts or the ideas behind it.

author: Berni
author_rank: Super Contributor
timestamp: March 02, 2025, 06:41:16 pm
content: UART in addition to the QSPI bus is just another needless complication.QSPI is way WAY faster and it is already there. All you have to do is reserve a small area of address space for memory mapped registers. But it is not async? Well Is the UART truly async? Sure the data over the wires is, but once it gets to the UART peripheral it is just a buffer full of bytes that you have to read out from a memory register. You can bypass all that by placing this buffer I/O memory register in the FPGAs memory space and you cut out a bunch of middlemen in getting the same thing done, putting a bunch of bytes somewhere into the FPGA (like a buffer for a GPU instruction queue). A more useful thing is connecting a bit of spare IO between the MCU and FPGA that can be used as flags or interrupt triggers, so that way the MCU doesn't have to poll a register via QSPI just to find out if a buffer is ready yet.BGAs are not as bad as they sound. The very large 1mm or 0.8mm pitch ones are very doable to hand solder without needing lots of practice or special tools. Especially if you use solder paste + reflow to assemble your boards. Just put some markings on the PCB for the corners of the BGA chip, place is as precisely into those markings and give it heat. But it does make debuging a pain when you can't poke any of the pins with a scope probe. But you do get a lot more pins so you can easily find the pins to bring out 16 spare IO lines to run into a external logic analyzer for live debugging (Then internally route those to the pins of interest)But in my opinion for this application you could get away with drawing gauges at 60fps using just a regular MCU directly as long as it is something modern, high clocked and the software is well optimized. Internal memory in MCUs can have a LOT of bandwith

author: Nominal Animal
author_rank: Super Contributor
timestamp: March 03, 2025, 01:53:29 am
content: Quote from: Berni on March 02, 2025, 06:41:16 pmBetween the command (MCU to FPGA) and the response (FPGA to MCU) there is a random delay between 7ms and 14ms. It does not need to be fast at all, because the commands and the responses are single bytes, at aforementioned intervals. (All other commands are related to initialization.) I do not want to poll. If I replace the connections with simple I/O wires and put the payload into the external RAM, I merge this into the memory arbitrator, making the latter more complex.My way, the UART transmitter and receiver is a separate unit with just a few bits of state shared with the graphics composer. It can use a fixed baud rate, 8n1, so should be quite simple. Anything else than an UART leads to more complex FPGA firmware and/or MCU software.Quote from: Berni on March 02, 2025, 06:41:16 pmI'm sure I'd do much better if I got some more practice. I've looked for affordable sensible 0.8mm pitch BGAs to make cheap BGA practice boards out of, but it looks like SRAMs are the cheapest that one can also easily verify for correct soldering results.Quote from: Berni on March 02, 2025, 06:41:16 pmAs I mentioned before, it eats between a quarter and a half of processing time on Teensy 4.x, NXP i.MX RT1062 Cortex-M7 core running at 600 MHz.It does look like the Milk-V Duo approach (dual core <10€ dev board) is more sensible, at least for now.

author: Berni
author_rank: Super Contributor
timestamp: March 03, 2025, 07:00:10 am
content: No no you wouldn't want a command queue in external RAM.These small buffers are always best to hold inside the FPGAs internal distributed RAM, this way the data can be moved in/out on any desired clock cycle or clock domain.Just because QSPI feeds into the external RAM doesn't mean that's the only place it can do. The QSPI slave is a separate block anyway that has a master parallel memory bus coming out of it, that then goes on into the external memory arbitrator for actual execution. There is nothing stopping you from also placing a address decoder on that bus to generate a collection of chip select signals for who we want to talk to. The majority of address space is assigned to the select line for external memory while a small area of addresses maps to hardware registers (where you can access things like the command queue). This doesn't cost you any Fmax either because the address MSB comes in first on QSPI so you can already get started with the address decoding before the rest of the command comes in(As long as you build the QSPI slave to make the address bits available as soon as they come in, not latch the whole address onto the bus once the whole command is in).FPGAs don't typically speak serial internally, so a UART would be turning data into a 8bit parallel bus as the first thing. All while parsing varied commands is annoying in logic as it has to be done with state machines and those can grow rather quickly when any form of complex and varied behavior comes up. This is the reason that softcores are so common in FPGAs (takes less logic to build a simple CPU and program it in C than it takes to directly implement complex behavior) and these interact with the rest of the FPGA via a memory bus (similar to the QSPI memory mapped bus you already have).This is also one of the big reasons it is so rare to see chips with UART interfaces on peripheral chips (ADCs, DACs, sensors..etc) and instead see them as SPI,I2C..etc that exposes a set of registers. This is what is the simplest to implement using digital logic and is also friendly for automation with a DMA.

author: nctnico
author_rank: Super Contributor
timestamp: March 03, 2025, 09:59:36 am
content: I can definitely see the advantage of a UART because you can initiate a transaction from both sides. SPI and I2C don't have that; there are uni-directional where it comes to initiating a transfer. With a UART the MCU can throw commands at the FPGA at any moment and the FPGA can throw responses back at its own pace.

author: Nominal Animal
author_rank: Super Contributor
timestamp: March 03, 2025, 01:48:38 pm
content: Quote from: Berni on March 03, 2025, 07:00:10 amAh, right; now I understand the idea. Yes, this isnearlyperfect. I'd still need an extra bit (I/O) for the FPGA to tell the MCU there is something new in the command queue, as you said.Fortunately, there are only a very few "commands", with all but the frame update being initialization-related. There are a number of different controllers that arealmostcompatible, just need different initialization sequences. I intend to use a bit of the unused memory following the buffers for a simplified comms queue (specifying command and data reads and writes to the display) anyway, so the only other command I really need is "run queue". I expect to control backlight and reset lines from the MCU.I obviously need to implement these in practice on the FPGA dev boards I have, just to see what kind of resources they take, and how it impacts on the MCU side programming, before making any kind of decision. (While command queues and mailboxes are bog standard stuff, cache control and such details need to be tested and verified for correct overall behaviour.)Quote from: Berni on March 03, 2025, 07:00:10 amRight. The QSPI PSRAM address space I'm using is 16 MBytes, so the very first 4-bit word will tell which 1 MB chunk the address refers to. Excellent.The one downside is that I may have to use the same caching policy for the command queue as I do for the framebuffers, and that likely means the MCU will burst-read a full cacheline when I'm just writing to a single byte in the command queue. As this is a programmable hardware peripheral on the MCU, I havesomebut notfullcontrol over it.Essentially, I may need to invalidate the cacheline(s) containing the command queue, then access the command queue, followed by flushing the cacheline if any data was written, invalidating it if not. Not a problem, but not trivial like hardware-based UART is.Quote from: Berni on March 03, 2025, 07:00:10 amI am aware of the complexities of the RX implementation: how it requires sampling at a multiple of the baud rate and so on. TX seems much simpler in comparison. And anything with a separate synchronous clock to refer to is obviously much simpler. I was counting on using a baud rate tied to the free-running clock via an integer divisor, so I can do something like 8×baud rate sampling (and reject/complain about messages where the sampling yielded 4:4).It is just that UARTs are plentiful on microcontrollers, while SPI and I2C are limited. For example, Teensy 4.1 has8UARTs, but only 3 SPI and 3 I²C hardware peripherals.

author: Langdon
author_rank: Frequent Contributor
timestamp: March 03, 2025, 02:20:11 pm
content: If you don't like BGA, you could always just use a BGA-to-DIP socket.They are a pain to remove chips from though.

author: Nominal Animal
author_rank: Super Contributor
timestamp: March 03, 2025, 05:07:35 pm
content: Quote from: Langdon on March 03, 2025, 02:20:11 pmI like them fine enough, it's just that my initial soldering attempts have failed. I hate it that I cannot really even inspect to see why/how.There is a definite learning curve there, what with my dinky little USB-C hot plate, hot air, and soldering irons –– they're all cheap hobbyist stuff. I also cannot really afford wasting 10€+ ICs just for learning purposes, so I've been on the lookout for simple many-I/O cheap BGA chips that would be amenable to making a BGA trainer board out of. The best option I've come up with thus far is simple async SRAM in BGA, with just supply bypass caps and a 0.1" header compatible with Tang Nano 1K/4K/9K FPGA boards, with FPGA firmware that just stress tests the SRAM, perhaps displaying the status using the small SPI display connector on 9K, or via I2C to an OLED module on 1K/4K.Any suggestions on BGA soldering training boards (that have a way of verifying the quality of the soldering other than taking an X-ray of it) would be very welcome, too.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 03, 2025, 05:17:49 pm
content: You could definitely consider having the boards assembled by JLCPCB, which would save the hassle of ordering the parts and soldering them yourself.Their prices for assembly are pretty low.

author: bson
author_rank: Unknown
timestamp: March 03, 2025, 06:50:52 pm
content: Quote from: brucehoult on February 27, 2025, 08:58:05 amLooks to be dated 2014, and surely KIPS/LUT and Fmax depend on the target device. On speed grade, if nothing else.

author: bson
author_rank: Unknown
timestamp: March 03, 2025, 06:52:37 pm
content: An option would be to have any BGAs mounted/assembled (as they will have RoHS factory balls) and then do the rest as you would normally.

author: Berni
author_rank: Super Contributor
timestamp: March 04, 2025, 07:38:16 am
content: Quote from: Nominal Animal on March 03, 2025, 01:48:38 pmFor that you would typically ban caching for that area of memory (like it is also done for memory areas containing the MCUs internal peripherals). In most MCUs this is typically done using the MPU (Memory Protection Unit) this is sort of a cut down version of the MMU that you typically see on all big CPUs that run real OSes like Linux. These can't remap and page memory like a real MMU can, but what it can do is apply special rules to certain areas of memory. It lets you do things like write protect areas, prevent code execution from certain areas..etc and often it lets you bypass caches for that area or apply different caching modes to areas (like write-trough cache).How much flexibility/features you have in MPU varies from MCU to MCU as it is not quite a mandatory standard part of the ARM core, so you have to check your particular MCU for what it can do. I often use the MPU as a easy way of getting around cache coherency issues due to DMA.

author: Nominal Animal
author_rank: Super Contributor
timestamp: March 04, 2025, 08:06:55 pm
content: Quote from: Berni on March 04, 2025, 07:38:16 amYup. (I'm looking at three different MCUs and several FPGAs at the same time related to this, so I don't always manage to focus on the pertinent details.)i.MX RT1062supports 16 regions, but that'sallits Reference Manual tells about that. The ARMv7-m Architecture Reference Manual describes the registers, but not the implementation defined parts – for example, the alignment requirements. Then there are some ARM errata to check, like#1259864(data corruption with write-through caching on Cortex-M7), as well as NXP's errata for i.MX RT1060 series; even a cursory look indicates there are some related ones (includingERR050469).It's also not easy to verify the cache is disabled without proper test equipment, like a logic analyser that can work at 88 MHz (although I could drop that down some – my LA can sample at max. 24 MHz). I don't like to do changes I cannot verify; I deeply dislike the good old "throw spaghetti at the wall and see what sticks" -method of problem solving. Testing both MCU changes and the related FPGA implementation at the same time is a bit iffy to me; bugs can lurk anywhere and frustration is likely...

author: pcprogrammer
author_rank: Super Contributor
timestamp: March 05, 2025, 06:26:07 am
content: Quote from: Nominal Animal on March 04, 2025, 08:06:55 pmThere are options to do this in the FPGA. Gowin has the analyzer oscilloscope system:https://www.gowinsemi.com/upload/database_doc/37/document/5bfcfed078251.pdf?_file=database_doc%2F37%2Fdocument%2F5bfcfed078251.pdf.I have not used it yet, so don't know how well it works. Xilinx has something similar, and other manufacturers will have something like this too. It does take some of the available logic, but with the modern FPGA's that should not be a big problem.

author: bywqdq
author_rank: Contributor
timestamp: March 05, 2025, 09:29:14 am
content: AG16KSDE176 64Mbit sdram + 16k fpga + mcu 在一个芯片上。只要30元

author: DiTBho
author_rank: Super Contributor
timestamp: March 14, 2025, 08:55:00 am
content: I casually look at this part of the forum, very little lately, I hadn't seen this topicUmmm, I worked with Papilio-Pro, based on Spartan6-LX9 with on-board SDRAM(1).Not sure if it was 2017?, but I remember LX9 had an integrated DRAM controller.I don't remember why we wanted to write our own, but writing the VHDL code for the controller was a bloody experience.Since then, it has worked reliably, and the code has been cleaned up, and is decent enough to be considered "educational".Personally, what made a big difference during the approach, was an "automa" (that was the sub-project name) implemented in the FPGA, capable of talking on the serial at 19200bps. It was simple, with the sole purpose of accepting commands and executing them.Things like, write this pattern (e.g. address-in-address) here, dump the memory there, etc90% of the activity was on the simulator, gtk-wave + a lot of testbenches, but it was very useful for debugging on the real hw.edit:(1) SDRAM, 64-Mbit, MT48LC4M16 by Micron

author: DiTBho
author_rank: Super Contributor
timestamp: March 14, 2025, 09:39:29 am
content: Quote from: Berni on March 03, 2025, 07:00:10 amDepends on how many commands, and their parameters.If the commands are just few and can be "pigeonholed" into the same pattern, then it becomes very simple.I mean, I implemented a gdb-stub in vhdl, but it was just a crazy idea.For a thing like that, a small softcore is better.I recommend to add a small FIFO buffer to the uart.

author: DiTBho
author_rank: Super Contributor
timestamp: March 14, 2025, 09:46:08 am
content: Quote from: Nominal Animal on March 04, 2025, 08:06:55 pmmy advice here is to avoid cache.I do, because it's always a source of problems.p.s.look at my mon/mips: it all works in the uncached kernel segment (MIPS)as I already have other quirks and issues to care about

author: DiTBho
author_rank: Super Contributor
timestamp: March 14, 2025, 10:24:52 am
content: The GameDuino2 might be interesting.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 14, 2025, 01:36:07 pm
content: Quote from: DiTBho on March 14, 2025, 08:55:00 amThe Spartan 6 series has integrated DDR memory controller(s), but only for DDR RAM, AFAIR. Not for SDRAM. They don't seem to supply an IP for an SDRAM controller (which would then use plain FPGA logic cells though), I checked in Xilinx ISE. Again, the memory controller only supports DDR (DDR/DDR2/DDR3 and LPDDR).Now, a SDRAM controller is much simpler to implement than a controller for DDR RAM. Not sure what the "bloody experience" was. SDRAM is pretty straightforward. Takes a bit more work if you want to optimize throughput (SDRAM chips can usuall have several banks open at the same time), but that's not nearly as bad as DDR for sure.

author: DiTBho
author_rank: Super Contributor
timestamp: March 14, 2025, 02:20:16 pm
content: I didn't remember why we ended up writing one, you made it clearQuote from: SiliconWizard on March 14, 2025, 01:36:07 pmI don't remember very well, it's been a long time, I just remember it was not a pleasant hobby experience, pretty frustrating and and I was not the only one feeling this.For me, it was quite annoying to carry bugs around until I wrote the Automa, which is useful not only for debugging but also for collecting statistics.After that, it was much easier and more fun to finalize the vhdl code.For at least two years thePapilioProdidn't have a dynamic ram controller.Other two guys worked on it.make it just workingmake it working and realiable"make it working, reliable, and with cycles optimizedwere the steps we all went through.

author: DiTBho
author_rank: Super Contributor
timestamp: March 14, 2025, 02:33:47 pm
content: Umm, also I guess most Spartan6 parts come with DRAM controller, but it wasn’t available on the TQG144 package used for the FPGA on the PapiloPro.I think it was a further reason for that.My Automa was similar tothisSDRAM tester, which just reads and writes 1 byte.The difficult part of mine of mine was implementing, debugging, and tuning bursts.

author: pcprogrammer
author_rank: Super Contributor
timestamp: March 14, 2025, 04:33:55 pm
content: Quote from: SiliconWizard on March 14, 2025, 01:36:07 pmI think your semantics are a bit off. SDRAM stands for Synchronous Dynamic Random Access Memory, and is what lies at the foundation of most DDRx based memory. I know it is a bit confusing, but you should have written SDR SDRAM is not supported.The terminology stands for SDR == Single Data Rate and DDR == Double Data Rate. For the unaware, with SDR only one edge of the memory clock is used to pass data, while with DDR on both edges of the clock data is passed.I just recently dove into this memory stuff to get the Tang Nano 20K up and running with the integrated SDR SDRAM. (MT48LC2M32B2)

author: pcprogrammer
author_rank: Super Contributor
timestamp: March 14, 2025, 04:39:39 pm
content: Quote from: DiTBho on March 14, 2025, 02:33:47 pmThat was also something I ran into, the burst handling and the terminating of it. Have not looked to close to DDR, but as it is also command driven with the three control lines I think it is not that much harder than the SDR memory.

author: DiTBho
author_rank: Super Contributor
timestamp: March 14, 2025, 11:28:50 pm
content: @NominalAnimalI don't know the correct term to call tham, I usually call them "STN-LCDs", even "super-twisted nematic" shouldn't refer to the "frame timing" but rather to the "liquid-crystal properties of changing their orientation when exposed to an electric field", which can be used to create images. This change is called the "twisted nematic" field effect, That's from where the TN of STN comes.Anyway, STN LCDs have also the unique property of being simply, low bandwidth, which made them suitatable for 2000s PDAs, and fpga (even CPLD) small projects.A dude in my group found the way to hack a couple of 2000s PDAs, and we got access to nice 320x240x4bit LCDs.They work at 3.3V, can be LED-backlighted and the frame timing, once tuned, it's of a few lines of VHDL.Which is good, because it's also super simple to create a "working model" for GHDL, so you can simulate the whole project by wrapping a simple pixel(x,y,color) function to a low level X11 primitive.Some PDA-LCDs also come with resistive touchscreen.Love them

author: Nominal Animal
author_rank: Super Contributor
timestamp: March 14, 2025, 11:57:50 pm
content: Quote from: DiTBho on March 14, 2025, 11:28:50 pmWhenever I use the labelsTN,IPSorPVAin relation to TFT displays, I do so to highlight the user-visible result of the technology: TN panels have narrow viewing angles at which the image looks "correct", outside of which it becomes unreadable, sometimes even inverting; IPS and PVA allowing very wide viewing angles (and later versions reduced off-angle glowing). The small displays I use have an integrated controller of ILI9341/ILI9488/ST7789 or similar type with their internal framebuffers/GRAM, so that I don't need to worry about the low-level details of refreshing the display.In all these, the power required by the panel is a fraction of what usable backlighting needs –– and I typically run mine at very low intensities, which also tends to make PWM flickering more perceptible, that resulted in my own backlighting adventures.Quote from: DiTBho on March 14, 2025, 11:28:50 pmAnd very low power, too. I do still have a bunch of unused Nokia 84×48 5110 LCDs for small projects. I must've bought themagesago, because they came with the 5110 plastic base!

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 17, 2025, 08:38:15 pm
content: Quote from: pcprogrammer on March 14, 2025, 04:33:55 pmPedantically speaking, yes, but it's ultra-common to use "SDRAM" as short for what is SDR SDRAM (which is what SDRAM was initially when it got released), and refer to DDR SDRAM as DDR RAM. It's pretty much what almost everyone uses and must have been used hundreds of times on this forum alone. And all context was there in this thread to easily catch the difference. Sorry if that confused you.So again and to make it ultra-clear, the Spartan 6 (except the lower end apparently) have one or more embedded memory controllers, which only support DDR/DDR2/DDR3/LPDDR RAM and can't be used in any way to control SDR SDRAM. Xilinx have gotten rid of those embedded controllers in the 7 series and they are provided as IPs implemented in non-dedicated logic cells.A (SDR) SDRAM controller is much easier to implement (ask BrianHG who has implemented a DDR3 controller). HamsterNZ has implemented one years ago and should still be easy to find. It was used by many precisely with Papilio dev boards. That's a starting point for those who are interested. Of course, the devil is in the details and just because you have a basic controller doesn't mean that the memory will be "easy" to use. A good controller will have several channels, FIFOs, a scheduler and various niceties to optimize throughput.

author: Berni
author_rank: Super Contributor
timestamp: March 18, 2025, 06:40:00 am
content: Yeah with these sort of DRAM controllers there is a big difference between one that works and one that works fast.You can implement the bare minimum to read and write some data to it, but in order to get fast performance you need a smart controller with multiple operations in flight and managing them in a way that minimizes bus idle time. To make things worse the thing that is using the memory also has to access it in blocks and be aware of the latency it takes to get data back.So because of all of this it is much much easier to use SRAM if you can. For graphics at reasonable resolutions the price of a few MB of SRAM is not that terrible, while saving you a lot of manhours in development.

author: pcprogrammer
author_rank: Super Contributor
timestamp: March 18, 2025, 08:13:45 am
content: Having a highly specialized and optimized memory controller depends totally on the needs within your project.Sure making a controller that can handle the different blocks available in the used memory is more difficult than making one that only uses a single block at a time, or one that only reads or writes a full 256 byte burst.In a system where the memory is only used by a single "device" a simple controller will do. That is the case in the project I did with avst. Just a single frame buffer that needs to be written and read. And starting with zero knowledge made it time consuming to get things working, as with every other subject one has no knowledge about. It takes time to learn. More now that I'm older and have concentration issues.For the project Nominal Animal is looking into, a more sophisticated controller might be needed, but by making use of other resources like blockram it can be somewhat simplified.Quote from: SiliconWizard on March 17, 2025, 08:38:15 pmThis it did not, I wrote my post to inform others that might not have understood your intent. (And unintended, maybe to be pedantic)

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 18, 2025, 12:47:20 pm
content: Quote from: Berni on March 18, 2025, 06:40:00 amIt is, but SRAM is still expensive. A few MB of async. SRAM will cost upwards of $10+ (compare that with SDR or DDR SDRAM), and access time will be slow. Fast SRAM is even more expensive, and often synchronous (making it only marginally "easier" to use than SDRAM). PSRAM is relatively cheap but only marginally easier to use than SDRAM IMO as well, if you need to develop the controller yourself.If cost is a concern, spending a bit more time designing for SDRAM (or PSRAM at worst) will be necessary. And if using a Xilinx FPGA, DDR controllers are provided as IPs for free both on the 6 and 7 series, so using DDR SDRAM makes more sense in this case. There are many dev boards that have a Spartan 6 and 32MB or 256MB of DDR3 for cheap, I had bought a bunch of them for about $15 each, prices have inflated now but still relatively reasonable. Routing your own board with DDR3 is a bit more involved than for SDR SDRAM, but not excessively so either.

author: Nominal Animal
author_rank: Super Contributor
timestamp: March 18, 2025, 01:08:45 pm
content: As my limiting factor is really the MCU access latency to the RAM, and not the framebuffer usage of it, you can probably see why I started looking into bank swapping. Some data would be duplicated, yes, and the triple buffering scheme can confuse anyone not familiar with it (it's common in games, especially older games that did not regenerate the whole display contents for every frame, only updated the differences), but it'd be quite a bit cheaper, and probably easier to implement, too.However, I do believe a couple of Milk-V Duo's (64M) are waiting for me at the post office. One 64-bit powerful core for MCUey stuff including high-speed USB 2.0 handling, and the other 64-bit almost as powerful core for my framebuffer shenanigans,with a 40-pin 0.5mm pitch FPC connector that is compatible with several of my displays–– no, I got that mixed with the Tang Nanos! ––, all for paltry 10€ apiece, shipped, makes for a powerful argument to try to do things this way.I do still intend to use the Tang Nano for FPGA shenanigans, most likely scaling and deinterlacing classic computer video chip outputs to panels or HDMI; but Milk-V Duo just fits my current framebuffer needs (for usb-connected displays for nontechnical humans stuff) best, I think. Time will tell.

author: pcprogrammer
author_rank: Super Contributor
timestamp: March 18, 2025, 02:35:29 pm
content: Quote from: Nominal Animal on March 18, 2025, 01:08:45 pmWhich Milk-V Duo is that? The ones I have (64MB versions) don't have a display interface.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 18, 2025, 03:25:04 pm
content: Yes, the Duo 64M only has a camera interface, not display out. So it must be at least the 256MB version, which sports a SG2002 instead of a CV1800B.I hope Nominal didn't expect to have video output via the MIPI interface on the 64MB version, otherwise he'll be in for a disappointment. (And the only option will be to use display modules with embedded GRAM and a SPI interface, I don't think you can even implement a proper "parallel" interface with it.)

author: pcprogrammer
author_rank: Super Contributor
timestamp: March 18, 2025, 07:20:46 pm
content: Quote from: SiliconWizard on March 18, 2025, 03:25:04 pmWell the SPI based interfaces with GRAM are what Nominal Animal said to be using, but the 40 pin 0.5mm connector he mentioned is on neither of the Milk-V duo modules I know of. That is why I asked.The SG2002, according to the block diagram, has support for video output. But in the tech specs they mention a Duo S based on a SG2000(probably a typo)and the video out connection is only via the GPIO header. In the tech specs they mention MIPI DSI 4 lanes. Maybe it is a pin thing, where the chip on the 64M and 256M boards is a to small version of it.Edit: Found that it is actually correct, the SG2000. It is a 512MB version of the chip. On Aliexpress the board without eMMC is about the same price as the 256MB version.https://www.aliexpress.com/item/1005006719645936.html

author: Nominal Animal
author_rank: Super Contributor
timestamp: March 19, 2025, 04:25:53 am
content: Quote from: pcprogrammer on March 18, 2025, 02:35:29 pmIgnore that, I got it confused with the Tang Nanos. (Whenever I do not verify my post after writing but before posting, I keep making these confusions, dammit. My excitement shows!)I'll use the GPIO pins, of which there arejustenough for my purposes.Quote from: SiliconWizard on March 18, 2025, 03:25:04 pmNope. The display modules I use a 8080-style bus to the GRAM, not synchronized to the display update (but do export the TE pin to indicate when the display refresh is complete). The second core will compute each output pixel color at update time by combining data from multiple logical planes, only one of which is RGB.The way I generate the GPIO pin states for that bus-to-GRAM uses yet more lookup tables. On Cortex-M7 I used theDR_TOGGLEregister to allow me to pick any pins in any order within the same bank, but the CV1008B only has a data output, no toggle. I'll need to investigate which solution (keeping a copy of the value in RAM, or just overwriting the entire bank) yields best results.

author: pcprogrammer
author_rank: Super Contributor
timestamp: March 19, 2025, 07:17:56 am
content: Quote from: Nominal Animal on March 19, 2025, 04:25:53 amAh that explains my confusion.Quote from: Nominal Animal on March 19, 2025, 04:25:53 amA while after making my previous post I realized that you mentioned the GRAM somewhere in this thread, but not the interface you use, which is the 8080 style bus instead of SPI, based on your last post. So my bad on assuming that it was SPI you are using.Do these display modules match the Tang Nano 9K connector? Because that one is intended towards RGB interface based panels. There is power provision for the backlight on it, but the current is set a bit low for the 7 inch panels I'm using.This is why I'm going to make a conversion board for my LCD panels that allow me to connect them to boards that don't have the backlight power too. I'm waiting for parts from Aliexpress to setup a prototype first.

author: Nominal Animal
author_rank: Super Contributor
timestamp: March 19, 2025, 04:52:17 pm
content: Tang Nano 9k 40-pin 0.5mm pitch LCD connector pinout hasPin 1 = LEDK, pin 2 = LEDAPins 4 and 31 = 3.3VPins 8..12 = Red3 .. Red7Pins 15..20 = Green2 .. Green7Pins 24..28 = Blue3 .. Blue7Pin 30 = ClockPin 32 = HSyncPin 33 = VSyncPin 34 = EnablePins 37-40 for touchscreenRest are GNDTo adjust the backlight peak current, you replace R25 with 0.25/I, where I is the current in amperes. The default is 13Ω, which sets the current to 19mA. This shares pins with HDMI, so you cannot use both at the same time.I do believe BuyDisplay currently offers four IPS panels that are compatible with Tang Nano 40pin 0.5mm pitch FPC connector:4.3" 480x272 (ER_TFT043A4-3)(15-20mA backlight),4.3" 800x480 (ER_TFT043A1-7)(35-40mA backlight),5" 800x480 (ER_TFT050-6)(45-60mA backlight), and7" 800x480 (ER-TFT070IPS-4)(140-180mA backlight). The boost LED driver (LP3320) on the Tang Nanos can handle the higher currents if you change the resistor.Tang Nano 9k also has a small 8-pin 0.5mm pitch connector for SPI LCD modules, with pin 1 to 3.3V via 5.1Ω resistor, pin 2 is GND, pin 3 is RESET, pin 4 is RS (aka C/D), pin 5 is DATA, pin 6 is CLOCK, pin 7 is 3.3V, and pin 8 is CS. I do believe0.96" 160x80 (ER-TFT0.96-4),1.14" 240x135 (ER-TFT1.14-2), and1.47" 320x172 (ER-TFT1.47A1-1)are compatible with this connector. I believe one can use the smaller connector at the same time as the other LCD connector or HDMI.

author: pcprogrammer
author_rank: Super Contributor
timestamp: March 19, 2025, 07:28:00 pm
content: That is the same as on the Tang Nano 20K, except for the smaller SPI based display connector. It does not have that one.But what I was wondering about is, if you can connect the 8080 interface display panels you use to the Tang Nano 9K 40 pin connector?I only have and buy the 50 pin based 7 inch displays because they came up cheaper. I bought the 7 inch 1024*600 you mentioned in the other thread for ~21 euro on Aliexpress to compare it with the 7 inch 1024*600 displays I already have that were a bit cheaper. (~14 euro)https://nl.aliexpress.com/item/1005008274773124.htmlhttps://nl.aliexpress.com/item/1005005292813240.htmlThe one from buydisplay seems to be a little bit better, but not by much.The 40 pin 7 inch one you linked to on buydisplay.com is interesting though, but I already have three 800*480 7 inch displays and 3 1024*600 7 inch displays, so I think that is enough for now.Edit: One remark on the Tang Nano 20K 40 pin connector, I found that it connects to the flat cable on both sides, so one can insert it the other way round. Pin one is clearly marked on the board though. Most of these FPC/FCC connectors are one sides.

author: Nominal Animal
author_rank: Super Contributor
timestamp: March 20, 2025, 04:41:31 am
content: Quote from: pcprogrammer on March 19, 2025, 07:28:00 pmWith suitable a 40-pin to 50-pin 0.5mm pitch FPC adapter, sure, because they also happen to support the RGB+Hsync+Vsync+Clock+DE interface.Although there are several with compatible pinouts, I'm specifically targeting2.8" 320×240 (ER-TFT028A2-4)and3.5" 480×320 (ER-TFT035IPS-6). There are a few pins (specifically, IMn) that you want to tie on the FPC adapter to either GND or VCC depending on the display, but yes, they are compatible with the Tang Nano 9k, with a mechanical adaptor board.Moreover, I do believe the Tang Nano 9k could drive them in the GRAM mode also, not just RGB+Hsync+Vsync+Clock+DE mode. You could even use an 8-bit parallel 8080 bus, repurposing some of the color bits, and make it work at the same time as the HDMI interface. For 16-bit color at 480×320 70Hz, you then need a ~ 22 MHz parallel bus clock. ILI4988 can do up to 33 MHz. 320×240 ILI4931 is specced to 15 MHz, but only 11 MHz is really needed; and all the ones I have can sustain at least 18 MHz without any issues at all. That is for 8-bit parallel bus, mind you; halve the frequency needed if you use a 15/16/18 bit parallel bus. The write strobe runs at twice that frequency, of course; you need to output a pulse per output word.As an aside, if you compare that pinout to e.g.7" 1024x600 (ER-TFT070A2-6)with also a 50-pin 0.5mm pitch FPC, you'll see that while they're not directly compatible, you can definitely do a simple adapter to the 40-pin one as used on the Tang Nanos. You'll want to tie some pins to VCC or GND depending on the exact display (including L/R and U/D mirroring pins), but no logic or translation is needed.If I recall correctly, you said you already had some such 40-pin to 50-pin FPC adapter boards designed? In my opinion, a design that also acts as a carrier for the display module and Tang Nano, with PCB extending beyond the display module with positions for studs and mounting holes to correctly place it with respect to the housing and display hole, would be very useful here. I've made cardboard stand-ins to determine where to put a slot for the FPC and where to put the connector. (You'll want a full flat ground plane without any components facing the display module, and use 3M double-sided foam tape strips (the 2-3mm thick kind, and just 4-6mm wide "strips", not a full plane) to adhesive the display to the carrier PCB.)Quote from: pcprogrammer on March 19, 2025, 07:28:00 pmWhile the pinout is common, not all display modules FPC cables expose the pins on the same side, I believe. I got dual-sided 40-pin 0.5mm pitch connectors for that exact reason.

author: pcprogrammer
author_rank: Super Contributor
timestamp: March 20, 2025, 07:03:30 am
content: Quote from: Nominal Animal on March 20, 2025, 04:41:31 amOk, so you still need an adapter board to connect the displays you are targeting to the 9K. That is what I thought.Quote from: Nominal Animal on March 20, 2025, 04:41:31 amWith the FPGA it is simple enough to make up what ever interface you need. The extra external hardware takes a bit of fiddling.Quote from: Nominal Animal on March 20, 2025, 04:41:31 amNo logic, but they do need more voltages to drive the panel, so a boost converter has to be added to make these.Quote from: Nominal Animal on March 20, 2025, 04:41:31 amI made a prototype for it. I still have to design an actual board for it. Ordered parts to do some testing for a better backlight drive and control. Have not thought about the mechanical aspects of the board yet, so appreciate your input.Seehttps://www.eevblog.com/forum/projects/please-recommend-a-vga-to-parallel-lcd-board-or-ic/msg5746485/#msg5746485for info on my proto board.Quote from: Nominal Animal on March 20, 2025, 04:41:31 amThat I have not encountered yet.

author: Nominal Animal
author_rank: Super Contributor
timestamp: March 20, 2025, 08:55:06 am
content: Quote from: pcprogrammer on March 20, 2025, 07:03:30 amVCOM=3.0V..3.5V, DVDD=3.0V..3.6V, AVDD=9.4V..9.8V, VGH=17V..19V, VGL=-6.6V..-5.4V, so you're referring to the 9.6VDC AVDD, 18VDC VGH, and -6VDC VGL rails. Yes, the larger panels need these because the controller chip on the FPC cannot do these internally, unlike for the smaller TFTs. I forgot about that because I don't normally use these larger ones. As I understand it, these rails don't draw much current at all, and is generated using charge pumps for the smaller TFTs.I'm a total newbie when it comes to implementing DC-DC converters; I follow datasheets and what TI Webench suggests, followed by additional simulation if possible. I've briefly glanced at the 18 or so dedicated ICs for this Mouser has in stock. Because mine are basically always powered from USB or from 5VDC supply, I'd need a boost to 9.6V, 18V, and -6V, from a +5V single supply;TI TPS65145seems an obvious candidate. Any other suggestions you could share on this front?Quote from: Nominal Animal on March 20, 2025, 04:41:31 amYeah; the smaller modules have the LEDs in parallel, so the forward voltage is in the 3.0V - 3.3V range, with currents in the 80mA – 120mA range. Since I absolutely detest any kind of flicker and backlight imbalance, I've looked a lot mixing current-controlled and very high frequency (ultrasonic, 30 kHz+) PWM. With the LEDs in series in the 9V-20V range, more interesting high-frequency (1 MHz+) boost topologies come into play. Even though it affects the color balance somewhat at lower currents, I must say I like the current control most.Quote from: pcprogrammer on March 20, 2025, 07:03:30 amIt's more common in the fewer-pin connector variety, where some FPCs are intended to be soldered directly to a PCB, whereas connector-type often has the pins on the "upper" side relative to the PCB in the intended configuration.I do need to resort to cardboard-aided-design and strips of paper with pin 1 marked to get the placement right; and remember how "deep" into the connector the FPC/FFC seats in. Papercraft for the win! Even thoughthissuggested untested adapter I created for some thread here, and it's as simple as an adapter can be, I'm 100% sure the FFC positioning is far from optimal. (Ten points if you can tell why one is at 90° angle to the other.) I even had to draw the cabling idea on the silkscreen, just to remember it myself how I suggested it be used. EasyEDA is an excellent tool for this kind of suggestions –– which I always put in Public Domain ––, as anyone can examine the schematic and the PCB files directly in their browser with just one click.

author: pcprogrammer
author_rank: Super Contributor
timestamp: March 20, 2025, 10:11:02 am
content: QuoteI'm no expert myself, but I'm going to do it with the TPS61040. I "stole" this design from the FNIRSI-1013D, where a plus and minus 15V is created with the boost converter setup, and zenerdiodes are used to make the other voltages.https://github.com/pecostm32/FNIRSI-1013D-1014D-Hack/blob/main/Schematics/1013D/Scope_Power_Supply.pngOn my prototype I used a module with a XL6007 boost converter that gives me the +/-15V. The other voltages are made with the zenerdiodes and works very well.QuoteI'm not to sensitive to flicker, but the low frequency noise is what bothers me. The FNIRSI-1013D uses ~800Hz PWM to dim the display, and that is very audible, so when I use that scope the brightness is on full.The PT4103 datasheet gives other options that indeed control the current without turning the boost converter on and off. That is also something I'm going to test first before making a board.QuoteI work rather similar. I guess that your reason for the 90 degree angle is that it is easier to get the cable in. To have it facing in the opposite direction so that the cable enters at one end and goes out at the other end would have needed you to cross all the traces on the board to get it routed. Having them inline with both cables in the same direction would eliminate this crossing, but would make it harder to insert the second cable.Another way to cope with this is to make use of the different type of cables or connectors. For the cables there are A-A and A-B types or Forward and Reverse direction. For the connectors there is top or bottom also referred to as forward or reverse, but also both sides. In searching for these it is not always clear what type it is, at least on Aliexpress.https://www.aliexpress.com/item/1005006274520167.htmlIt does make designing complicated though.Edit: I looked at your design again and noticed that the cables are going in on at one and and the other on the other end, so my guess is wrong. Still think it has to do something with the orientation of the pinning and the simplified routing.

author: Nominal Animal
author_rank: Super Contributor
timestamp: March 20, 2025, 11:21:15 am
content: Quote from: pcprogrammer on March 20, 2025, 10:11:02 amThe pin order is reversed, but both cables need pin 1 to be on the same side for the standard display orientation to work; and this board will be sandwiched between the display and the original board, so the stacking order and directions of the two cables is important. IIRC, I made a cardboard model with paper strips acting like FFCs, and then worked out a way to make standard length FFCs work with the FPC on this particular display.The one trick is to have just the right amount of extra length when going through slots or bends, so the FFC fits nicely without binding or having annoying floppy loops of it where you don't need it. Papercraft CAD makes that easy.

author: RoGeorge
author_rank: Super Contributor
timestamp: March 27, 2025, 10:58:51 am
content: What is GRAM?Asking out of curiosity. Never met the term before. DuckDuckGo doesn't know it either. By the context it seems to be video RAM, though, I didn't read the entire thread. Is GRAM the same as VRAM?

author: Nominal Animal
author_rank: Super Contributor
timestamp: March 27, 2025, 11:23:30 am
content: Quote from: RoGeorge on March 27, 2025, 10:58:51 amYes. It is the term the display controllers likeILI9341use for the (typically) 18-bit graphics buffer they contain. It does not really act like "normal" RAM, in the sense that if you use narrower writes (say, 15-bit RGB555 or 16-bit RGB565) the data is expanded to 18-bit on write by duplicating the high bits. Also, reads from this memory are exceedingly slow compared to writes. For ILI9341 (320×240, exactly 240×320×18 bits), write strobe can be repeated every 66ns (up to 15 MHz), but read cycles are limited to 450ns (2.2 MHz or less). Bulk writes are not limited to a sequential block of GRAM either; you can set up a 2D rectangular window and update direction within that window your writes will modify. (Unfortunately, no blitting or skipping of pixels, so no transparency support.)

author: cunningfellow
author_rank: Regular Contributor
timestamp: March 27, 2025, 10:16:46 pm
content: I don't think it is the same as VRAM (dual port RAM with the 2nd port being serial access only) as VRAM was known in the 80s and 90s.These days the young kids call any RAM used for video VRAM.Which is how I think the term GRAM is being used. Graphics RAM. I don't think there is anything fancy about it.

author: nctnico
author_rank: Super Contributor
timestamp: March 27, 2025, 10:50:42 pm
content: Quote from: Nominal Animal on March 20, 2025, 08:55:06 amVery nice if you come across such a panel. NOT! I used an LT1947 in one of my designs. This is a single chip solution to create all the necessary voltages. IIRC the datasheet / documentation is quite straighforward. For VCOM I used an opamp as a buffer for a resistor divider. Most of the rails don't draw much current indeed.

author: Nominal Animal
author_rank: Super Contributor
timestamp: March 28, 2025, 11:46:38 am
content: Quote from: cunningfellow on March 27, 2025, 10:16:46 pmNot by me. I use the term to describe its behaviour: fast writes expanding data to 18-bit RGB regardless of written data width, extremely slow reads.Note that it is also kind-of dual-ported: the controller is constantly refreshing the TFT, and thus reading from this memory. The state of the refresh does not affect the write timings at all.

author: RoGeorge
author_rank: Super Contributor
timestamp: March 28, 2025, 02:17:14 pm
content: To me, GRAM looks like a (probably) wrong translation from another language, or maybe some workplace/office specific slang (unless there is a motivation/explanation for why using GRAM instead of VRAM). Most probably specific to that datasheet only, or to that manufacturer only.Also in the "IEEE 100 - the authoritative dictionary of IEEE standards", there is no entry for GRAM, only for VRAM:QuoteNo matter why the LCD datasheet is using GRAM, it doesn't seem to be some new type of RAM I might need to know/study/learn about (that was one of the reasons I was asking, apart from the casual curiosity reaction of "WTF is GRAM?!").Thanks for clarifications, and sorry for the offtopic question.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 28, 2025, 02:33:05 pm
content: GRAM just stands for graphics RAM for all I know, if that matters. This is just how the internal video RAM buffer of a display controller is usually called, for display controllers that handle display refreshing on their own, as opposed to the more basic controllers which take RGB+Sync signals and need to be manually fed (this is still a controller, but obviously much simpler).This RAM is in effect dual-port, although internally the controller may use single-port RAM and may interleave access to it. The pixel data you send it may be using various programmable formats (common usual suspects for TFT panels are RGB565 and RGB666 or RGB888) and the controller transforms the pixel format on the fly to the full pixel data required by the panel itself, often 18- to 24-bit (so 6 to 8 bpp). For monochrome OLED panels, the formats are usually either 1 bpp or 4 bpp. I've never run into a monochrome OLED panel that supported more than 16 grayscale, but such a beast may exist. The color ones vary.

author: Nominal Animal
author_rank: Super Contributor
timestamp: March 28, 2025, 05:08:57 pm
content: I'm happy to use any name for the buffer memory on these controllers, I just want to avoid any confusion as to how it is used: that it is external to the MCU/FPGA, is internal to the controller IC on the display FPC, has very asymmetric write/read timings, and is constantly read by the controller to refresh the display without affecting the write timings or access. It's what the Ilitek ILI9341 (320×240) and ILI9488 (480×320) datasheets use, so I didn't even bother to check any dictionary for the correct term. Should I use VRAM for this in the future, or just "display module framebuffer" or "display module graphics RAM" or something else?The display modules I use do export the TE pin which informs the external MCU/FPGA of a completed refresh allowing the external one to start writing the contents of a new frame without tearing, plus have a register which can be read –– at 150ns cycles or max. 6.7 MHz –– to obtain the scan line currently being updated.Just to clarify, my favourite display is2.8" 320×240 IPS, ER-TFT028A2-450-pin 0.5mm pitch FPC, ILI9341 controller, max. 15 MHz writes (66ns), physical size 70mm×50mm, active area 57.6mm×43.2mm, 0.18mm×0.18mm square pixels, optional capacitive touch panel uses separate 6-pin FPC, and backlight is four white LEDs in parallel with common cathode connection having 3.2V–3.4V forward voltage at 70mA–80mA currentbut2.4" 320×240 IPS, ER-TFT024IPS-350-pin 0.5mm pitch FPC, ST7789 controller, max. 15 MHz writes (66ns), physical size 60mm×43mm, active area 48.96mm×36.72mm, 0.153mm×0.153mm square pixels, backlight is four white LEDs in parallel with common anode having 3.2V–3.4V forward voltage at 70mA–80mA current3.5" 480×320 IPS, ER-TFT035IPS-650-pin 0.5mm pitch FPC, ILI9488 controller, max. 33 MHz writes (30ns), physical size 83mm×55mm (85mm×57mm with optional capacitive touch panel in the same FPC), active area 73.44mm×48.96mm, 0.153mm×0.153mm square pixels, and backlight is six white LEDs in parallel with common anode for all, two common cathodes for each group of three LEDs, having 3.0V–3.2V forward voltage at 110mA–120mA currentall have a compatible 50-pin FPC and very similar controllers too. Then there are3.2" 320×240 IPS, ER-TFT032IPS-3.240-pin 0.5mm pitch FPC, ST7789V2 controller, max. 15 MHz writes (66ns), physical size 78mm×55mm, active area 64.8mm×48.6mm, 0.2025mm×0.2025mm square pixels, optional capacitive touch, backlight is four white LEDs in parallel, 3.2V–3.4V forward voltage at 110mA–120mA current3.92" 320×320 IPS, ER-TFT3.92-140-pin 0.5mm pitch FPC, ST7796S controller, max. 15 MHz writes (66ns), physical size 84mm×84mm, active area 70mm×71mm, 0.21mm×0.22mm pixels (<5% from square), optional capacitive touch, backlight is two parallel chains of five white LEDs in series, forward voltage 15V–16V at 30mA–40mA current; no TE pin4.3" 800×480 IPS, ER-TFT043-940-pin 0.5mm pitch FPC, NT35510 controller, physical size 104mm×61mm, active area 93.6mm×56.16mm, 0.117mm×0.117mm square pixels, and backlight is two parallel chains of five series white LEDs with 15V–16V forward voltage at 30mA–40mA current; no TE pinhave 16-bit parallel 8080-style buses and can be used in the same fashion, although the pinouts vary. All these have a controller with built-in memory for the contents, and can be used like I do (with video updates synchronized with the display, but only changes need to be sent). While the last two do not have an output pin to indicate completion of display refresh, they do support command 0x45 that returns the scan line currently being refreshed, so one can do active polling to avoid tearing.The annoying thing with these small panels is driving the backlight without flicker. With series white LEDs there are efficient boost converters working in the MHz range. With parallel LEDs, although I have 5V at sufficient currents available, losses are converted to heat, and although 0.2W or so of heat isn't that much, it does need to be get rid of, and the enclosures I use are small (routers, switches, NAS boxes, et cetera). An MCU/FPGA-programmable current efficient buck controller from 5V (to around 3V) with resistor-settable maximum current (80mA–120mA) operating at 300kHz - 2MHz would benice. I've already found out that all the displays I have have very well balanced backlight LEDs, so mythread from 2022 on backlightingwas overly cautious: I've not needed to balance backlight LEDs ever.

author: bson
author_rank: Unknown
timestamp: March 28, 2025, 05:47:52 pm
content: Quote from: Berni on March 18, 2025, 06:40:00 amTotally agree. What sensible person is even thinking of using SDRAM (and cache!) for a few MB? Drop in a 4MB 10ns SRAM and - done! It might cost $20, but for a one-off project, who cares. This is the kind of SRAM that would be used for cache anyway...